[ovs-dev] [PATCH 2/3] ovn-northd: Improve efficiency of stateful checking for ACLs on port groups.
Mark Michelson
mmichels at redhat.com
Tue Aug 7 20:45:41 UTC 2018
Nice find, Han!
Acked-by: Mark Michelson <mmichels at redhat.com>
On 08/06/2018 10:44 PM, Han Zhou wrote:
> Currently in has_stateful_acl(), to check if a datapath has stateful ACLs,
> it needs to iterate all port groups and check if the current datapath is
> related to each port group, and then iterate the ACLs on the port group. This
> is inefficient if there are a lot of port groups. A typical scenario is in
> OpenStack each tenant will have a default security group which will be mapped
> as a port group, and the default security group is supposed to contain ports
> of the tenant only, so most likely only the logical switches belonging to the
> tenant should be related to the port group, but we are checking all the port
> groups belonging to all tenants for each datapath.
>
> To improve this, a reverse direction of hmap is built from logical switch to
> port group, so that the iteration is avoided. The time complexity of this
> function improves from O(P * A) to O(PL * A), P = total number of port groups
> in NB, PL = number of port groups related to the logical switch, A = number
> of ACLs.
>
> Signed-off-by: Han Zhou <hzhou8 at ebay.com>
> ---
> ovn/northd/ovn-northd.c | 60 +++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 46 insertions(+), 14 deletions(-)
>
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index d2a777f..ba86bf5 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -439,6 +439,9 @@ struct ovn_datapath {
> * the "redirect-chassis". */
> struct ovn_port *l3redirect_port;
> struct ovn_port *localnet_port;
> +
> + /* Port groups related to the datapath, used only when nbs is NOT NULL. */
> + struct hmap nb_pgs;
> };
>
> struct macam_node {
> @@ -467,11 +470,14 @@ ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
> od->nbs = nbs;
> od->nbr = nbr;
> hmap_init(&od->port_tnlids);
> + hmap_init(&od->nb_pgs);
> od->port_key_hint = 0;
> hmap_insert(datapaths, &od->key_node, uuid_hash(&od->key));
> return od;
> }
>
> +static void ovn_ls_port_group_destroy(struct hmap *nb_pgs);
> +
> static void
> ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
> {
> @@ -483,6 +489,7 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
> destroy_tnlids(&od->port_tnlids);
> bitmap_free(od->ipam_info.allocated_ipv4s);
> free(od->router_ports);
> + ovn_ls_port_group_destroy(&od->nb_pgs);
> free(od);
> }
> }
> @@ -3053,8 +3060,34 @@ ovn_port_group_ls_find(struct ovn_port_group *pg, const struct uuid *ls_uuid)
> return NULL;
> }
>
> +struct ovn_ls_port_group {
> + struct hmap_node key_node; /* Index on 'key'. */
> + struct uuid key; /* nb_pg->header_.uuid. */
> + const struct nbrec_port_group *nb_pg;
> +};
> +
> +static void
> +ovn_ls_port_group_add(struct hmap *nb_pgs,
> + const struct nbrec_port_group *nb_pg)
> +{
> + struct ovn_ls_port_group *ls_pg = xzalloc(sizeof *ls_pg);
> + ls_pg->key = nb_pg->header_.uuid;
> + ls_pg->nb_pg = nb_pg;
> + hmap_insert(nb_pgs, &ls_pg->key_node, uuid_hash(&ls_pg->key));
> +}
> +
> +static void
> +ovn_ls_port_group_destroy(struct hmap *nb_pgs)
> +{
> + struct ovn_ls_port_group *ls_pg;
> + HMAP_FOR_EACH_POP (ls_pg, key_node, nb_pgs) {
> + free(ls_pg);
> + }
> + hmap_destroy(nb_pgs);
> +}
> +
> static bool
> -has_stateful_acl(struct ovn_datapath *od, struct hmap *port_groups)
> +has_stateful_acl(struct ovn_datapath *od)
> {
> for (size_t i = 0; i < od->nbs->n_acls; i++) {
> struct nbrec_acl *acl = od->nbs->acls[i];
> @@ -3063,25 +3096,23 @@ has_stateful_acl(struct ovn_datapath *od, struct hmap *port_groups)
> }
> }
>
> - struct ovn_port_group *pg;
> - HMAP_FOR_EACH (pg, key_node, port_groups) {
> - if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
> - for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
> - struct nbrec_acl *acl = pg->nb_pg->acls[i];
> - if (!strcmp(acl->action, "allow-related")) {
> - return true;
> - }
> + struct ovn_ls_port_group *ls_pg;
> + HMAP_FOR_EACH (ls_pg, key_node, &od->nb_pgs) {
> + for (size_t i = 0; i < ls_pg->nb_pg->n_acls; i++) {
> + struct nbrec_acl *acl = ls_pg->nb_pg->acls[i];
> + if (!strcmp(acl->action, "allow-related")) {
> + return true;
> }
> }
> }
> +
> return false;
> }
>
> static void
> -build_pre_acls(struct ovn_datapath *od, struct hmap *lflows,
> - struct hmap *port_groups)
> +build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
> {
> - bool has_stateful = has_stateful_acl(od, port_groups);
> + bool has_stateful = has_stateful_acl(od);
>
> /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
> * allowed by default. */
> @@ -3606,6 +3637,7 @@ build_port_group_lswitches(struct northd_context *ctx, struct hmap *pgs,
> ovn_port_group_ls_find(pg, &op->od->nbs->header_.uuid);
> if (!pg_ls) {
> ovn_port_group_ls_add(pg, op->od->nbs);
> + ovn_ls_port_group_add(&op->od->nb_pgs, nb_pg);
> }
> }
> }
> @@ -3615,7 +3647,7 @@ static void
> build_acls(struct ovn_datapath *od, struct hmap *lflows,
> struct hmap *port_groups)
> {
> - bool has_stateful = has_stateful_acl(od, port_groups);
> + bool has_stateful = has_stateful_acl(od);
>
> /* Ingress and Egress ACL Table (Priority 0): Packets are allowed by
> * default. A related rule at priority 1 is added below if there
> @@ -3968,7 +4000,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
> continue;
> }
>
> - build_pre_acls(od, lflows, port_groups);
> + build_pre_acls(od, lflows);
> build_pre_lb(od, lflows);
> build_pre_stateful(od, lflows);
> build_acls(od, lflows, port_groups);
>
More information about the dev
mailing list