Hi Han,
Thanks for the northd refactor, that's great work!
On 3/21/23 07:02, Han Zhou wrote:
> Similar to the previous commit that splits switch ports and router
> ports, this patch splits the two types of datapaths in different hmap
> tables. This is also mainly to help for future incremental processing
> implementation. As a byproduct, the recompute performance is improved
> slightly. (Together with the previous commit that splits ports, scale
> test shows around ~4% improvment)
>
> Note: This patch didn't change the ovn_datapath structure, which is
> used by both switches and routers. It may be a followup improvement in
> the future if necessary, e.g. to reduce memory footprint.
>
I think, for better readability, it actually makes sense to do this part
as soon as possible too. That would allow us to avoid (clumsy) checks like:
static void
destroy_router_external_ips(struct ovn_datapath *od)
{
if (!od->nbr) {
return;
}
sset_destroy(&od->external_ips);
}
If you don't plan to work on it, please let me know and I can try to
prepare a series that does that (and maybe split LSP/LRP ports too).
In the meantime I posted a minor follow up patch; please take a look
when you have time:
https://patchwork.ozlabs.org/project/ovn/patch/[email protected]/
Regards,
Dumitru
> Signed-off-by: Han Zhou <[email protected]>
> ---
> lib/lb.c | 15 +-
> lib/lb.h | 6 +-
> northd/en-lflow.c | 3 +-
> northd/en-sync-sb.c | 2 +-
> northd/mac-binding-aging.c | 2 +-
> northd/northd.c | 946 ++++++++++++++++++++-----------------
> northd/northd.h | 6 +-
> 7 files changed, 543 insertions(+), 437 deletions(-)
>
> diff --git a/lib/lb.c b/lib/lb.c
> index 66c8152750a1..37e05c31f918 100644
> --- a/lib/lb.c
> +++ b/lib/lb.c
> @@ -521,7 +521,7 @@ ovn_lb_get_health_check(const struct nbrec_load_balancer
> *nbrec_lb,
>
> struct ovn_northd_lb *
> ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb,
> - size_t n_datapaths)
> + size_t n_ls_datapaths, size_t n_lr_datapaths)
> {
> bool template = smap_get_bool(&nbrec_lb->options, "template", false);
> bool is_udp = nullable_string_is_equal(nbrec_lb->protocol, "udp");
> @@ -560,8 +560,8 @@ ovn_northd_lb_create(const struct nbrec_load_balancer
> *nbrec_lb,
> }
> lb->affinity_timeout = affinity_timeout;
>
> - lb->nb_ls_map = bitmap_allocate(n_datapaths);
> - lb->nb_lr_map = bitmap_allocate(n_datapaths);
> + lb->nb_ls_map = bitmap_allocate(n_ls_datapaths);
> + lb->nb_lr_map = bitmap_allocate(n_lr_datapaths);
>
> sset_init(&lb->ips_v4);
> sset_init(&lb->ips_v6);
> @@ -687,12 +687,13 @@ ovn_northd_lb_destroy(struct ovn_northd_lb *lb)
>
> /* Constructs a new 'struct ovn_lb_group' object from the Nb LB Group record
> * and a hash map of all existing 'struct ovn_northd_lb' objects. Space will
> - * be allocated for 'max_datapaths' logical switches and the same amount of
> + * be allocated for 'max_ls_datapaths' logical switches and
> 'max_lr_datapaths'
> * logical routers to which this LB Group is applied. Can be filled later
> * with ovn_lb_group_add_ls() and ovn_lb_group_add_lr() respectively. */
> struct ovn_lb_group *
> ovn_lb_group_create(const struct nbrec_load_balancer_group *nbrec_lb_group,
> - const struct hmap *lbs, size_t max_datapaths)
> + const struct hmap *lbs, size_t max_ls_datapaths,
> + size_t max_lr_datapaths)
> {
> struct ovn_lb_group *lb_group;
>
> @@ -700,8 +701,8 @@ ovn_lb_group_create(const struct
> nbrec_load_balancer_group *nbrec_lb_group,
> lb_group->uuid = nbrec_lb_group->header_.uuid;
> lb_group->n_lbs = nbrec_lb_group->n_load_balancer;
> lb_group->lbs = xmalloc(lb_group->n_lbs * sizeof *lb_group->lbs);
> - lb_group->ls = xmalloc(max_datapaths * sizeof *lb_group->ls);
> - lb_group->lr = xmalloc(max_datapaths * sizeof *lb_group->lr);
> + lb_group->ls = xmalloc(max_ls_datapaths * sizeof *lb_group->ls);
> + lb_group->lr = xmalloc(max_lr_datapaths * sizeof *lb_group->lr);
> lb_group->lb_ips = ovn_lb_ip_set_create();
>
> for (size_t i = 0; i < nbrec_lb_group->n_load_balancer; i++) {
> diff --git a/lib/lb.h b/lib/lb.h
> index ddd41703da44..ba48a0dac4f0 100644
> --- a/lib/lb.h
> +++ b/lib/lb.h
> @@ -130,7 +130,8 @@ struct ovn_northd_lb_backend {
> };
>
> struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer
> *,
> - size_t n_datapaths);
> + size_t n_ls_datapaths,
> + size_t n_lr_datapaths);
> struct ovn_northd_lb *ovn_northd_lb_find(const struct hmap *,
> const struct uuid *);
> const struct smap *ovn_northd_lb_get_vips(const struct ovn_northd_lb *);
> @@ -157,7 +158,8 @@ struct ovn_lb_group {
> struct ovn_lb_group *ovn_lb_group_create(
> const struct nbrec_load_balancer_group *,
> const struct hmap *lbs,
> - size_t max_datapaths);
> + size_t max_ls_datapaths,
> + size_t max_lr_datapaths);
> void ovn_lb_group_destroy(struct ovn_lb_group *lb_group);
> struct ovn_lb_group *ovn_lb_group_find(const struct hmap *lb_groups,
> const struct uuid *);
> diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> index 9e7a2145e520..995c7cc10e33 100644
> --- a/northd/en-lflow.c
> +++ b/northd/en-lflow.c
> @@ -54,7 +54,8 @@ void en_lflow_run(struct engine_node *node, void *data
> OVS_UNUSED)
> engine_get_input("SB_multicast_group", node),
> "sbrec_mcast_group_by_name");
>
> - lflow_input.datapaths = &northd_data->datapaths;
> + lflow_input.ls_datapaths = &northd_data->ls_datapaths;
> + lflow_input.lr_datapaths = &northd_data->lr_datapaths;
> lflow_input.ls_ports = &northd_data->ls_ports;
> lflow_input.lr_ports = &northd_data->lr_ports;
> lflow_input.port_groups = &northd_data->port_groups;
> diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c
> index 6e33901a8a29..d4f4e60eabd6 100644
> --- a/northd/en-sync-sb.c
> +++ b/northd/en-sync-sb.c
> @@ -91,7 +91,7 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void
> *data OVS_UNUSED)
>
> sync_addr_sets(nb_address_set_table, nb_port_group_table,
> sb_address_set_table, eng_ctx->ovnsb_idl_txn,
> - &northd_data->datapaths);
> + &northd_data->lr_datapaths);
>
> engine_set_node_state(node, EN_UPDATED);
> }
> diff --git a/northd/mac-binding-aging.c b/northd/mac-binding-aging.c
> index 1c30e979e1ac..3bdf1c2ea8d9 100644
> --- a/northd/mac-binding-aging.c
> +++ b/northd/mac-binding-aging.c
> @@ -109,7 +109,7 @@ en_mac_binding_aging_run(struct engine_node *node, void
> *data OVS_UNUSED)
> "sbrec_mac_binding_by_datapath");
>
> struct ovn_datapath *od;
> - HMAP_FOR_EACH (od, key_node, &northd_data->datapaths) {
> + HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths) {
> if (od->sb && od->nbr) {
> mac_binding_aging_run_for_datapath(od->sb, od->nbr,
> sbrec_mac_binding_by_datapath,
> diff --git a/northd/northd.c b/northd/northd.c
> index 10b16e685adf..baee1786469a 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -947,16 +947,24 @@ ovn_datapath_is_stale(const struct ovn_datapath *od)
> }
>
> static struct ovn_datapath *
> -ovn_datapath_from_sbrec(const struct hmap *datapaths,
> +ovn_datapath_from_sbrec(const struct hmap *ls_datapaths,
> + const struct hmap *lr_datapaths,
> const struct sbrec_datapath_binding *sb)
> {
> struct uuid key;
> + const struct hmap *dps;
>
> - if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) &&
> - !smap_get_uuid(&sb->external_ids, "logical-router", &key)) {
> + if (smap_get_uuid(&sb->external_ids, "logical-switch", &key)) {
> + dps = ls_datapaths;
> + } else if (smap_get_uuid(&sb->external_ids, "logical-router", &key)) {
> + dps = lr_datapaths;
> + } else {
> + return NULL;
> + }
> + if (!dps) {
> return NULL;
> }
> - struct ovn_datapath *od = ovn_datapath_find(datapaths, &key);
> + struct ovn_datapath *od = ovn_datapath_find(dps, &key);
> if (od && (od->sb == sb)) {
> return od;
> }
> @@ -1375,9 +1383,15 @@ ovn_datapath_assign_requested_tnl_id(struct
> northd_input *input_data,
> }
> }
>
> -/* Array of all datapaths, with 'od->index' being their index in the array.
> */
> -static struct ovn_datapath **datapaths_array = NULL;
> -static size_t n_datapaths = 0; /* Size of the 'datapaths_array'. */
> +/* Array of ls datapaths, with 'od->index' being their index in the array. */
> +static struct ovn_datapath **ls_datapaths_array = NULL;
> +/* Size of the 'ls_datapaths_array'. */
> +static size_t n_ls_datapaths = 0;
> +
> +/* Array of lr datapaths, with 'od->index' being their index in the array. */
> +static struct ovn_datapath **lr_datapaths_array = NULL;
> +/* Size of the 'lr_datapaths_array'. */
> +static size_t n_lr_datapaths = 0;
>
> /* Updates the southbound Datapath_Binding table so that it contains the
> * logical switches and routers specified by the northbound database.
> @@ -1387,11 +1401,13 @@ static size_t n_datapaths = 0; /* Size of the
> 'datapaths_array'. */
> static void
> build_datapaths(struct northd_input *input_data,
> struct ovsdb_idl_txn *ovnsb_txn,
> - struct hmap *datapaths,
> + struct hmap *ls_datapaths,
> + struct hmap *lr_datapaths,
> struct ovs_list *lr_list)
> {
> struct ovs_list sb_only, nb_only, both;
>
> + struct hmap *datapaths = ls_datapaths;
> join_datapaths(input_data, ovnsb_txn,
> datapaths, &sb_only, &nb_only, &both, lr_list);
>
> @@ -1444,17 +1460,37 @@ build_datapaths(struct northd_input *input_data,
> ovn_datapath_destroy(datapaths, od);
> }
>
> + /* Move lr datapaths to lr_datapaths, and ls datapaths will
> + * remain in datapaths/ls_datapaths. */
> + HMAP_FOR_EACH_SAFE (od, key_node, datapaths) {
> + if (!od->nbr) {
> + ovs_assert(od->nbs);
> + continue;
> + }
> + hmap_remove(datapaths, &od->key_node);
> + hmap_insert(lr_datapaths, &od->key_node, od->key_node.hash);
> + }
> +
> /* Assign unique sequential indexes to all datapaths. These are not
> * visible outside of the northd loop, so, unlike the tunnel keys, it
> * doesn't matter if they are different on every iteration. */
> size_t index = 0;
>
> - n_datapaths = hmap_count(datapaths);
> - datapaths_array = xrealloc(datapaths_array,
> - n_datapaths * sizeof *datapaths_array);
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + n_ls_datapaths = hmap_count(ls_datapaths);
> + ls_datapaths_array = xrealloc(ls_datapaths_array,
> + n_ls_datapaths * sizeof
> *ls_datapaths_array);
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + od->index = index;
> + ls_datapaths_array[index++] = od;
> + }
> +
> + index = 0;
> + n_lr_datapaths = hmap_count(lr_datapaths);
> + lr_datapaths_array = xrealloc(lr_datapaths_array,
> + n_lr_datapaths * sizeof
> *lr_datapaths_array);
> + HMAP_FOR_EACH (od, key_node, lr_datapaths) {
> od->index = index;
> - datapaths_array[index++] = od;
> + lr_datapaths_array[index++] = od;
> }
> }
>
> @@ -2243,7 +2279,7 @@ update_dynamic_addresses(struct dynamic_address_update
> *update)
> }
>
> static void
> -build_ipam(struct hmap *datapaths, struct hmap *ls_ports)
> +build_ipam(struct hmap *ls_datapaths, struct hmap *ls_ports)
> {
> /* IPAM generally stands for IP address management. In non-virtualized
> * world, MAC addresses come with the hardware. But, with virtualized
> @@ -2257,10 +2293,8 @@ build_ipam(struct hmap *datapaths, struct hmap
> *ls_ports)
> struct ovs_list updates;
>
> ovs_list_init(&updates);
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> - if (!od->nbs) {
> - continue;
> - }
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + ovs_assert(od->nbs);
>
> for (size_t i = 0; i < od->nbs->n_ports; i++) {
> const struct nbrec_logical_switch_port *nbsp = od->nbs->ports[i];
> @@ -2440,8 +2474,8 @@ tag_alloc_create_new_tag(struct hmap *tag_alloc_table,
>
> static void
> join_logical_ports(struct northd_input *input_data,
> - struct hmap *datapaths, struct hmap *ports,
> - struct hmap *chassis_qdisc_queues,
> + struct hmap *ls_datapaths, struct hmap *lr_datapaths,
> + struct hmap *ports, struct hmap *chassis_qdisc_queues,
> struct hmap *tag_alloc_table, struct ovs_list *sb_only,
> struct ovs_list *nb_only, struct ovs_list *both)
> {
> @@ -2458,225 +2492,226 @@ join_logical_ports(struct northd_input *input_data,
> }
>
> struct ovn_datapath *od;
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> - if (od->nbs) {
> - size_t n_allocated_localnet_ports = 0;
> - for (size_t i = 0; i < od->nbs->n_ports; i++) {
> - const struct nbrec_logical_switch_port *nbsp
> - = od->nbs->ports[i];
> - struct ovn_port *op = ovn_port_find_bound(ports, nbsp->name);
> - if (op && (op->od || op->nbsp || op->nbrp)) {
> - static struct vlog_rate_limit rl
> - = VLOG_RATE_LIMIT_INIT(5, 1);
> - VLOG_WARN_RL(&rl, "duplicate logical port %s",
> nbsp->name);
> - continue;
> - } else if (op && (!op->sb || op->sb->datapath == od->sb)) {
> - /*
> - * Handle cases where lport type was explicitly changed
> - * in the NBDB, in such cases:
> - * 1. remove the current sbrec of the affected lport from
> - * the port_binding table.
> - *
> - * 2. create a new sbrec with the same logical_port as
> the
> - * deleted lport and add it to the nb_only list which
> - * will make the northd handle this lport as a new
> - * created one and recompute everything that is needed
> - * for this lport.
> - *
> - * This change will affect container/virtual lport type
> - * changes only for now, this change is needed in
> - * contaier/virtual lport cases to avoid port type
> - * conflicts in the ovn-controller when the user clears
> - * the parent_port field in the container lport or
> updated
> - * the lport type.
> - *
> - */
> - bool update_sbrec = false;
> - if (op->sb && lsp_is_type_changed(op->sb, nbsp,
> - &update_sbrec)
> - && update_sbrec) {
> - ovs_list_remove(&op->list);
> - sbrec_port_binding_delete(op->sb);
> - ovn_port_destroy(ports, op);
> - op = ovn_port_create(ports, nbsp->name, nbsp,
> - NULL, NULL);
> - ovs_list_push_back(nb_only, &op->list);
> - } else {
> - ovn_port_set_nb(op, nbsp, NULL);
> - ovs_list_remove(&op->list);
> -
> - uint32_t queue_id = smap_get_int(&op->sb->options,
> - "qdisc_queue_id",
> 0);
> - if (queue_id && op->sb->chassis) {
> - add_chassis_queue(
> - chassis_qdisc_queues,
> - &op->sb->chassis->header_.uuid,
> - queue_id);
> - }
> -
> - ovs_list_push_back(both, &op->list);
> -
> - /* This port exists due to a SB binding, but should
> - * not have been initialized fully. */
> - ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs);
> - }
> - } else {
> - op = ovn_port_create(ports, nbsp->name, nbsp, NULL,
> NULL);
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + ovs_assert(od->nbs);
> + size_t n_allocated_localnet_ports = 0;
> + for (size_t i = 0; i < od->nbs->n_ports; i++) {
> + const struct nbrec_logical_switch_port *nbsp
> + = od->nbs->ports[i];
> + struct ovn_port *op = ovn_port_find_bound(ports, nbsp->name);
> + if (op && (op->od || op->nbsp || op->nbrp)) {
> + static struct vlog_rate_limit rl
> + = VLOG_RATE_LIMIT_INIT(5, 1);
> + VLOG_WARN_RL(&rl, "duplicate logical port %s", nbsp->name);
> + continue;
> + } else if (op && (!op->sb || op->sb->datapath == od->sb)) {
> + /*
> + * Handle cases where lport type was explicitly changed
> + * in the NBDB, in such cases:
> + * 1. remove the current sbrec of the affected lport from
> + * the port_binding table.
> + *
> + * 2. create a new sbrec with the same logical_port as the
> + * deleted lport and add it to the nb_only list which
> + * will make the northd handle this lport as a new
> + * created one and recompute everything that is needed
> + * for this lport.
> + *
> + * This change will affect container/virtual lport type
> + * changes only for now, this change is needed in
> + * contaier/virtual lport cases to avoid port type
> + * conflicts in the ovn-controller when the user clears
> + * the parent_port field in the container lport or updated
> + * the lport type.
> + *
> + */
> + bool update_sbrec = false;
> + if (op->sb && lsp_is_type_changed(op->sb, nbsp,
> + &update_sbrec)
> + && update_sbrec) {
> + ovs_list_remove(&op->list);
> + sbrec_port_binding_delete(op->sb);
> + ovn_port_destroy(ports, op);
> + op = ovn_port_create(ports, nbsp->name, nbsp,
> + NULL, NULL);
> ovs_list_push_back(nb_only, &op->list);
> - }
> + } else {
> + ovn_port_set_nb(op, nbsp, NULL);
> + ovs_list_remove(&op->list);
>
> - if (lsp_is_localnet(nbsp)) {
> - if (od->n_localnet_ports >= n_allocated_localnet_ports) {
> - od->localnet_ports = x2nrealloc(
> - od->localnet_ports, &n_allocated_localnet_ports,
> - sizeof *od->localnet_ports);
> - }
> - od->localnet_ports[od->n_localnet_ports++] = op;
> - }
> + uint32_t queue_id = smap_get_int(&op->sb->options,
> + "qdisc_queue_id", 0);
> + if (queue_id && op->sb->chassis) {
> + add_chassis_queue(
> + chassis_qdisc_queues,
> + &op->sb->chassis->header_.uuid,
> + queue_id);
> + }
>
> - if (lsp_is_vtep(nbsp)) {
> - od->has_vtep_lports = true;
> - }
> + ovs_list_push_back(both, &op->list);
>
> - op->lsp_addrs
> - = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses);
> - for (size_t j = 0; j < nbsp->n_addresses; j++) {
> - if (!strcmp(nbsp->addresses[j], "unknown")) {
> - op->has_unknown = true;
> - continue;
> - }
> - if (!strcmp(nbsp->addresses[j], "router")) {
> - continue;
> - }
> - if (is_dynamic_lsp_address(nbsp->addresses[j])) {
> - continue;
> - } else if (!extract_lsp_addresses(nbsp->addresses[j],
> - &op->lsp_addrs[op->n_lsp_addrs]))
> {
> - static struct vlog_rate_limit rl
> - = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical "
> - "switch port addresses. No MAC "
> - "address found",
> - op->nbsp->addresses[j]);
> - continue;
> - }
> - op->n_lsp_addrs++;
> - }
> - op->n_lsp_non_router_addrs = op->n_lsp_addrs;
> -
> - op->ps_addrs
> - = xmalloc(sizeof *op->ps_addrs * nbsp->n_port_security);
> - for (size_t j = 0; j < nbsp->n_port_security; j++) {
> - if (!extract_lsp_addresses(nbsp->port_security[j],
> -
> &op->ps_addrs[op->n_ps_addrs])) {
> - static struct vlog_rate_limit rl
> - = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_INFO_RL(&rl, "invalid syntax '%s' in port "
> - "security. No MAC address found",
> - op->nbsp->port_security[j]);
> - continue;
> - }
> - op->n_ps_addrs++;
> + /* This port exists due to a SB binding, but should
> + * not have been initialized fully. */
> + ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs);
> }
> + } else {
> + op = ovn_port_create(ports, nbsp->name, nbsp, NULL, NULL);
> + ovs_list_push_back(nb_only, &op->list);
> + }
>
> - op->od = od;
> - ovs_list_push_back(&od->port_list, &op->dp_node);
> - tag_alloc_add_existing_tags(tag_alloc_table, nbsp);
> + if (lsp_is_localnet(nbsp)) {
> + if (od->n_localnet_ports >= n_allocated_localnet_ports) {
> + od->localnet_ports = x2nrealloc(
> + od->localnet_ports, &n_allocated_localnet_ports,
> + sizeof *od->localnet_ports);
> + }
> + od->localnet_ports[od->n_localnet_ports++] = op;
> }
> - } else {
> - size_t n_allocated_l3dgw_ports = 0;
> - for (size_t i = 0; i < od->nbr->n_ports; i++) {
> - const struct nbrec_logical_router_port *nbrp
> - = od->nbr->ports[i];
>
> - struct lport_addresses lrp_networks;
> - if (!extract_lrp_networks(nbrp, &lrp_networks)) {
> - static struct vlog_rate_limit rl
> - = VLOG_RATE_LIMIT_INIT(5, 1);
> - VLOG_WARN_RL(&rl, "bad 'mac' %s", nbrp->mac);
> + if (lsp_is_vtep(nbsp)) {
> + od->has_vtep_lports = true;
> + }
> +
> + op->lsp_addrs
> + = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses);
> + for (size_t j = 0; j < nbsp->n_addresses; j++) {
> + if (!strcmp(nbsp->addresses[j], "unknown")) {
> + op->has_unknown = true;
> continue;
> }
> -
> - if (!lrp_networks.n_ipv4_addrs &&
> !lrp_networks.n_ipv6_addrs) {
> + if (!strcmp(nbsp->addresses[j], "router")) {
> continue;
> }
> -
> - struct ovn_port *op = ovn_port_find_bound(ports, nbrp->name);
> - if (op && (op->od || op->nbsp || op->nbrp)) {
> + if (is_dynamic_lsp_address(nbsp->addresses[j])) {
> + continue;
> + } else if (!extract_lsp_addresses(nbsp->addresses[j],
> + &op->lsp_addrs[op->n_lsp_addrs])) {
> static struct vlog_rate_limit rl
> - = VLOG_RATE_LIMIT_INIT(5, 1);
> - VLOG_WARN_RL(&rl, "duplicate logical router port %s",
> - nbrp->name);
> - destroy_lport_addresses(&lrp_networks);
> + = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical "
> + "switch port addresses. No MAC "
> + "address found",
> + op->nbsp->addresses[j]);
> continue;
> - } else if (op && (!op->sb || op->sb->datapath == od->sb)) {
> - ovn_port_set_nb(op, NULL, nbrp);
> - ovs_list_remove(&op->list);
> - ovs_list_push_back(both, &op->list);
> + }
> + op->n_lsp_addrs++;
> + }
> + op->n_lsp_non_router_addrs = op->n_lsp_addrs;
>
> - /* This port exists but should not have been
> - * initialized fully. */
> - ovs_assert(!op->lrp_networks.n_ipv4_addrs
> - && !op->lrp_networks.n_ipv6_addrs);
> - } else {
> - op = ovn_port_create(ports, nbrp->name, NULL, nbrp,
> NULL);
> - ovs_list_push_back(nb_only, &op->list);
> + op->ps_addrs
> + = xmalloc(sizeof *op->ps_addrs * nbsp->n_port_security);
> + for (size_t j = 0; j < nbsp->n_port_security; j++) {
> + if (!extract_lsp_addresses(nbsp->port_security[j],
> + &op->ps_addrs[op->n_ps_addrs])) {
> + static struct vlog_rate_limit rl
> + = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_INFO_RL(&rl, "invalid syntax '%s' in port "
> + "security. No MAC address found",
> + op->nbsp->port_security[j]);
> + continue;
> }
> + op->n_ps_addrs++;
> + }
>
> - op->lrp_networks = lrp_networks;
> - op->od = od;
> - ovs_list_push_back(&od->port_list, &op->dp_node);
> + op->od = od;
> + ovs_list_push_back(&od->port_list, &op->dp_node);
> + tag_alloc_add_existing_tags(tag_alloc_table, nbsp);
> + }
> + }
> + HMAP_FOR_EACH (od, key_node, lr_datapaths) {
> + ovs_assert(od->nbr);
> + size_t n_allocated_l3dgw_ports = 0;
> + for (size_t i = 0; i < od->nbr->n_ports; i++) {
> + const struct nbrec_logical_router_port *nbrp
> + = od->nbr->ports[i];
>
> - if (!od->redirect_bridged) {
> - const char *redirect_type =
> - smap_get(&nbrp->options, "redirect-type");
> - od->redirect_bridged =
> - redirect_type && !strcasecmp(redirect_type,
> "bridged");
> - }
> + struct lport_addresses lrp_networks;
> + if (!extract_lrp_networks(nbrp, &lrp_networks)) {
> + static struct vlog_rate_limit rl
> + = VLOG_RATE_LIMIT_INIT(5, 1);
> + VLOG_WARN_RL(&rl, "bad 'mac' %s", nbrp->mac);
> + continue;
> + }
>
> - if (op->nbrp->ha_chassis_group ||
> - op->nbrp->n_gateway_chassis) {
> - /* Additional "derived" ovn_port crp represents the
> - * instance of op on the gateway chassis. */
> - const char *gw_chassis = smap_get(&op->od->nbr->options,
> - "chassis");
> - if (gw_chassis) {
> - static struct vlog_rate_limit rl
> - = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_WARN_RL(&rl, "Bad configuration: distributed "
> - "gateway port configured on port %s "
> - "on L3 gateway router", nbrp->name);
> - continue;
> - }
> + if (!lrp_networks.n_ipv4_addrs && !lrp_networks.n_ipv6_addrs) {
> + continue;
> + }
>
> - char *redirect_name =
> - ovn_chassis_redirect_name(nbrp->name);
> - struct ovn_port *crp = ovn_port_find(ports,
> redirect_name);
> - if (crp && crp->sb && crp->sb->datapath == od->sb) {
> - ovn_port_set_nb(crp, NULL, nbrp);
> - ovs_list_remove(&crp->list);
> - ovs_list_push_back(both, &crp->list);
> - } else {
> - crp = ovn_port_create(ports, redirect_name,
> - NULL, nbrp, NULL);
> - ovs_list_push_back(nb_only, &crp->list);
> - }
> - crp->l3dgw_port = op;
> - op->cr_port = crp;
> - crp->od = od;
> - free(redirect_name);
> + struct ovn_port *op = ovn_port_find_bound(ports, nbrp->name);
> + if (op && (op->od || op->nbsp || op->nbrp)) {
> + static struct vlog_rate_limit rl
> + = VLOG_RATE_LIMIT_INIT(5, 1);
> + VLOG_WARN_RL(&rl, "duplicate logical router port %s",
> + nbrp->name);
> + destroy_lport_addresses(&lrp_networks);
> + continue;
> + } else if (op && (!op->sb || op->sb->datapath == od->sb)) {
> + ovn_port_set_nb(op, NULL, nbrp);
> + ovs_list_remove(&op->list);
> + ovs_list_push_back(both, &op->list);
> +
> + /* This port exists but should not have been
> + * initialized fully. */
> + ovs_assert(!op->lrp_networks.n_ipv4_addrs
> + && !op->lrp_networks.n_ipv6_addrs);
> + } else {
> + op = ovn_port_create(ports, nbrp->name, NULL, nbrp, NULL);
> + ovs_list_push_back(nb_only, &op->list);
> + }
>
> - /* Add to l3dgw_ports in od, for later use during flow
> - * creation. */
> - if (od->n_l3dgw_ports == n_allocated_l3dgw_ports) {
> - od->l3dgw_ports = x2nrealloc(od->l3dgw_ports,
> -
> &n_allocated_l3dgw_ports,
> - sizeof
> *od->l3dgw_ports);
> - }
> - od->l3dgw_ports[od->n_l3dgw_ports++] = op;
> + op->lrp_networks = lrp_networks;
> + op->od = od;
> + ovs_list_push_back(&od->port_list, &op->dp_node);
>
> - assign_routable_addresses(op);
> + if (!od->redirect_bridged) {
> + const char *redirect_type =
> + smap_get(&nbrp->options, "redirect-type");
> + od->redirect_bridged =
> + redirect_type && !strcasecmp(redirect_type, "bridged");
> + }
> +
> + if (op->nbrp->ha_chassis_group ||
> + op->nbrp->n_gateway_chassis) {
> + /* Additional "derived" ovn_port crp represents the
> + * instance of op on the gateway chassis. */
> + const char *gw_chassis = smap_get(&op->od->nbr->options,
> + "chassis");
> + if (gw_chassis) {
> + static struct vlog_rate_limit rl
> + = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_WARN_RL(&rl, "Bad configuration: distributed "
> + "gateway port configured on port %s "
> + "on L3 gateway router", nbrp->name);
> + continue;
> }
> +
> + char *redirect_name =
> + ovn_chassis_redirect_name(nbrp->name);
> + struct ovn_port *crp = ovn_port_find(ports, redirect_name);
> + if (crp && crp->sb && crp->sb->datapath == od->sb) {
> + ovn_port_set_nb(crp, NULL, nbrp);
> + ovs_list_remove(&crp->list);
> + ovs_list_push_back(both, &crp->list);
> + } else {
> + crp = ovn_port_create(ports, redirect_name,
> + NULL, nbrp, NULL);
> + ovs_list_push_back(nb_only, &crp->list);
> + }
> + crp->l3dgw_port = op;
> + op->cr_port = crp;
> + crp->od = od;
> + free(redirect_name);
> +
> + /* Add to l3dgw_ports in od, for later use during flow
> + * creation. */
> + if (od->n_l3dgw_ports == n_allocated_l3dgw_ports) {
> + od->l3dgw_ports = x2nrealloc(od->l3dgw_ports,
> + &n_allocated_l3dgw_ports,
> + sizeof *od->l3dgw_ports);
> + }
> + od->l3dgw_ports[od->n_l3dgw_ports++] = op;
> +
> + assign_routable_addresses(op);
> }
> }
> }
> @@ -3704,14 +3739,14 @@ ovn_port_update_sbrec(struct northd_input *input_data,
> * deleted. */
> static void
> cleanup_mac_bindings(struct northd_input *input_data,
> - struct hmap *datapaths,
> + struct hmap *lr_datapaths,
> struct hmap *lr_ports)
> {
> const struct sbrec_mac_binding *b;
> SBREC_MAC_BINDING_TABLE_FOR_EACH_SAFE (b,
> input_data->sbrec_mac_binding_table) {
> const struct ovn_datapath *od =
> - ovn_datapath_from_sbrec(datapaths, b->datapath);
> + ovn_datapath_from_sbrec(NULL, lr_datapaths, b->datapath);
>
> if (!od || ovn_datapath_is_stale(od) ||
> !ovn_port_find(lr_ports, b->logical_port)) {
> @@ -3735,14 +3770,14 @@ cleanup_sb_ha_chassis_groups(struct northd_input
> *input_data,
>
> static void
> cleanup_stale_fdb_entries(struct northd_input *input_data,
> - struct hmap *datapaths)
> + struct hmap *ls_datapaths)
> {
> const struct sbrec_fdb *fdb_e;
> SBREC_FDB_TABLE_FOR_EACH_SAFE (fdb_e,
> input_data->sbrec_fdb_table) {
> bool delete = true;
> struct ovn_datapath *od
> - = ovn_datapath_find_by_key(datapaths, fdb_e->dp_key);
> + = ovn_datapath_find_by_key(ls_datapaths, fdb_e->dp_key);
> if (od) {
> if (ovn_tnlid_present(&od->port_tnlids, fdb_e->port_key)) {
> delete = false;
> @@ -3988,8 +4023,8 @@ build_lrouter_lb_ips(struct ovn_lb_ip_set *lb_ips,
> }
>
> static void
> -build_lbs(struct northd_input *input_data, struct hmap *datapaths,
> - struct hmap *lbs, struct hmap *lb_groups)
> +build_lbs(struct northd_input *input_data, struct hmap *ls_datapaths,
> + struct hmap *lr_datapaths, struct hmap *lbs, struct hmap
> *lb_groups)
> {
> const struct nbrec_load_balancer_group *nbrec_lb_group;
> struct ovn_lb_group *lb_group;
> @@ -4002,7 +4037,8 @@ build_lbs(struct northd_input *input_data, struct hmap
> *datapaths,
> NBREC_LOAD_BALANCER_TABLE_FOR_EACH (nbrec_lb,
> input_data->nbrec_load_balancer_table) {
> struct ovn_northd_lb *lb_nb = ovn_northd_lb_create(nbrec_lb,
> - n_datapaths);
> + n_ls_datapaths,
> + n_lr_datapaths);
> hmap_insert(lbs, &lb_nb->hmap_node,
> uuid_hash(&nbrec_lb->header_.uuid));
> }
> @@ -4010,7 +4046,8 @@ build_lbs(struct northd_input *input_data, struct hmap
> *datapaths,
> NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH (nbrec_lb_group,
> input_data->nbrec_load_balancer_group_table) {
> lb_group = ovn_lb_group_create(nbrec_lb_group, lbs,
> - hmap_count(datapaths));
> + hmap_count(ls_datapaths),
> + hmap_count(lr_datapaths));
>
> for (size_t i = 0; i < lb_group->n_lbs; i++) {
> build_lrouter_lb_ips(lb_group->lb_ips, lb_group->lbs[i]);
> @@ -4021,7 +4058,7 @@ build_lbs(struct northd_input *input_data, struct hmap
> *datapaths,
> }
>
> struct ovn_datapath *od;
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> if (!od->nbs) {
> continue;
> }
> @@ -4048,7 +4085,7 @@ build_lbs(struct northd_input *input_data, struct hmap
> *datapaths,
> }
> }
>
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + HMAP_FOR_EACH (od, key_node, lr_datapaths) {
> if (!od->nbr) {
> continue;
> }
> @@ -4198,11 +4235,11 @@ build_lrouter_lb_reachable_ips(struct ovn_datapath
> *od,
> }
>
> static void
> -build_lrouter_lbs_check(const struct hmap *datapaths)
> +build_lrouter_lbs_check(const struct hmap *lr_datapaths)
> {
> struct ovn_datapath *od;
>
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + HMAP_FOR_EACH (od, key_node, lr_datapaths) {
> if (!od->nbr) {
> continue;
> }
> @@ -4221,12 +4258,12 @@ build_lrouter_lbs_check(const struct hmap *datapaths)
> }
>
> static void
> -build_lrouter_lbs_reachable_ips(struct hmap *datapaths, struct hmap *lbs,
> +build_lrouter_lbs_reachable_ips(struct hmap *lr_datapaths, struct hmap *lbs,
> struct hmap *lb_groups)
> {
> struct ovn_datapath *od;
>
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + HMAP_FOR_EACH (od, key_node, lr_datapaths) {
> if (!od->nbr) {
> continue;
> }
> @@ -4263,8 +4300,8 @@ build_lswitch_lbs_from_lrouter(struct hmap *lbs, struct
> hmap *lb_groups)
> size_t index;
>
> HMAP_FOR_EACH (lb, hmap_node, lbs) {
> - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) {
> - struct ovn_datapath *od = datapaths_array[index];
> + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) {
> + struct ovn_datapath *od = lr_datapaths_array[index];
> ovn_northd_lb_add_ls(lb, od->n_ls_peers, od->ls_peers);
> }
> }
> @@ -4288,8 +4325,8 @@ build_lb_count_dps(struct hmap *lbs)
> struct ovn_northd_lb *lb;
>
> HMAP_FOR_EACH (lb, hmap_node, lbs) {
> - lb->n_nb_lr = bitmap_count1(lb->nb_lr_map, n_datapaths);
> - lb->n_nb_ls = bitmap_count1(lb->nb_ls_map, n_datapaths);
> + lb->n_nb_lr = bitmap_count1(lb->nb_lr_map, n_lr_datapaths);
> + lb->n_nb_ls = bitmap_count1(lb->nb_ls_map, n_ls_datapaths);
> }
> }
>
> @@ -4298,13 +4335,13 @@ build_lb_count_dps(struct hmap *lbs)
> * networks to have been parsed.
> */
> static void
> -build_lb_port_related_data(struct hmap *datapaths, struct hmap *ls_ports,
> +build_lb_port_related_data(struct hmap *lr_datapaths, struct hmap *ls_ports,
> struct hmap *lbs, struct hmap *lb_groups,
> struct northd_input *input_data,
> struct ovsdb_idl_txn *ovnsb_txn)
> {
> - build_lrouter_lbs_check(datapaths);
> - build_lrouter_lbs_reachable_ips(datapaths, lbs, lb_groups);
> + build_lrouter_lbs_check(lr_datapaths);
> + build_lrouter_lbs_reachable_ips(lr_datapaths, lbs, lb_groups);
> build_lb_svcs(input_data, ovnsb_txn, ls_ports, lbs);
> build_lswitch_lbs_from_lrouter(lbs, lb_groups);
> }
> @@ -4318,12 +4355,13 @@ struct ovn_dp_group {
>
> static struct ovn_dp_group *
> ovn_dp_group_find(const struct hmap *dp_groups,
> - const unsigned long *dpg_bitmap, uint32_t hash)
> + const unsigned long *dpg_bitmap, size_t bitmap_len,
> + uint32_t hash)
> {
> struct ovn_dp_group *dpg;
>
> HMAP_FOR_EACH_WITH_HASH (dpg, node, hash, dp_groups) {
> - if (bitmap_equal(dpg->bitmap, dpg_bitmap, n_datapaths)) {
> + if (bitmap_equal(dpg->bitmap, dpg_bitmap, bitmap_len)) {
> return dpg;
> }
> }
> @@ -4332,14 +4370,16 @@ ovn_dp_group_find(const struct hmap *dp_groups,
>
> static struct sbrec_logical_dp_group *
> ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn *ovnsb_txn,
> - const unsigned long *dpg_bitmap)
> + const unsigned long *dpg_bitmap,
> + size_t bitmap_len,
> + struct ovn_datapath **datapaths_array)
> {
> struct sbrec_logical_dp_group *dp_group;
> const struct sbrec_datapath_binding **sb;
> size_t n = 0, index;
>
> - sb = xmalloc(bitmap_count1(dpg_bitmap, n_datapaths) * sizeof *sb);
> - BITMAP_FOR_EACH_1 (index, n_datapaths, dpg_bitmap) {
> + sb = xmalloc(bitmap_count1(dpg_bitmap, bitmap_len) * sizeof *sb);
> + BITMAP_FOR_EACH_1 (index, bitmap_len, dpg_bitmap) {
> sb[n++] = datapaths_array[index]->sb;
> }
> dp_group = sbrec_logical_dp_group_insert(ovnsb_txn);
> @@ -4355,7 +4395,7 @@ ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn
> *ovnsb_txn,
> */
> static void
> sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn,
> - struct hmap *datapaths, struct hmap *lbs)
> + struct hmap *ls_datapaths, struct hmap *lbs)
> {
> struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups);
> struct ovn_northd_lb *lb;
> @@ -4401,11 +4441,11 @@ sync_lbs(struct northd_input *input_data, struct
> ovsdb_idl_txn *ovnsb_txn,
> struct ovn_dp_group *dpg = xzalloc(sizeof *dpg);
> size_t i, n = 0;
>
> - dpg->bitmap = bitmap_allocate(n_datapaths);
> + dpg->bitmap = bitmap_allocate(n_ls_datapaths);
> for (i = 0; i < dp_group->n_datapaths; i++) {
> struct ovn_datapath *datapath_od;
>
> - datapath_od = ovn_datapath_from_sbrec(datapaths,
> + datapath_od = ovn_datapath_from_sbrec(ls_datapaths, NULL,
> dp_group->datapaths[i]);
> if (!datapath_od || ovn_datapath_is_stale(datapath_od)) {
> break;
> @@ -4416,7 +4456,8 @@ sync_lbs(struct northd_input *input_data, struct
> ovsdb_idl_txn *ovnsb_txn,
> if (i == dp_group->n_datapaths) {
> uint32_t hash = hash_int(n, 0);
>
> - if (!ovn_dp_group_find(&dp_groups, dpg->bitmap, hash)) {
> + if (!ovn_dp_group_find(&dp_groups, dpg->bitmap, n_ls_datapaths,
> + hash)) {
> dpg->dp_group = dp_group;
> hmap_insert(&dp_groups, &dpg->node, hash);
> continue;
> @@ -4459,12 +4500,15 @@ sync_lbs(struct northd_input *input_data, struct
> ovsdb_idl_txn *ovnsb_txn,
> uint32_t hash;
>
> hash = hash_int(lb->n_nb_ls, 0);
> - dpg = ovn_dp_group_find(&dp_groups, lb->nb_ls_map, hash);
> + dpg = ovn_dp_group_find(&dp_groups, lb->nb_ls_map, n_ls_datapaths,
> + hash);
> if (!dpg) {
> dpg = xzalloc(sizeof *dpg);
> dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn,
> - lb->nb_ls_map);
> - dpg->bitmap = bitmap_clone(lb->nb_ls_map, n_datapaths);
> + lb->nb_ls_map,
> + n_ls_datapaths,
> +
> ls_datapaths_array);
> + dpg->bitmap = bitmap_clone(lb->nb_ls_map, n_ls_datapaths);
> hmap_insert(&dp_groups, &dpg->node, hash);
> }
>
> @@ -4490,10 +4534,8 @@ sync_lbs(struct northd_input *input_data, struct
> ovsdb_idl_txn *ovnsb_txn,
> * schema for compatibility reasons. Reset it to empty, just in case.
> */
> struct ovn_datapath *od;
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> - if (!od->nbs) {
> - continue;
> - }
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + ovs_assert(od->nbs);
>
> if (od->sb->n_load_balancers) {
> sbrec_datapath_binding_set_load_balancers(od->sb, NULL, 0);
> @@ -4572,8 +4614,8 @@ build_ports(struct northd_input *input_data,
> struct ovsdb_idl_txn *ovnsb_txn,
> struct ovsdb_idl_index *sbrec_chassis_by_name,
> struct ovsdb_idl_index *sbrec_chassis_by_hostname,
> - struct hmap *datapaths, struct hmap *ls_ports,
> - struct hmap *lr_ports)
> + struct hmap *ls_datapaths, struct hmap *lr_datapaths,
> + struct hmap *ls_ports, struct hmap *lr_ports)
> {
> struct ovs_list sb_only, nb_only, both;
> struct hmap tag_alloc_table = HMAP_INITIALIZER(&tag_alloc_table);
> @@ -4586,8 +4628,8 @@ build_ports(struct northd_input *input_data,
> /* Borrow ls_ports for joining NB and SB for both LSPs and LRPs.
> * We will split them later. */
> struct hmap *ports = ls_ports;
> - join_logical_ports(input_data,
> - datapaths, ports, &chassis_qdisc_queues,
> + join_logical_ports(input_data, ls_datapaths, lr_datapaths,
> + ports, &chassis_qdisc_queues,
> &tag_alloc_table, &sb_only, &nb_only, &both);
>
> /* Purge stale Mac_Bindings if ports are deleted. */
> @@ -4669,7 +4711,7 @@ build_ports(struct northd_input *input_data,
> }
>
> if (remove_mac_bindings) {
> - cleanup_mac_bindings(input_data, datapaths, lr_ports);
> + cleanup_mac_bindings(input_data, lr_datapaths, lr_ports);
> }
>
> tag_alloc_destroy(&tag_alloc_table);
> @@ -5101,11 +5143,11 @@ static int parallelization_state = STATE_NULL;
>
> static void
> ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
> - enum ovn_stage stage, uint16_t priority,
> + size_t dp_bitmap_len, enum ovn_stage stage, uint16_t priority,
> char *match, char *actions, char *io_port, char *ctrl_meter,
> char *stage_hint, const char *where)
> {
> - lflow->dpg_bitmap = bitmap_allocate(n_datapaths);
> + lflow->dpg_bitmap = bitmap_allocate(dp_bitmap_len);
> lflow->od = od;
> lflow->stage = stage;
> lflow->priority = priority;
> @@ -5219,14 +5261,15 @@ static thread_local size_t thread_lflow_counter = 0;
> static void
> ovn_dp_group_add_with_reference(struct ovn_lflow *lflow_ref,
> const struct ovn_datapath *od,
> - const unsigned long *dp_bitmap)
> + const unsigned long *dp_bitmap,
> + size_t bitmap_len)
> OVS_REQUIRES(fake_hash_mutex)
> {
> if (od) {
> bitmap_set1(lflow_ref->dpg_bitmap, od->index);
> }
> if (dp_bitmap) {
> - bitmap_or(lflow_ref->dpg_bitmap, dp_bitmap, n_datapaths);
> + bitmap_or(lflow_ref->dpg_bitmap, dp_bitmap, bitmap_len);
> }
> }
>
> @@ -5246,10 +5289,13 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct
> ovn_datapath *od,
> struct ovn_lflow *old_lflow;
> struct ovn_lflow *lflow;
>
> + size_t n_datapaths = ovn_stage_to_datapath_type(stage) == DP_SWITCH ?
> + n_ls_datapaths : n_lr_datapaths;
> +
> old_lflow = ovn_lflow_find(lflow_map, NULL, stage, priority, match,
> actions, ctrl_meter, hash);
> if (old_lflow) {
> - ovn_dp_group_add_with_reference(old_lflow, od, dp_bitmap);
> + ovn_dp_group_add_with_reference(old_lflow, od, dp_bitmap,
> n_datapaths);
> return;
> }
>
> @@ -5257,13 +5303,13 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct
> ovn_datapath *od,
> /* While adding new logical flows we're not setting single datapath, but
> * collecting a group. 'od' will be updated later for all flows with
> only
> * one datapath in a group, so it could be hashed correctly. */
> - ovn_lflow_init(lflow, NULL, stage, priority,
> + ovn_lflow_init(lflow, NULL, n_datapaths, stage, priority,
> xstrdup(match), xstrdup(actions),
> io_port ? xstrdup(io_port) : NULL,
> nullable_xstrdup(ctrl_meter),
> ovn_lflow_hint(stage_hint), where);
>
> - ovn_dp_group_add_with_reference(lflow, od, dp_bitmap);
> + ovn_dp_group_add_with_reference(lflow, od, dp_bitmap, n_datapaths);
>
> if (parallelization_state != STATE_USE_PARALLELIZATION) {
> hmap_insert(lflow_map, &lflow->hmap_node, hash);
> @@ -5772,9 +5818,7 @@ static void
> build_lswitch_learn_fdb_od(
> struct ovn_datapath *od, struct hmap *lflows)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
> ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;");
> ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;");
> }
> @@ -5786,9 +5830,7 @@ static void
> build_lswitch_output_port_sec_od(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
> ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 100,
> "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;");
> ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 0, "1",
> @@ -7166,7 +7208,7 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct
> ovn_northd_lb *lb,
> char *lb_action, const unsigned long *dp_bitmap)
> {
> if (!lb->affinity_timeout ||
> - bitmap_is_all_zeros(dp_bitmap, n_datapaths)) {
> + bitmap_is_all_zeros(dp_bitmap, n_lr_datapaths)) {
> return;
> }
>
> @@ -7476,9 +7518,7 @@ static void
> build_lswitch_lb_affinity_default_flows(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
> ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;");
> ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;");
> }
> @@ -7487,9 +7527,7 @@ static void
> build_lrouter_lb_affinity_default_flows(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;");
> ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;");
> }
> @@ -7539,9 +7577,9 @@ build_lb_rules(struct hmap *lflows, struct
> ovn_northd_lb *lb,
> if (reject) {
> size_t index;
>
> - dp_non_meter = bitmap_clone(lb->nb_ls_map, n_datapaths);
> - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_ls_map) {
> - struct ovn_datapath *od = datapaths_array[index];
> + dp_non_meter = bitmap_clone(lb->nb_ls_map, n_ls_datapaths);
> + BITMAP_FOR_EACH_1 (index, n_ls_datapaths, lb->nb_ls_map) {
> + struct ovn_datapath *od = ls_datapaths_array[index];
>
> meter = copp_meter_get(COPP_REJECT, od->nbs->copp,
> meter_groups);
> @@ -7717,8 +7755,8 @@ build_vtep_hairpin(struct ovn_datapath *od, struct hmap
> *lflows)
> static void
> build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows)
> {
> -
> - if (!od->nbs || !od->nbs->n_forwarding_groups) {
> + ovs_assert(od->nbs);
> + if (!od->nbs->n_forwarding_groups) {
> return;
> }
> struct ds match = DS_EMPTY_INITIALIZER;
> @@ -8399,9 +8437,7 @@ build_lswitch_lflows_pre_acl_and_acl(struct
> ovn_datapath *od,
> struct hmap *lflows,
> const struct shash *meter_groups)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
> ls_get_acl_flags(od);
>
> build_pre_acls(od, port_groups, lflows);
> @@ -8421,9 +8457,7 @@ static void
> build_lswitch_lflows_admission_control(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
> /* Logical VLANs not supported. */
> if (!is_vlan_transparent(od)) {
> /* Block logical VLANs. */
> @@ -8786,9 +8820,8 @@ static void
> build_lswitch_arp_nd_responder_default(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (od->nbs) {
> - ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;");
> - }
> + ovs_assert(od->nbs);
> + ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;");
> }
>
> /* Ingress table 19: ARP/ND responder for service monitor source ip.
> @@ -8921,9 +8954,7 @@ static void
> build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
> ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;");
> ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;");
> ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;");
> @@ -8939,7 +8970,8 @@ build_lswitch_dns_lookup_and_response(struct
> ovn_datapath *od,
> struct hmap *lflows,
> const struct shash *meter_groups)
> {
> - if (!od->nbs || !ls_has_dns_records(od->nbs)) {
> + ovs_assert(od->nbs);
> + if (!ls_has_dns_records(od->nbs)) {
> return;
> }
> ovn_lflow_metered(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100,
> @@ -8986,9 +9018,7 @@ build_lswitch_destination_lookup_bmcast(struct
> ovn_datapath *od,
> struct ds *actions,
> const struct shash *meter_groups)
> {
> - if (!od->nbs) {
> - return;
> - }
> + ovs_assert(od->nbs);
>
> ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110,
> "eth.dst == $svc_monitor_mac",
> @@ -10650,14 +10680,14 @@ build_gw_lrouter_nat_flows_for_lb(struct
> lrouter_nat_lb_flows_ctx *ctx,
> bool build_non_meter = false;
> size_t index;
>
> - if (bitmap_is_all_zeros(dp_bitmap, n_datapaths)) {
> + if (bitmap_is_all_zeros(dp_bitmap, n_lr_datapaths)) {
> return;
> }
>
> if (ctx->reject) {
> - dp_non_meter = bitmap_clone(dp_bitmap, n_datapaths);
> - BITMAP_FOR_EACH_1 (index, n_datapaths, dp_bitmap) {
> - struct ovn_datapath *od = datapaths_array[index];
> + dp_non_meter = bitmap_clone(dp_bitmap, n_lr_datapaths);
> + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, dp_bitmap) {
> + struct ovn_datapath *od = lr_datapaths_array[index];
> const char *meter;
>
> meter = copp_meter_get(COPP_REJECT, od->nbr->copp,
> @@ -10795,15 +10825,15 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip
> *lb_vip,
> unsigned long *dp_bitmap[LROUTER_NAT_LB_FLOW_MAX + 2];
>
> for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX + 2; i++) {
> - dp_bitmap[i] = bitmap_allocate(n_datapaths);
> + dp_bitmap[i] = bitmap_allocate(n_lr_datapaths);
> }
>
> /* Group gw router since we do not have datapath dependency in
> * lflow generation for them.
> */
> size_t index;
> - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) {
> - struct ovn_datapath *od = datapaths_array[index];
> + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) {
> + struct ovn_datapath *od = lr_datapaths_array[index];
> enum lrouter_nat_lb_flow_type type;
>
> if (lb->skip_snat) {
> @@ -10897,8 +10927,8 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb,
> struct hmap *lflows,
> }
>
> size_t index;
> - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_ls_map) {
> - struct ovn_datapath *od = datapaths_array[index];
> + BITMAP_FOR_EACH_1 (index, n_ls_datapaths, lb->nb_ls_map) {
> + struct ovn_datapath *od = ls_datapaths_array[index];
>
> ovn_lflow_add_with_hint__(lflows, od,
> S_SWITCH_IN_PRE_LB, 130,
> ds_cstr(match),
> @@ -11001,8 +11031,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb,
> struct hmap *lflows,
> continue;
> }
>
> - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) {
> - struct ovn_datapath *od = datapaths_array[index];
> + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) {
> + struct ovn_datapath *od = lr_datapaths_array[index];
>
> ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT,
> 130, ds_cstr(match), ds_cstr(action),
> @@ -11015,8 +11045,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb,
> struct hmap *lflows,
> }
>
> if (lb->skip_snat) {
> - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) {
> - struct ovn_datapath *od = datapaths_array[index];
> + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) {
> + struct ovn_datapath *od = lr_datapaths_array[index];
>
> ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120,
> "flags.skip_snat_for_lb == 1 && ip", "next;");
> @@ -11619,9 +11649,7 @@ static void
> build_adm_ctrl_flows_for_lrouter(
> struct ovn_datapath *od, struct hmap *lflows)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> /* Logical VLANs not supported.
> * Broadcast/multicast source address is invalid. */
> ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100,
> @@ -11776,9 +11804,7 @@ build_neigh_learning_flows_for_lrouter(
> struct ds *match, struct ds *actions,
> const struct shash *meter_groups)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
>
> /* Learn MAC bindings from ARP/IPv6 ND.
> *
> @@ -12066,10 +12092,9 @@ build_ND_RA_flows_for_lrouter_port(
> static void
> build_ND_RA_flows_for_lrouter(struct ovn_datapath *od, struct hmap *lflows)
> {
> - if (od->nbr) {
> - ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1",
> "next;");
> - ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1",
> "next;");
> - }
> + ovs_assert(od->nbr);
> + ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1", "next;");
> + ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;");
> }
>
> /* Logical router ingress table IP_ROUTING_PRE:
> @@ -12078,10 +12103,9 @@ static void
> build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od,
> struct hmap *lflows)
> {
> - if (od->nbr) {
> - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1",
> - REG_ROUTE_TABLE_ID" = 0; next;");
> - }
> + ovs_assert(od->nbr);
> + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1",
> + REG_ROUTE_TABLE_ID" = 0; next;");
> }
>
> /* Logical router ingress table IP_ROUTING : IP Routing.
> @@ -12172,9 +12196,7 @@ build_static_route_flows_for_lrouter(
> struct hmap *lflows, const struct hmap *lr_ports,
> const struct hmap *bfd_connections)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP);
> ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING);
> ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150,
> @@ -12238,9 +12260,7 @@ build_mcast_lookup_flows_for_lrouter(
> struct ovn_datapath *od, struct hmap *lflows,
> struct ds *match, struct ds *actions)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
>
> /* Drop IPv6 multicast traffic that shouldn't be forwarded,
> * i.e., router solicitation and router advertisement.
> @@ -12341,9 +12361,7 @@ build_ingress_policy_flows_for_lrouter(
> struct ovn_datapath *od, struct hmap *lflows,
> const struct hmap *lr_ports)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> /* This is a catch-all rule. It has the lowest priority (0)
> * does a match-all("1") and pass-through (next) */
> ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1",
> @@ -12376,9 +12394,7 @@ static void
> build_arp_resolve_flows_for_lrouter(
> struct ovn_datapath *od, struct hmap *lflows)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> /* Multicast packets already have the outport set so just advance to
> * next table (priority 500). */
> ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500,
> @@ -12808,9 +12824,7 @@ build_check_pkt_len_flows_for_lrouter(
> struct ds *match, struct ds *actions,
> const struct shash *meter_groups)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
>
> /* Packets are allowed by default. */
> ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 0, "1",
> @@ -12835,9 +12849,7 @@ build_gateway_redirect_flows_for_lrouter(
> struct ovn_datapath *od, struct hmap *lflows,
> struct ds *match, struct ds *actions)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
> if (l3dgw_port_has_associated_vtep_lports(od->l3dgw_ports[i])) {
> /* Skip adding redirect lflow for vtep-enabled l3dgw ports.
> @@ -12924,9 +12936,7 @@ build_arp_request_flows_for_lrouter(
> struct ds *match, struct ds *actions,
> const struct shash *meter_groups)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> for (int i = 0; i < od->nbr->n_static_routes; i++) {
> const struct nbrec_logical_router_static_route *route;
>
> @@ -13044,9 +13054,7 @@ static void
> build_misc_local_traffic_drop_flows_for_lrouter(
> struct ovn_datapath *od, struct hmap *lflows)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> /* Allow IGMP and MLD packets (with TTL = 1) if the router is
> * configured to flood them statically on some ports.
> */
> @@ -13300,9 +13308,7 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath
> *od,
> struct hmap *lflows,
> const struct shash *meter_groups)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
> /* Priority-90-92 flows handle ARP requests and ND packets. Most are
> * per logical port but DNAT addresses can be handled per datapath
> * for non gateway router ports.
> @@ -14265,9 +14271,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath
> *od, struct hmap *lflows,
> const struct shash *meter_groups,
> const struct chassis_features *features)
> {
> - if (!od->nbr) {
> - return;
> - }
> + ovs_assert(od->nbr);
>
> /* Packets are allowed by default. */
> ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;");
> @@ -14590,7 +14594,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath
> *od, struct hmap *lflows,
>
>
> struct lswitch_flow_build_info {
> - const struct hmap *datapaths;
> + const struct hmap *ls_datapaths;
> + const struct hmap *lr_datapaths;
> const struct hmap *ls_ports;
> const struct hmap *lr_ports;
> const struct hmap *port_groups;
> @@ -14608,17 +14613,16 @@ struct lswitch_flow_build_info {
> };
>
> /* Helper function to combine all lflow generation which is iterated by
> - * datapath.
> + * logical switch datapath.
> *
> * When extending the function new "work data" must be added to the lsi
> * struct, not passed as an argument.
> */
> -
> static void
> -build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
> +build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od,
> struct lswitch_flow_build_info *lsi)
> {
> - /* Build Logical Switch Flows. */
> + ovs_assert(od->nbs);
> build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups,
> lsi->features,
> lsi->lflows,
> @@ -14634,8 +14638,16 @@ build_lswitch_and_lrouter_iterate_by_od(struct
> ovn_datapath *od,
> lsi->meter_groups);
> build_lswitch_output_port_sec_od(od, lsi->lflows);
> build_lswitch_lb_affinity_default_flows(od, lsi->lflows);
> +}
>
> - /* Build Logical Router Flows. */
> +/* Helper function to combine all lflow generation which is iterated by
> + * logical router datapath.
> + */
> +static void
> +build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od,
> + struct lswitch_flow_build_info *lsi)
> +{
> + ovs_assert(od->nbr);
> build_adm_ctrl_flows_for_lrouter(od, lsi->lflows);
> build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> &lsi->actions, lsi->meter_groups);
> @@ -14748,14 +14760,27 @@ build_lflows_thread(void *arg)
> if (lsi) {
> /* Iterate over bucket ThreadID, ThreadID+size, ... */
> for (bnum = control->id;
> - bnum <= lsi->datapaths->mask;
> + bnum <= lsi->ls_datapaths->mask;
> + bnum += control->pool->size)
> + {
> + HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum,
> + lsi->ls_datapaths) {
> + if (stop_parallel_processing()) {
> + return NULL;
> + }
> + build_lswitch_and_lrouter_iterate_by_ls(od, lsi);
> + }
> + }
> + for (bnum = control->id;
> + bnum <= lsi->lr_datapaths->mask;
> bnum += control->pool->size)
> {
> - HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum,
> lsi->datapaths) {
> + HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum,
> + lsi->lr_datapaths) {
> if (stop_parallel_processing()) {
> return NULL;
> }
> - build_lswitch_and_lrouter_iterate_by_od(od, lsi);
> + build_lswitch_and_lrouter_iterate_by_lr(od, lsi);
> }
> }
> for (bnum = control->id;
> @@ -14859,7 +14884,8 @@ fix_flow_map_size(struct hmap *lflow_map,
> }
>
> static void
> -build_lswitch_and_lrouter_flows(const struct hmap *datapaths,
> +build_lswitch_and_lrouter_flows(const struct hmap *ls_datapaths,
> + const struct hmap *lr_datapaths,
> const struct hmap *ls_ports,
> const struct hmap *lr_ports,
> const struct hmap *port_groups,
> @@ -14887,7 +14913,8 @@ build_lswitch_and_lrouter_flows(const struct hmap
> *datapaths,
> * on a per-bucket level.
> */
> lsiv[index].lflows = lflows;
> - lsiv[index].datapaths = datapaths;
> + lsiv[index].ls_datapaths = ls_datapaths;
> + lsiv[index].lr_datapaths = lr_datapaths;
> lsiv[index].ls_ports = ls_ports;
> lsiv[index].lr_ports = lr_ports;
> lsiv[index].port_groups = port_groups;
> @@ -14920,7 +14947,8 @@ build_lswitch_and_lrouter_flows(const struct hmap
> *datapaths,
> struct ovn_northd_lb *lb;
> struct ovn_igmp_group *igmp_group;
> struct lswitch_flow_build_info lsi = {
> - .datapaths = datapaths,
> + .ls_datapaths = ls_datapaths,
> + .lr_datapaths = lr_datapaths,
> .ls_ports = ls_ports,
> .lr_ports = lr_ports,
> .port_groups = port_groups,
> @@ -14940,8 +14968,11 @@ build_lswitch_and_lrouter_flows(const struct hmap
> *datapaths,
> * will move here and will be reogranized by iterator type.
> */
> stopwatch_start(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec());
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> - build_lswitch_and_lrouter_iterate_by_od(od, &lsi);
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + build_lswitch_and_lrouter_iterate_by_ls(od, &lsi);
> + }
> + HMAP_FOR_EACH (od, key_node, lr_datapaths) {
> + build_lswitch_and_lrouter_iterate_by_lr(od, &lsi);
> }
> stopwatch_stop(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec());
> stopwatch_start(LFLOWS_PORTS_STOPWATCH_NAME, time_msec());
> @@ -14978,7 +15009,7 @@ build_lswitch_and_lrouter_flows(const struct hmap
> *datapaths,
> }
>
> free(svc_check_match);
> - build_lswitch_flows(datapaths, lflows);
> + build_lswitch_flows(ls_datapaths, lflows);
> }
>
> static void
> @@ -14986,12 +15017,14 @@ ovn_sb_set_lflow_logical_dp_group(
> struct ovsdb_idl_txn *ovnsb_txn,
> struct hmap *dp_groups,
> const struct sbrec_logical_flow *sbflow,
> - const unsigned long *dpg_bitmap)
> + const unsigned long *dpg_bitmap,
> + size_t bitmap_len,
> + struct ovn_datapath **datapaths_array)
> {
> struct ovn_dp_group *dpg;
> size_t n_ods;
>
> - n_ods = bitmap_count1(dpg_bitmap, n_datapaths);
> + n_ods = bitmap_count1(dpg_bitmap, bitmap_len);
>
> if (!n_ods) {
> sbrec_logical_flow_set_logical_dp_group(sbflow, NULL);
> @@ -15000,11 +15033,14 @@ ovn_sb_set_lflow_logical_dp_group(
>
> ovs_assert(n_ods != 1);
>
> - dpg = ovn_dp_group_find(dp_groups, dpg_bitmap, hash_int(n_ods, 0));
> + dpg = ovn_dp_group_find(dp_groups, dpg_bitmap, bitmap_len,
> + hash_int(n_ods, 0));
> ovs_assert(dpg != NULL);
>
> if (!dpg->dp_group) {
> - dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn,
> dpg->bitmap);
> + dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn,
> dpg->bitmap,
> + bitmap_len,
> + datapaths_array);
> }
> sbrec_logical_flow_set_logical_dp_group(sbflow, dpg->dp_group);
> }
> @@ -15031,7 +15067,7 @@ void run_update_worker_pool(int n_threads)
>
> static void
> build_mcast_groups(struct lflow_input *data,
> - const struct hmap *datapaths,
> + const struct hmap *ls_datapaths,
> const struct hmap *ls_ports,
> const struct hmap *lr_ports,
> struct hmap *mcast_groups,
> @@ -15046,13 +15082,14 @@ void build_lflows(struct lflow_input *input_data,
> struct hmap mcast_groups;
> struct hmap igmp_groups;
>
> - build_mcast_groups(input_data, input_data->datapaths,
> + build_mcast_groups(input_data, input_data->ls_datapaths,
> input_data->ls_ports, input_data->lr_ports,
> &mcast_groups, &igmp_groups);
>
> fast_hmap_size_for(&lflows, max_seen_lflow_size);
>
> - build_lswitch_and_lrouter_flows(input_data->datapaths,
> + build_lswitch_and_lrouter_flows(input_data->ls_datapaths,
> + input_data->lr_datapaths,
> input_data->ls_ports,
> input_data->lr_ports,
> input_data->port_groups, &lflows,
> @@ -15076,7 +15113,8 @@ void build_lflows(struct lflow_input *input_data,
>
> stopwatch_start(LFLOWS_DP_GROUPS_STOPWATCH_NAME, time_msec());
> /* Collecting all unique datapath groups. */
> - struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups);
> + struct hmap ls_dp_groups = HMAP_INITIALIZER(&ls_dp_groups);
> + struct hmap lr_dp_groups = HMAP_INITIALIZER(&lr_dp_groups);
> struct hmap single_dp_lflows;
>
> /* Single dp_flows will never grow bigger than lflows,
> @@ -15092,6 +15130,19 @@ void build_lflows(struct lflow_input *input_data,
> struct ovn_dp_group *dpg;
> uint32_t hash, n_ods;
>
> + struct hmap *dp_groups;
> + size_t n_datapaths;
> + struct ovn_datapath **datapaths_array;
> + if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) {
> + n_datapaths = n_ls_datapaths;
> + dp_groups = &ls_dp_groups;
> + datapaths_array = ls_datapaths_array;
> + } else {
> + n_datapaths = n_lr_datapaths;
> + dp_groups = &lr_dp_groups;
> + datapaths_array = lr_datapaths_array;
> + }
> +
> n_ods = bitmap_count1(lflow->dpg_bitmap, n_datapaths);
>
> ovs_assert(n_ods);
> @@ -15117,11 +15168,12 @@ void build_lflows(struct lflow_input *input_data,
> }
>
> hash = hash_int(n_ods, 0);
> - dpg = ovn_dp_group_find(&dp_groups, lflow->dpg_bitmap, hash);
> + dpg = ovn_dp_group_find(dp_groups, lflow->dpg_bitmap, n_datapaths,
> + hash);
> if (!dpg) {
> dpg = xzalloc(sizeof *dpg);
> dpg->bitmap = bitmap_clone(lflow->dpg_bitmap, n_datapaths);
> - hmap_insert(&dp_groups, &dpg->node, hash);
> + hmap_insert(dp_groups, &dpg->node, hash);
> }
> lflow->dpg = dpg;
> }
> @@ -15147,7 +15199,9 @@ void build_lflows(struct lflow_input *input_data,
> struct sbrec_datapath_binding *dp = sbflow->logical_datapath;
> if (dp) {
> logical_datapath_od = ovn_datapath_from_sbrec(
> - input_data->datapaths, dp);
> + input_data->ls_datapaths,
> + input_data->lr_datapaths,
> + dp);
> if (logical_datapath_od
> && ovn_datapath_is_stale(logical_datapath_od)) {
> logical_datapath_od = NULL;
> @@ -15155,7 +15209,9 @@ void build_lflows(struct lflow_input *input_data,
> }
> for (i = 0; dp_group && i < dp_group->n_datapaths; i++) {
> logical_datapath_od = ovn_datapath_from_sbrec(
> - input_data->datapaths, dp_group->datapaths[i]);
> + input_data->ls_datapaths,
> + input_data->lr_datapaths,
> + dp_group->datapaths[i]);
> if (logical_datapath_od
> && !ovn_datapath_is_stale(logical_datapath_od)) {
> break;
> @@ -15179,6 +15235,18 @@ void build_lflows(struct lflow_input *input_data,
> sbflow->priority, sbflow->match, sbflow->actions,
> sbflow->controller_meter, sbflow->hash);
> if (lflow) {
> + struct hmap *dp_groups;
> + size_t n_datapaths;
> + struct ovn_datapath **datapaths_array;
> + if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) {
> + n_datapaths = n_ls_datapaths;
> + dp_groups = &ls_dp_groups;
> + datapaths_array = ls_datapaths_array;
> + } else {
> + n_datapaths = n_lr_datapaths;
> + dp_groups = &lr_dp_groups;
> + datapaths_array = lr_datapaths_array;
> + }
> if (input_data->ovn_internal_version_changed) {
> const char *stage_name = smap_get_def(&sbflow->external_ids,
> "stage-name", "");
> @@ -15231,7 +15299,8 @@ void build_lflows(struct lflow_input *input_data,
> /* Check all logical datapaths from the group. */
> for (i = 0; i < dp_group->n_datapaths; i++) {
> od = ovn_datapath_from_sbrec(
> - input_data->datapaths, dp_group->datapaths[i]);
> + input_data->ls_datapaths,
> input_data->lr_datapaths,
> + dp_group->datapaths[i]);
> if (!od || ovn_datapath_is_stale(od)) {
> continue;
> }
> @@ -15244,8 +15313,10 @@ void build_lflows(struct lflow_input *input_data,
> }
>
> if (update_dp_group) {
> - ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, &dp_groups,
> - sbflow, lflow->dpg_bitmap);
> + ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, dp_groups,
> + sbflow, lflow->dpg_bitmap,
> + n_datapaths,
> + datapaths_array);
> } else if (lflow->dpg && !lflow->dpg->dp_group) {
> /* Setting relation between unique datapath group and
> * Sb DB datapath goup. */
> @@ -15263,12 +15334,26 @@ void build_lflows(struct lflow_input *input_data,
> const char *pipeline = ovn_stage_get_pipeline_name(lflow->stage);
> uint8_t table = ovn_stage_get_table(lflow->stage);
>
> + struct hmap *dp_groups;
> + size_t n_datapaths;
> + struct ovn_datapath **datapaths_array;
> + if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) {
> + n_datapaths = n_ls_datapaths;
> + dp_groups = &ls_dp_groups;
> + datapaths_array = ls_datapaths_array;
> + } else {
> + n_datapaths = n_lr_datapaths;
> + dp_groups = &lr_dp_groups;
> + datapaths_array = lr_datapaths_array;
> + }
> +
> sbflow = sbrec_logical_flow_insert(ovnsb_txn);
> if (lflow->od) {
> sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb);
> }
> - ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, &dp_groups,
> - sbflow, lflow->dpg_bitmap);
> + ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, dp_groups,
> + sbflow, lflow->dpg_bitmap,
> + n_datapaths, datapaths_array);
> sbrec_logical_flow_set_pipeline(sbflow, pipeline);
> sbrec_logical_flow_set_table_id(sbflow, table);
> sbrec_logical_flow_set_priority(sbflow, lflow->priority);
> @@ -15309,18 +15394,25 @@ void build_lflows(struct lflow_input *input_data,
>
> stopwatch_stop(LFLOWS_TO_SB_STOPWATCH_NAME, time_msec());
> struct ovn_dp_group *dpg;
> - HMAP_FOR_EACH_POP (dpg, node, &dp_groups) {
> + HMAP_FOR_EACH_POP (dpg, node, &ls_dp_groups) {
> bitmap_free(dpg->bitmap);
> free(dpg);
> }
> - hmap_destroy(&dp_groups);
> + hmap_destroy(&ls_dp_groups);
> + HMAP_FOR_EACH_POP (dpg, node, &lr_dp_groups) {
> + bitmap_free(dpg->bitmap);
> + free(dpg);
> + }
> + hmap_destroy(&lr_dp_groups);
>
> /* Push changes to the Multicast_Group table to database. */
> const struct sbrec_multicast_group *sbmc;
> SBREC_MULTICAST_GROUP_TABLE_FOR_EACH_SAFE (sbmc,
> input_data->sbrec_multicast_group_table) {
> struct ovn_datapath *od = ovn_datapath_from_sbrec(
> - input_data->datapaths, sbmc->datapath);
> + input_data->ls_datapaths,
> + input_data->lr_datapaths,
> + sbmc->datapath);
>
> if (!od || ovn_datapath_is_stale(od)) {
> sbrec_multicast_group_delete(sbmc);
> @@ -15705,12 +15797,13 @@ get_dns_info_from_hmap(struct hmap *dns_map, struct
> uuid *uuid)
> static void
> sync_dns_entries(struct northd_input *input_data,
> struct ovsdb_idl_txn *ovnsb_txn,
> - struct hmap *datapaths)
> + struct hmap *ls_datapaths)
> {
> struct hmap dns_map = HMAP_INITIALIZER(&dns_map);
> struct ovn_datapath *od;
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> - if (!od->nbs || !od->nbs->n_dns_records) {
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + ovs_assert(od->nbs);
> + if (!od->nbs->n_dns_records) {
> continue;
> }
>
> @@ -15828,9 +15921,9 @@ sync_template_vars(struct northd_input *input_data,
> }
>
> static void
> -destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ls_ports,
> - struct hmap *lr_ports,
> - struct ovs_list *lr_list)
> +destroy_datapaths_and_ports(struct hmap *ls_datapaths,
> + struct hmap *lr_datapaths, struct hmap *ls_ports,
> + struct hmap *lr_ports, struct ovs_list *lr_list)
> {
> struct ovn_datapath *router_dp;
> LIST_FOR_EACH_POP (router_dp, lr_list, lr_list) {
> @@ -15848,10 +15941,15 @@ destroy_datapaths_and_ports(struct hmap *datapaths,
> struct hmap *ls_ports,
> }
>
> struct ovn_datapath *dp;
> - HMAP_FOR_EACH_SAFE (dp, key_node, datapaths) {
> - ovn_datapath_destroy(datapaths, dp);
> + HMAP_FOR_EACH_SAFE (dp, key_node, ls_datapaths) {
> + ovn_datapath_destroy(ls_datapaths, dp);
> + }
> + hmap_destroy(ls_datapaths);
> +
> + HMAP_FOR_EACH_SAFE (dp, key_node, lr_datapaths) {
> + ovn_datapath_destroy(lr_datapaths, dp);
> }
> - hmap_destroy(datapaths);
> + hmap_destroy(lr_datapaths);
>
> struct ovn_port *port;
> HMAP_FOR_EACH_SAFE (port, key_node, ls_ports) {
> @@ -15868,14 +15966,12 @@ destroy_datapaths_and_ports(struct hmap *datapaths,
> struct hmap *ls_ports,
> static void
> build_ip_mcast(struct northd_input *input_data,
> struct ovsdb_idl_txn *ovnsb_txn,
> - struct hmap *datapaths)
> + struct hmap *ls_datapaths)
> {
> struct ovn_datapath *od;
>
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> - if (!od->nbs) {
> - continue;
> - }
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> + ovs_assert(od->nbs);
>
> const struct sbrec_ip_multicast *ip_mcast =
> ip_mcast_lookup(input_data->sbrec_ip_mcast_by_dp, od->sb);
> @@ -15891,7 +15987,7 @@ build_ip_mcast(struct northd_input *input_data,
>
> SBREC_IP_MULTICAST_TABLE_FOR_EACH_SAFE (sb,
> input_data->sbrec_ip_multicast_table) {
> - od = ovn_datapath_from_sbrec(datapaths, sb->datapath);
> + od = ovn_datapath_from_sbrec(ls_datapaths, NULL, sb->datapath);
> if (!od || ovn_datapath_is_stale(od)) {
> sbrec_ip_multicast_delete(sb);
> }
> @@ -15900,7 +15996,7 @@ build_ip_mcast(struct northd_input *input_data,
>
> static void
> build_mcast_groups(struct lflow_input *input_data,
> - const struct hmap *datapaths,
> + const struct hmap *ls_datapaths,
> const struct hmap *ls_ports,
> const struct hmap *lr_ports,
> struct hmap *mcast_groups,
> @@ -15912,7 +16008,7 @@ build_mcast_groups(struct lflow_input *input_data,
> hmap_init(igmp_groups);
> struct ovn_datapath *od;
>
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
> init_mcast_flow_count(od);
> }
>
> @@ -15976,7 +16072,7 @@ build_mcast_groups(struct lflow_input *input_data,
> }
>
> /* If the datapath value is stale, purge the group. */
> - od = ovn_datapath_from_sbrec(datapaths, sb_igmp->datapath);
> + od = ovn_datapath_from_sbrec(ls_datapaths, NULL, sb_igmp->datapath);
>
> if (!od || ovn_datapath_is_stale(od)) {
> sbrec_igmp_group_delete(sb_igmp);
> @@ -16021,7 +16117,7 @@ build_mcast_groups(struct lflow_input *input_data,
> * IGMP groups are based on the groups learnt by their multicast enabled
> * peers.
> */
> - HMAP_FOR_EACH (od, key_node, datapaths) {
> + HMAP_FOR_EACH (od, key_node, ls_datapaths) {
>
> if (ovs_list_is_empty(&od->mcast_info.groups)) {
> continue;
> @@ -16192,7 +16288,8 @@ build_static_mac_binding_table(struct northd_input
> *input_data,
> void
> northd_init(struct northd_data *data)
> {
> - hmap_init(&data->datapaths);
> + hmap_init(&data->ls_datapaths);
> + hmap_init(&data->lr_datapaths);
> hmap_init(&data->ls_ports);
> hmap_init(&data->lr_ports);
> hmap_init(&data->port_groups);
> @@ -16247,8 +16344,9 @@ northd_destroy(struct northd_data *data)
> */
> cleanup_macam();
>
> - destroy_datapaths_and_ports(&data->datapaths, &data->ls_ports,
> - &data->lr_ports, &data->lr_list);
> + destroy_datapaths_and_ports(&data->ls_datapaths, &data->lr_datapaths,
> + &data->ls_ports, &data->lr_ports,
> + &data->lr_list);
> destroy_debug_config();
> }
>
> @@ -16336,20 +16434,22 @@ ovnnb_db_run(struct northd_input *input_data,
>
> init_debug_config(nb);
>
> - build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list);
> - build_lbs(input_data, &data->datapaths, &data->lbs, &data->lb_groups);
> + build_datapaths(input_data, ovnsb_txn, &data->ls_datapaths,
> + &data->lr_datapaths, &data->lr_list);
> + build_lbs(input_data, &data->ls_datapaths, &data->lr_datapaths,
> &data->lbs,
> + &data->lb_groups);
> build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name,
> - sbrec_chassis_by_hostname, &data->datapaths,
> - &data->ls_ports, &data->lr_ports);
> - build_lb_port_related_data(&data->datapaths, &data->ls_ports,
> + sbrec_chassis_by_hostname, &data->ls_datapaths,
> + &data->lr_datapaths, &data->ls_ports, &data->lr_ports);
> + build_lb_port_related_data(&data->lr_datapaths, &data->ls_ports,
> &data->lbs, &data->lb_groups, input_data,
> ovnsb_txn);
> build_lb_count_dps(&data->lbs);
> - build_ipam(&data->datapaths, &data->ls_ports);
> + build_ipam(&data->ls_datapaths, &data->ls_ports);
> build_port_group_lswitches(input_data, &data->port_groups,
> &data->ls_ports);
> build_lrouter_groups(&data->lr_ports, &data->lr_list);
> - build_ip_mcast(input_data, ovnsb_txn, &data->datapaths);
> + build_ip_mcast(input_data, ovnsb_txn, &data->ls_datapaths);
> build_meter_groups(input_data, &data->meter_groups);
> build_static_mac_binding_table(input_data, ovnsb_txn, &data->lr_ports);
> stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
> @@ -16357,14 +16457,14 @@ ovnnb_db_run(struct northd_input *input_data,
> ovn_update_ipv6_options(&data->lr_ports);
> ovn_update_ipv6_prefix(&data->lr_ports);
>
> - sync_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs);
> + sync_lbs(input_data, ovnsb_txn, &data->ls_datapaths, &data->lbs);
> sync_port_groups(input_data, ovnsb_txn, &data->port_groups);
> sync_meters(input_data, ovnsb_txn, &data->meter_groups);
> sync_mirrors(input_data, ovnsb_txn);
> - sync_dns_entries(input_data, ovnsb_txn, &data->datapaths);
> + sync_dns_entries(input_data, ovnsb_txn, &data->ls_datapaths);
> sync_template_vars(input_data, ovnsb_txn);
>
> - cleanup_stale_fdb_entries(input_data, &data->datapaths);
> + cleanup_stale_fdb_entries(input_data, &data->ls_datapaths);
> stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
>
> /* Set up SB_Global (depends on chassis features). */
> diff --git a/northd/northd.h b/northd/northd.h
> index cdb521d46566..cfd36e32c9a7 100644
> --- a/northd/northd.h
> +++ b/northd/northd.h
> @@ -76,7 +76,8 @@ struct chassis_features {
>
> struct northd_data {
> /* Global state for 'en-northd'. */
> - struct hmap datapaths;
> + struct hmap ls_datapaths;
> + struct hmap lr_datapaths;
> struct hmap ls_ports;
> struct hmap lr_ports;
> struct hmap port_groups;
> @@ -102,7 +103,8 @@ struct lflow_input {
> /* Indexes */
> struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp;
>
> - const struct hmap *datapaths;
> + const struct hmap *ls_datapaths;
> + const struct hmap *lr_datapaths;
> const struct hmap *ls_ports;
> const struct hmap *lr_ports;
> const struct hmap *port_groups;
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev