> On Wed, Aug 7, 2024 at 2:36 PM Han Zhou <[email protected]> wrote: > > > > On Wed, Aug 7, 2024 at 10:29 AM Lorenzo Bianconi > > <[email protected]> wrote: > > > > > > > On Tue, Aug 6, 2024 at 9:53 AM Lorenzo Bianconi > > > > <[email protected]> wrote: > > > > > > > > > > [...] > > > > > > > -void > > > > > > > -bfd_cleanup_connections(const struct nbrec_bfd_table > > > > > > > *nbrec_bfd_table, > > > > > > > - struct hmap *bfd_map) > > > > > > > +static bool > > > > > > > +bfd_is_port_running(const struct hmap *bfd_map, const char *port) > > > > > > > { > > > > > > > - const struct nbrec_bfd *nb_bt; > > > > > > > struct bfd_entry *bfd_e; > > > > > > > - > > > > > > > - NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) { > > > > > > > - bfd_e = bfd_port_lookup(bfd_map, nb_bt->logical_port, > > > > > > > nb_bt->dst_ip); > > > > > > > - if (!bfd_e) { > > > > > > > - continue; > > > > > > > - } > > > > > > > - > > > > > > > - if (!bfd_e->ref && strcmp(nb_bt->status, "admin_down")) { > > > > > > > - /* no user for this bfd connection */ > > > > > > > - nbrec_bfd_set_status(nb_bt, "admin_down"); > > > > > > > + HMAP_FOR_EACH (bfd_e, hmap_node, bfd_map) { > > > > > > > > > > > > I like the idea of checking the existence of the bfd entry to decide > > > > > > if a port has bfd instead of relying on the has_bfd status. > > > > > > However, I > > > > > > have performance concerns for this loop. The bfd_port_lookup() > > > > > > searches by hashing both logical_port and dst_ip, but here for > > > > > > logical_port it just iterates all bfd entries, which looks > > > > > > unreasonable. It may be better to add a hindex for logical_port. > > > > > > > > > > Hi Han, > > > > > > > > > > I did not get what you mean here, can you please provide more details? > > > > > Do you mean another hmap to link the logical_port name to the > > > > > bfd_entry? > > > > > > > > > > > > > The goal is to avoid this O(n) iteration looking for a given > > > > logical_port. Since multiple bfd entries can have the same > > > > logical_port name, it would be better to use the struct hindex instead > > > > of struct hmap to link logical_port name to the bfd_entry. > > > > > > ack, fine. Since in this case we just need to know if the logical_port is > > > used > > > in at least one bfd_entry, I guess a simap to count number of bfd_entry > > > for a > > > given logical port is enough, what do you think? > > > > > > > Yes, or it can be just a sset, if we only care about the existence (0 > > or >0) but not the actual count. > > > > To unblock the ECMP series, I am ok to merge it as is for now, and > optimize with sset later, preferably before the release. > > Acked-by: Han Zhou <[email protected]>
I worked on the requested changes, you can find the patch here [0], but if you prefer we can apply the v11 and I can post just a follow-up patch. Up to you. Regards, Lorenzo [0] https://github.com/LorenzoBianconi/ovn/commit/27d160598b4180427c26a0a25768c125b1801392 > > > > > > > > > > > > > > > > > > + if (!strcmp(bfd_e->logical_port, port)) { > > > > > > > + return true; > > > > > > > } > > > > > > > } > > > > > > > - > > > > > > > - HMAP_FOR_EACH_POP (bfd_e, hmap_node, bfd_map) { > > > > > > > - free(bfd_e); > > > > > > > - } > > > > > > > + return false; > > > > > > > } > > > > > > > > > > > > > > + > > > > > > > #define BFD_DEF_MINTX 1000 /* 1s */ > > > > > > > #define BFD_DEF_MINRX 1000 /* 1s */ > > > > > > > #define BFD_DEF_DETECT_MULT 5 > > > > > > > @@ -9809,51 +9835,88 @@ static int bfd_get_unused_port(unsigned > > > > > > > long *bfd_src_ports) > > > > > > > return port + BFD_UDP_SRC_PORT_START; > > > > > > > } > > > > > > > > > > > > > > -void > > > > > > > -build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn, > > > > > > > - const struct nbrec_bfd_table *nbrec_bfd_table, > > > > > > > - const struct sbrec_bfd_table *sbrec_bfd_table, > > > > > > > - const struct hmap *lr_ports, struct hmap > > > > > > > *bfd_connections) > > > > > > > +static char * > > > > > > > +bfd_get_connection_status(const struct nbrec_bfd *nb_bt, > > > > > > > + const struct hmap *rp_bfd_connections, > > > > > > > + const struct hmap *sr_bfd_connections) > > > > > > > { > > > > > > > - struct hmap sb_only = HMAP_INITIALIZER(&sb_only); > > > > > > > - const struct sbrec_bfd *sb_bt; > > > > > > > - unsigned long *bfd_src_ports; > > > > > > > - struct bfd_entry *bfd_e; > > > > > > > - uint32_t hash; > > > > > > > + struct bfd_entry *bfd_rp, *bfd_sr; > > > > > > > > > > > > > > - bfd_src_ports = bitmap_allocate(BFD_UDP_SRC_PORT_LEN); > > > > > > > + bfd_rp = bfd_port_lookup(rp_bfd_connections, > > > > > > > nb_bt->logical_port, > > > > > > > + nb_bt->dst_ip); > > > > > > > + if (!bfd_rp) { > > > > > > > + bfd_sr = bfd_port_lookup(sr_bfd_connections, > > > > > > > nb_bt->logical_port, > > > > > > > + nb_bt->dst_ip); > > > > > > > + if (!bfd_sr) { > > > > > > > + return "admin_down"; > > > > > > > + } > > > > > > > + } > > > > > > > > > > > > > > - SBREC_BFD_TABLE_FOR_EACH (sb_bt, sbrec_bfd_table) { > > > > > > > - bfd_e = xmalloc(sizeof *bfd_e); > > > > > > > - bfd_e->sb_bt = sb_bt; > > > > > > > - hash = hash_string(sb_bt->dst_ip, 0); > > > > > > > - hash = hash_string(sb_bt->logical_port, hash); > > > > > > > - hmap_insert(&sb_only, &bfd_e->hmap_node, hash); > > > > > > > - bitmap_set1(bfd_src_ports, sb_bt->src_port - > > > > > > > BFD_UDP_SRC_PORT_START); > > > > > > > + return bfd_rp ? bfd_rp->status : bfd_sr->status; > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +bfd_table_sync(struct ovsdb_idl_txn *ovnsb_txn, > > > > > > > + const struct nbrec_bfd_table *nbrec_bfd_table, > > > > > > > + const struct hmap *lr_ports, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > + const struct hmap *rp_bfd_connections, > > > > > > > + const struct hmap *sr_bfd_connections, > > > > > > > + struct hmap *sync_bfd_connections) > > > > > > > +{ > > > > > > > + if (!ovnsb_txn) { > > > > > > > + return; > > > > > > > + } > > > > > > > + > > > > > > > + unsigned long *bfd_src_ports = > > > > > > > bitmap_allocate(BFD_UDP_SRC_PORT_LEN); > > > > > > > + > > > > > > > + struct bfd_entry *bfd_e; > > > > > > > + HMAP_FOR_EACH (bfd_e, hmap_node, bfd_connections) { > > > > > > > + struct bfd_entry *e = > > > > > > > bfd_alloc_entry(sync_bfd_connections, > > > > > > > + > > > > > > > bfd_e->logical_port, > > > > > > > + bfd_e->dst_ip, > > > > > > > bfd_e->status); > > > > > > > > > > > > It looks like we are blindly allocating a new entry for each entry > > > > > > in > > > > > > bfd_connections without checking if it already exists. Did I > > > > > > misunderstand? > > > > > > > > > > So far sync_bfd_connections always start from scratch and it is 1:1 > > > > > with > > > > > bfd_connections, so I guess an entry can't already exist. But I > > > > > prefer to be > > > > > more generic and check it. I will fix it. > > > > > > > > > > > > > What I meant was that now the sync_bfd_connections table is persistent > > > > across I-P engine runs (I didn't see it get destroyed across > > > > iterations but correct me if I am wrong), the above code just > > > > allocates entries again and again every iteration without removing the > > > > old ones. For simplicity we may just destroy old entries at the > > > > beginning of this function because now we always do recompute. In the > > > > future it may be optimized to incrementally consolidate new/old > > > > entries. Does this make sense? > > > > > > > > > sync_bfd_connections is destroyed at the beginning of en_bfd_sync_run() > > > so I > > > guess we already have what you are suggesting, right? Anyway we can still > > > use > > > bfd_port_lookup() to check if an entry has been already allocated. What > > > do you > > > prefer? > > > > > > > Oh, yes. Sorry I missed that. If it is recreated then there is no > > point to check the existence again. > > > > Thanks, > > Han > > > > > Regards, > > > Lorenzo > > > > > > > > > > > Thanks, > > > > Han > > > > > > > > > Regards, > > > > > Lorenzo > > > > > > > > > > > > > > > > > Thanks, > > > > > > Han > > > > > > > > > > > > > + e->nb_bt = bfd_e->nb_bt; > > > > > > > + e->sb_bt = bfd_e->sb_bt; > > > > > > > + e->stale = true; > > > > > > > + /* we need to check if this entry is even in the BFD nb > > > > > > > db table */ > > > > > > > + if (bfd_e->sb_bt) { > > > > > > > + bitmap_set1(bfd_src_ports, > > > > > > > + bfd_e->sb_bt->src_port - > > > > > > > BFD_UDP_SRC_PORT_START); > > > > > > > + } > > > > > > > } > > > > > > > > > > > > > > const struct nbrec_bfd *nb_bt; > > > > > > > NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) { > > > > > > > - if (!nb_bt->status) { > > > > > > > - /* default state is admin_down */ > > > > > > > - nbrec_bfd_set_status(nb_bt, "admin_down"); > > > > > > > + bfd_e = bfd_port_lookup(sync_bfd_connections, > > > > > > > nb_bt->logical_port, > > > > > > > + nb_bt->dst_ip); > > > > > > > + if (!bfd_e) { > > > > > > > + continue; > > > > > > > } > > > > > > > > > > > > > > struct ovn_port *op = ovn_port_find(lr_ports, > > > > > > > nb_bt->logical_port); > > > > > > > - bfd_e = bfd_port_lookup(&sb_only, nb_bt->logical_port, > > > > > > > nb_bt->dst_ip); > > > > > > > - if (!bfd_e) { > > > > > > > + if (!op || !op->sb) { > > > > > > > + /* skip not bounded ports */ > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + nbrec_bfd_set_status(nb_bt, > > > > > > > + bfd_get_connection_status(nb_bt, > > > > > > > + > > > > > > > rp_bfd_connections, > > > > > > > + > > > > > > > sr_bfd_connections)); > > > > > > > + if (!bfd_e->sb_bt) { > > > > > > > int udp_src = bfd_get_unused_port(bfd_src_ports); > > > > > > > if (udp_src < 0) { > > > > > > > continue; > > > > > > > } > > > > > > > > > > > > > > - sb_bt = sbrec_bfd_insert(ovnsb_txn); > > > > > > > + /* Add entry to bfd sb table. */ > > > > > > > + const struct sbrec_bfd *sb_bt = > > > > > > > sbrec_bfd_insert(ovnsb_txn); > > > > > > > sbrec_bfd_set_logical_port(sb_bt, > > > > > > > nb_bt->logical_port); > > > > > > > sbrec_bfd_set_dst_ip(sb_bt, nb_bt->dst_ip); > > > > > > > sbrec_bfd_set_disc(sb_bt, 1 + random_uint32()); > > > > > > > sbrec_bfd_set_src_port(sb_bt, udp_src); > > > > > > > sbrec_bfd_set_status(sb_bt, nb_bt->status); > > > > > > > - if (op && op->sb && op->sb->chassis) { > > > > > > > + if (op->sb->chassis) { > > > > > > > sbrec_bfd_set_chassis_name(sb_bt, > > > > > > > op->sb->chassis->name); > > > > > > > } > > > > > > > > > > > > > > @@ -9873,39 +9936,61 @@ build_bfd_table(struct ovsdb_idl_txn > > > > > > > *ovnsb_txn, > > > > > > > nbrec_bfd_set_status(nb_bt, > > > > > > > bfd_e->sb_bt->status); > > > > > > > } > > > > > > > } > > > > > > > + > > > > > > > build_bfd_update_sb_conf(nb_bt, bfd_e->sb_bt); > > > > > > > - if (op && op->sb && op->sb->chassis && > > > > > > > - strcmp(op->sb->chassis->name, > > > > > > > bfd_e->sb_bt->chassis_name)) { > > > > > > > + if (op->sb->chassis && !strcmp(op->sb->chassis->name, > > > > > > > + > > > > > > > bfd_e->sb_bt->chassis_name)) { > > > > > > > sbrec_bfd_set_chassis_name(bfd_e->sb_bt, > > > > > > > > > > > > > > op->sb->chassis->name); > > > > > > > } > > > > > > > - > > > > > > > - hmap_remove(&sb_only, &bfd_e->hmap_node); > > > > > > > - bfd_e->ref = false; > > > > > > > - hash = hash_string(bfd_e->sb_bt->dst_ip, 0); > > > > > > > - hash = hash_string(bfd_e->sb_bt->logical_port, hash); > > > > > > > - hmap_insert(bfd_connections, &bfd_e->hmap_node, > > > > > > > hash); > > > > > > > } > > > > > > > > > > > > > > - if (op) { > > > > > > > - op->has_bfd = true; > > > > > > > - } > > > > > > > + bfd_e->stale = false; > > > > > > > } > > > > > > > > > > > > > > - HMAP_FOR_EACH_POP (bfd_e, hmap_node, &sb_only) { > > > > > > > - struct ovn_port *op = ovn_port_find(lr_ports, > > > > > > > - > > > > > > > bfd_e->sb_bt->logical_port); > > > > > > > - if (op) { > > > > > > > - op->has_bfd = false; > > > > > > > + HMAP_FOR_EACH_SAFE (bfd_e, hmap_node, sync_bfd_connections) { > > > > > > > + if (bfd_e->stale) { > > > > > > > + hmap_remove(sync_bfd_connections, &bfd_e->hmap_node); > > > > > > > + sbrec_bfd_delete(bfd_e->sb_bt); > > > > > > > + bfd_erase_entry(bfd_e); > > > > > > > } > > > > > > > - sbrec_bfd_delete(bfd_e->sb_bt); > > > > > > > - free(bfd_e); > > > > > > > } > > > > > > > - hmap_destroy(&sb_only); > > > > > > > > > > > > > > bitmap_free(bfd_src_ports); > > > > > > > } > > > > > > > > > > > > > > +void > > > > > > > +build_bfd_map(const struct nbrec_bfd_table *nbrec_bfd_table, > > > > > > > + const struct sbrec_bfd_table *sbrec_bfd_table, > > > > > > > + struct hmap *bfd_connections) > > > > > > > +{ > > > > > > > + struct bfd_entry *bfd_e; > > > > > > > + > > > > > > > + /* align bfd_map to sb db */ > > > > > > > + const struct sbrec_bfd *sb_bt; > > > > > > > + SBREC_BFD_TABLE_FOR_EACH (sb_bt, sbrec_bfd_table) { > > > > > > > + bfd_e = bfd_port_lookup(bfd_connections, > > > > > > > sb_bt->logical_port, > > > > > > > + sb_bt->dst_ip); > > > > > > > + if (!bfd_e) { > > > > > > > + bfd_e = bfd_alloc_entry(bfd_connections, > > > > > > > sb_bt->logical_port, > > > > > > > + sb_bt->dst_ip, > > > > > > > sb_bt->status); > > > > > > > + } > > > > > > > + bfd_e->sb_bt = sb_bt; > > > > > > > + } > > > > > > > + > > > > > > > + const struct nbrec_bfd *nb_bt; > > > > > > > + NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) { > > > > > > > + bfd_e = bfd_port_lookup(bfd_connections, > > > > > > > nb_bt->logical_port, > > > > > > > + nb_bt->dst_ip); > > > > > > > + if (!bfd_e) { > > > > > > > + /* brand new entry. */ > > > > > > > + bfd_e = bfd_alloc_entry(bfd_connections, > > > > > > > nb_bt->logical_port, > > > > > > > + nb_bt->dst_ip, "admin_down"); > > > > > > > + } > > > > > > > + bfd_e->nb_bt = nb_bt; > > > > > > > + } > > > > > > > +} > > > > > > > + > > > > > > > /* Returns a string of the IP address of the router port 'op' > > > > > > > that > > > > > > > * overlaps with 'ip_s". If one is not found, returns NULL. > > > > > > > * > > > > > > > @@ -9941,17 +10026,13 @@ > > > > > > > get_outport_for_routing_policy_nexthop(struct ovn_datapath *od, > > > > > > > return NULL; > > > > > > > } > > > > > > > > > > > > > > -static struct ovs_mutex bfd_lock = OVS_MUTEX_INITIALIZER; > > > > > > > - > > > > > > > -static bool check_bfd_state( > > > > > > > - const struct nbrec_logical_router_policy *rule, > > > > > > > - const struct hmap *bfd_connections, > > > > > > > - struct ovn_port *out_port, > > > > > > > - const char *nexthop) > > > > > > > +static bool check_bfd_state(const struct > > > > > > > nbrec_logical_router_policy *rule, > > > > > > > + struct ovn_port *out_port, const > > > > > > > char *nexthop, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > + struct hmap *bfd_active_connections) > > > > > > > { > > > > > > > struct in6_addr nexthop_v6; > > > > > > > bool is_nexthop_v6 = ipv6_parse(nexthop, &nexthop_v6); > > > > > > > - bool ret = true; > > > > > > > > > > > > > > for (size_t i = 0; i < rule->n_bfd_sessions; i++) { > > > > > > > /* Check if there is a BFD session associated to the > > > > > > > reroute > > > > > > > @@ -9976,39 +10057,48 @@ static bool check_bfd_state( > > > > > > > struct bfd_entry *bfd_e = > > > > > > > bfd_port_lookup(bfd_connections, > > > > > > > > > > > > > > nb_bt->logical_port, > > > > > > > nb_bt->dst_ip); > > > > > > > - ovs_mutex_lock(&bfd_lock); > > > > > > > - if (bfd_e) { > > > > > > > - bfd_e->ref = true; > > > > > > > + if (!bfd_e) { > > > > > > > + continue; > > > > > > > } > > > > > > > > > > > > > > - if (!strcmp(nb_bt->status, "admin_down")) { > > > > > > > - nbrec_bfd_set_status(nb_bt, "down"); > > > > > > > + /* This route policy is linked to an active bfd session. > > > > > > > */ > > > > > > > + struct bfd_entry *bfd_rp = > > > > > > > bfd_port_lookup(bfd_active_connections, > > > > > > > + > > > > > > > nb_bt->logical_port, > > > > > > > + > > > > > > > nb_bt->dst_ip); > > > > > > > + if (!bfd_rp) { > > > > > > > + bfd_rp = bfd_alloc_entry(bfd_active_connections, > > > > > > > + nb_bt->logical_port, > > > > > > > nb_bt->dst_ip, > > > > > > > + bfd_e->status); > > > > > > > } > > > > > > > > > > > > > > - ret = strcmp(nb_bt->status, "down"); > > > > > > > - ovs_mutex_unlock(&bfd_lock); > > > > > > > - break; > > > > > > > + if (!strcmp(bfd_e->status, "admin_down")) { > > > > > > > + bfd_set_status(bfd_rp, "down"); > > > > > > > + } > > > > > > > + > > > > > > > + return strcmp(bfd_rp->status, "down"); > > > > > > > } > > > > > > > > > > > > > > - return ret; > > > > > > > + return true; > > > > > > > } > > > > > > > > > > > > > > static void > > > > > > > build_routing_policy_flow(struct lflow_table *lflows, struct > > > > > > > ovn_datapath *od, > > > > > > > - const struct hmap *lr_ports, > > > > > > > - const struct > > > > > > > nbrec_logical_router_policy *rule, > > > > > > > - const struct hmap *bfd_connections, > > > > > > > + const struct hmap *lr_ports, struct > > > > > > > route_policy *rp, > > > > > > > const struct ovsdb_idl_row *stage_hint, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > + const struct nbrec_logical_router_policy *rule = rp->rule; > > > > > > > struct ds match = DS_EMPTY_INITIALIZER; > > > > > > > struct ds actions = DS_EMPTY_INITIALIZER; > > > > > > > > > > > > > > if (!strcmp(rule->action, "reroute")) { > > > > > > > ovs_assert(rule->n_nexthops <= 1); > > > > > > > > > > > > > > - char *nexthop = > > > > > > > - (rule->n_nexthops == 1 ? rule->nexthops[0] : > > > > > > > rule->nexthop); > > > > > > > + if (!rp->n_valid_nexthops) { > > > > > > > + return; > > > > > > > + } > > > > > > > + > > > > > > > + char *nexthop = rp->valid_nexthops[0]; > > > > > > > struct ovn_port *out_port = > > > > > > > get_outport_for_routing_policy_nexthop( > > > > > > > od, lr_ports, rule->priority, nexthop); > > > > > > > if (!out_port) { > > > > > > > @@ -10024,10 +10114,6 @@ build_routing_policy_flow(struct > > > > > > > lflow_table *lflows, struct ovn_datapath *od, > > > > > > > return; > > > > > > > } > > > > > > > > > > > > > > - if (!check_bfd_state(rule, bfd_connections, out_port, > > > > > > > nexthop)) { > > > > > > > - return; > > > > > > > - } > > > > > > > - > > > > > > > uint32_t pkt_mark = smap_get_uint(&rule->options, > > > > > > > "pkt_mark", 0); > > > > > > > if (pkt_mark) { > > > > > > > ds_put_format(&actions, "pkt.mark = %u; ", pkt_mark); > > > > > > > @@ -10070,19 +10156,18 @@ static void > > > > > > > build_ecmp_routing_policy_flows(struct lflow_table *lflows, > > > > > > > struct ovn_datapath *od, > > > > > > > const struct hmap *lr_ports, > > > > > > > - const struct > > > > > > > nbrec_logical_router_policy *rule, > > > > > > > - const struct hmap > > > > > > > *bfd_connections, > > > > > > > + struct route_policy *rp, > > > > > > > uint16_t ecmp_group_id, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > - ovs_assert(rule->n_nexthops > 1); > > > > > > > - > > > > > > > bool nexthops_is_ipv4 = true; > > > > > > > + const struct nbrec_logical_router_policy *rule = rp->rule; > > > > > > > + ovs_assert(rule->n_nexthops > 1); > > > > > > > > > > > > > > /* Check that all the nexthops belong to the same addr > > > > > > > family before > > > > > > > * adding logical flows. */ > > > > > > > - for (uint16_t i = 0; i < rule->n_nexthops; i++) { > > > > > > > - bool is_ipv4 = strchr(rule->nexthops[i], '.') ? true : > > > > > > > false; > > > > > > > + for (uint16_t i = 0; i < rp->n_valid_nexthops; i++) { > > > > > > > + bool is_ipv4 = strchr(rp->valid_nexthops[i], '.') ? true > > > > > > > : false; > > > > > > > > > > > > > > if (i == 0) { > > > > > > > nexthops_is_ipv4 = is_ipv4; > > > > > > > @@ -10093,7 +10178,7 @@ build_ecmp_routing_policy_flows(struct > > > > > > > lflow_table *lflows, > > > > > > > VLOG_WARN_RL(&rl, "nexthop [%s] of the router policy > > > > > > > with " > > > > > > > "the match [%s] do not belong to the > > > > > > > same address " > > > > > > > "family as other next hops", > > > > > > > - rule->nexthops[i], rule->match); > > > > > > > + rp->valid_nexthops[i], rule->match); > > > > > > > return; > > > > > > > } > > > > > > > } > > > > > > > @@ -10101,40 +10186,30 @@ build_ecmp_routing_policy_flows(struct > > > > > > > lflow_table *lflows, > > > > > > > struct ds match = DS_EMPTY_INITIALIZER; > > > > > > > struct ds actions = DS_EMPTY_INITIALIZER; > > > > > > > > > > > > > > - size_t *valid_nexthops = xcalloc(rule->n_nexthops, sizeof > > > > > > > *valid_nexthops); > > > > > > > - size_t n_valid_nexthops = 0; > > > > > > > - > > > > > > > - for (size_t i = 0; i < rule->n_nexthops; i++) { > > > > > > > + for (size_t i = 0; i < rp->n_valid_nexthops; i++) { > > > > > > > struct ovn_port *out_port = > > > > > > > get_outport_for_routing_policy_nexthop( > > > > > > > - od, lr_ports, rule->priority, rule->nexthops[i]); > > > > > > > + od, lr_ports, rule->priority, > > > > > > > rp->valid_nexthops[i]); > > > > > > > if (!out_port) { > > > > > > > goto cleanup; > > > > > > > } > > > > > > > > > > > > > > const char *lrp_addr_s = > > > > > > > - find_lrp_member_ip(out_port, rule->nexthops[i]); > > > > > > > + find_lrp_member_ip(out_port, rp->valid_nexthops[i]); > > > > > > > if (!lrp_addr_s) { > > > > > > > static struct vlog_rate_limit rl = > > > > > > > VLOG_RATE_LIMIT_INIT(5, 1); > > > > > > > VLOG_WARN_RL(&rl, "lrp_addr not found for routing > > > > > > > policy " > > > > > > > " priority %"PRId64" nexthop %s", > > > > > > > - rule->priority, rule->nexthops[i]); > > > > > > > + rule->priority, > > > > > > > rp->valid_nexthops[i]); > > > > > > > goto cleanup; > > > > > > > } > > > > > > > > > > > > > > - if (!check_bfd_state(rule, bfd_connections, out_port, > > > > > > > - rule->nexthops[i])) { > > > > > > > - continue; > > > > > > > - } > > > > > > > - > > > > > > > - valid_nexthops[n_valid_nexthops++] = i + 1; > > > > > > > - > > > > > > > ds_clear(&actions); > > > > > > > uint32_t pkt_mark = smap_get_uint(&rule->options, > > > > > > > "pkt_mark", 0); > > > > > > > if (pkt_mark) { > > > > > > > ds_put_format(&actions, "pkt.mark = %u; ", pkt_mark); > > > > > > > } > > > > > > > > > > > > > > - bool is_ipv4 = strchr(rule->nexthops[i], '.') ? true : > > > > > > > false; > > > > > > > + bool is_ipv4 = strchr(rp->valid_nexthops[i], '.') ? true > > > > > > > : false; > > > > > > > > > > > > > > ds_put_format(&actions, "%s = %s; " > > > > > > > "%s = %s; " > > > > > > > @@ -10143,7 +10218,7 @@ build_ecmp_routing_policy_flows(struct > > > > > > > lflow_table *lflows, > > > > > > > "flags.loopback = 1; " > > > > > > > "next;", > > > > > > > is_ipv4 ? REG_NEXT_HOP_IPV4 : > > > > > > > REG_NEXT_HOP_IPV6, > > > > > > > - rule->nexthops[i], > > > > > > > + rp->valid_nexthops[i], > > > > > > > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > > > > > > lrp_addr_s, > > > > > > > out_port->lrp_networks.ea_s, > > > > > > > @@ -10159,37 +10234,30 @@ build_ecmp_routing_policy_flows(struct > > > > > > > lflow_table *lflows, > > > > > > > lflow_ref); > > > > > > > } > > > > > > > > > > > > > > - if (!n_valid_nexthops) { > > > > > > > - goto cleanup; > > > > > > > - } > > > > > > > - > > > > > > > ds_clear(&actions); > > > > > > > - if (n_valid_nexthops > 1) { > > > > > > > + if (rp->n_valid_nexthops > 1) { > > > > > > > ds_put_format(&actions, "%s = %"PRIu16 > > > > > > > "; %s = select(", REG_ECMP_GROUP_ID, > > > > > > > ecmp_group_id, > > > > > > > REG_ECMP_MEMBER_ID); > > > > > > > > > > > > > > - for (size_t i = 0; i < n_valid_nexthops; i++) { > > > > > > > + for (size_t i = 0; i < rp->n_valid_nexthops; i++) { > > > > > > > if (i > 0) { > > > > > > > ds_put_cstr(&actions, ", "); > > > > > > > } > > > > > > > > > > > > > > - ds_put_format(&actions, "%"PRIuSIZE, > > > > > > > valid_nexthops[i]); > > > > > > > + ds_put_format(&actions, "%"PRIuSIZE, i + 1); > > > > > > > } > > > > > > > ds_put_cstr(&actions, ");"); > > > > > > > } else { > > > > > > > ds_put_format(&actions, "%s = %"PRIu16 > > > > > > > - "; %s = %"PRIuSIZE"; next;", > > > > > > > REG_ECMP_GROUP_ID, > > > > > > > - ecmp_group_id, REG_ECMP_MEMBER_ID, > > > > > > > - valid_nexthops[0]); > > > > > > > + "; %s = 1; next;", REG_ECMP_GROUP_ID, > > > > > > > + ecmp_group_id, REG_ECMP_MEMBER_ID); > > > > > > > } > > > > > > > ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, > > > > > > > rule->priority, rule->match, > > > > > > > ds_cstr(&actions), &rule->header_, > > > > > > > lflow_ref); > > > > > > > - > > > > > > > cleanup: > > > > > > > - free(valid_nexthops); > > > > > > > ds_destroy(&match); > > > > > > > ds_destroy(&actions); > > > > > > > } > > > > > > > @@ -10214,7 +10282,7 @@ route_table_add(struct simap > > > > > > > *route_tables, const char *route_table_name) > > > > > > > return rtb_id; > > > > > > > } > > > > > > > > > > > > > > -static uint32_t > > > > > > > +uint32_t > > > > > > > get_route_table_id(struct simap *route_tables, const char > > > > > > > *route_table_name) > > > > > > > { > > > > > > > if (!route_table_name || !route_table_name[0]) { > > > > > > > @@ -10255,18 +10323,6 @@ build_route_table_lflow(struct > > > > > > > ovn_datapath *od, struct lflow_table *lflows, > > > > > > > ds_destroy(&actions); > > > > > > > } > > > > > > > > > > > > > > -struct parsed_route { > > > > > > > - struct ovs_list list_node; > > > > > > > - struct in6_addr prefix; > > > > > > > - unsigned int plen; > > > > > > > - bool is_src_route; > > > > > > > - uint32_t route_table_id; > > > > > > > - uint32_t hash; > > > > > > > - const struct nbrec_logical_router_static_route *route; > > > > > > > - bool ecmp_symmetric_reply; > > > > > > > - bool is_discard_route; > > > > > > > -}; > > > > > > > - > > > > > > > static uint32_t > > > > > > > route_hash(struct parsed_route *route) > > > > > > > { > > > > > > > @@ -10281,11 +10337,53 @@ find_static_route_outport(struct > > > > > > > ovn_datapath *od, const struct hmap *lr_ports, > > > > > > > > > > > > > > /* Parse and validate the route. Return the parsed route if > > > > > > > successful. > > > > > > > * Otherwise return NULL. */ > > > > > > > + > > > > > > > static struct parsed_route * > > > > > > > +parsed_route_lookup(struct hmap *routes, size_t hash, > > > > > > > + struct parsed_route *new_pr) > > > > > > > +{ > > > > > > > + struct parsed_route *pr; > > > > > > > + HMAP_FOR_EACH_WITH_HASH (pr, key_node, hash, routes) { > > > > > > > + if (pr->plen != new_pr->plen) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (memcmp(&pr->prefix, &new_pr->prefix, sizeof(struct > > > > > > > in6_addr))) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (pr->is_src_route != new_pr->is_src_route) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (pr->route_table_id != new_pr->route_table_id) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (pr->route != new_pr->route) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (pr->ecmp_symmetric_reply != > > > > > > > new_pr->ecmp_symmetric_reply) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (pr->is_discard_route != new_pr->is_discard_route) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + return pr; > > > > > > > + } > > > > > > > + > > > > > > > + return NULL; > > > > > > > +} > > > > > > > + > > > > > > > +static void > > > > > > > parsed_routes_add(struct ovn_datapath *od, const struct hmap > > > > > > > *lr_ports, > > > > > > > - struct ovs_list *routes, struct simap > > > > > > > *route_tables, > > > > > > > const struct nbrec_logical_router_static_route > > > > > > > *route, > > > > > > > - const struct hmap *bfd_connections) > > > > > > > + struct hmap *bfd_connections, > > > > > > > + struct hmap *routes, struct simap > > > > > > > *route_tables, > > > > > > > + struct hmap *bfd_active_connections) > > > > > > > { > > > > > > > /* Verify that the next hop is an IP address with an > > > > > > > all-ones mask. */ > > > > > > > struct in6_addr nexthop; > > > > > > > @@ -10298,7 +10396,7 @@ parsed_routes_add(struct ovn_datapath > > > > > > > *od, const struct hmap *lr_ports, > > > > > > > VLOG_WARN_RL(&rl, "bad 'nexthop' %s in static route " > > > > > > > UUID_FMT, route->nexthop, > > > > > > > UUID_ARGS(&route->header_.uuid)); > > > > > > > - return NULL; > > > > > > > + return; > > > > > > > } > > > > > > > if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) || > > > > > > > (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) { > > > > > > > @@ -10306,7 +10404,7 @@ parsed_routes_add(struct ovn_datapath > > > > > > > *od, const struct hmap *lr_ports, > > > > > > > VLOG_WARN_RL(&rl, "bad next hop mask %s in static > > > > > > > route " > > > > > > > UUID_FMT, route->nexthop, > > > > > > > UUID_ARGS(&route->header_.uuid)); > > > > > > > - return NULL; > > > > > > > + return; > > > > > > > } > > > > > > > } > > > > > > > > > > > > > > @@ -10317,7 +10415,7 @@ parsed_routes_add(struct ovn_datapath > > > > > > > *od, const struct hmap *lr_ports, > > > > > > > VLOG_WARN_RL(&rl, "bad 'ip_prefix' %s in static route " > > > > > > > UUID_FMT, route->ip_prefix, > > > > > > > UUID_ARGS(&route->header_.uuid)); > > > > > > > - return NULL; > > > > > > > + return; > > > > > > > } > > > > > > > > > > > > > > /* Verify that ip_prefix and nexthop have same address > > > > > > > familiy. */ > > > > > > > @@ -10328,7 +10426,7 @@ parsed_routes_add(struct ovn_datapath > > > > > > > *od, const struct hmap *lr_ports, > > > > > > > " %s and 'nexthop' %s in static route > > > > > > > "UUID_FMT, > > > > > > > route->ip_prefix, route->nexthop, > > > > > > > UUID_ARGS(&route->header_.uuid)); > > > > > > > - return NULL; > > > > > > > + return; > > > > > > > } > > > > > > > } > > > > > > > > > > > > > > @@ -10337,52 +10435,88 @@ parsed_routes_add(struct ovn_datapath > > > > > > > *od, const struct hmap *lr_ports, > > > > > > > !find_static_route_outport(od, lr_ports, route, > > > > > > > IN6_IS_ADDR_V4MAPPED(&prefix), > > > > > > > NULL, NULL)) { > > > > > > > - return NULL; > > > > > > > + return; > > > > > > > } > > > > > > > > > > > > > > const struct nbrec_bfd *nb_bt = route->bfd; > > > > > > > if (nb_bt && !strcmp(nb_bt->dst_ip, route->nexthop)) { > > > > > > > - struct bfd_entry *bfd_e; > > > > > > > + struct bfd_entry *bfd_e = > > > > > > > bfd_port_lookup(bfd_connections, > > > > > > > + > > > > > > > nb_bt->logical_port, > > > > > > > + nb_bt->dst_ip); > > > > > > > + if (!bfd_e) { > > > > > > > + return; > > > > > > > + } > > > > > > > > > > > > > > - bfd_e = bfd_port_lookup(bfd_connections, > > > > > > > nb_bt->logical_port, > > > > > > > - nb_bt->dst_ip); > > > > > > > - ovs_mutex_lock(&bfd_lock); > > > > > > > - if (bfd_e) { > > > > > > > - bfd_e->ref = true; > > > > > > > + /* This static route is linked to an active bfd session. > > > > > > > */ > > > > > > > + struct bfd_entry *bfd_sr = > > > > > > > bfd_port_lookup(bfd_active_connections, > > > > > > > + > > > > > > > nb_bt->logical_port, > > > > > > > + > > > > > > > nb_bt->dst_ip); > > > > > > > + if (!bfd_sr) { > > > > > > > + bfd_sr = bfd_alloc_entry(bfd_active_connections, > > > > > > > + nb_bt->logical_port, > > > > > > > nb_bt->dst_ip, > > > > > > > + bfd_e->status); > > > > > > > } > > > > > > > > > > > > > > - if (!strcmp(nb_bt->status, "admin_down")) { > > > > > > > - nbrec_bfd_set_status(nb_bt, "down"); > > > > > > > + if (!strcmp(bfd_e->status, "admin_down")) { > > > > > > > + bfd_set_status(bfd_sr, "down"); > > > > > > > } > > > > > > > > > > > > > > - if (!strcmp(nb_bt->status, "down")) { > > > > > > > - ovs_mutex_unlock(&bfd_lock); > > > > > > > - return NULL; > > > > > > > + > > > > > > > + if (!strcmp(bfd_sr->status, "down")) { > > > > > > > + return; > > > > > > > } > > > > > > > - ovs_mutex_unlock(&bfd_lock); > > > > > > > } > > > > > > > > > > > > > > - struct parsed_route *pr = xzalloc(sizeof *pr); > > > > > > > - pr->prefix = prefix; > > > > > > > - pr->plen = plen; > > > > > > > - pr->route_table_id = get_route_table_id(route_tables, > > > > > > > route->route_table); > > > > > > > - pr->is_src_route = (route->policy && !strcmp(route->policy, > > > > > > > - "src-ip")); > > > > > > > - pr->hash = route_hash(pr); > > > > > > > - pr->route = route; > > > > > > > - pr->ecmp_symmetric_reply = smap_get_bool(&route->options, > > > > > > > - > > > > > > > "ecmp_symmetric_reply", false); > > > > > > > - pr->is_discard_route = is_discard_route; > > > > > > > - ovs_list_insert(routes, &pr->list_node); > > > > > > > - return pr; > > > > > > > + struct parsed_route *new_pr = xzalloc(sizeof *new_pr); > > > > > > > + new_pr->prefix = prefix; > > > > > > > + new_pr->plen = plen; > > > > > > > + new_pr->route_table_id = get_route_table_id(route_tables, > > > > > > > + > > > > > > > route->route_table); > > > > > > > + new_pr->is_src_route = (route->policy && > > > > > > > + !strcmp(route->policy, "src-ip")); > > > > > > > + new_pr->hash = route_hash(new_pr); > > > > > > > + new_pr->route = route; > > > > > > > + new_pr->nbr = od->nbr; > > > > > > > + new_pr->ecmp_symmetric_reply = smap_get_bool(&route->options, > > > > > > > + > > > > > > > "ecmp_symmetric_reply", > > > > > > > + false); > > > > > > > + new_pr->is_discard_route = is_discard_route; > > > > > > > + > > > > > > > + size_t hash = uuid_hash(&od->key); > > > > > > > + struct parsed_route *pr = parsed_route_lookup(routes, hash, > > > > > > > new_pr); > > > > > > > + if (!pr) { > > > > > > > + hmap_insert(routes, &new_pr->key_node, hash); > > > > > > > + } else { > > > > > > > + pr->stale = false; > > > > > > > + free(new_pr); > > > > > > > + } > > > > > > > } > > > > > > > > > > > > > > -static void > > > > > > > -parsed_routes_destroy(struct ovs_list *routes) > > > > > > > +void > > > > > > > +build_parsed_routes(struct ovn_datapath *od, const struct hmap > > > > > > > *lr_ports, > > > > > > > + struct hmap *bfd_connections, struct hmap > > > > > > > *routes, > > > > > > > + struct simap *route_tables, > > > > > > > + struct hmap *bfd_active_connections) > > > > > > > { > > > > > > > struct parsed_route *pr; > > > > > > > - LIST_FOR_EACH_SAFE (pr, list_node, routes) { > > > > > > > - ovs_list_remove(&pr->list_node); > > > > > > > + HMAP_FOR_EACH (pr, key_node, routes) { > > > > > > > + if (pr->nbr == od->nbr) { > > > > > > > + pr->stale = true; > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + for (int i = 0; i < od->nbr->n_static_routes; i++) { > > > > > > > + parsed_routes_add(od, lr_ports, > > > > > > > od->nbr->static_routes[i], > > > > > > > + bfd_connections, routes, route_tables, > > > > > > > + bfd_active_connections); > > > > > > > + } > > > > > > > + > > > > > > > + HMAP_FOR_EACH_SAFE (pr, key_node, routes) { > > > > > > > + if (!pr->stale) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + hmap_remove(routes, &pr->key_node); > > > > > > > free(pr); > > > > > > > } > > > > > > > } > > > > > > > @@ -10830,6 +10964,7 @@ add_route(struct lflow_table *lflows, > > > > > > > struct ovn_datapath *od, > > > > > > > const struct ovn_port *op, const char *lrp_addr_s, > > > > > > > const char *network_s, int plen, const char *gateway, > > > > > > > bool is_src_route, const uint32_t rtb_id, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > const struct ovsdb_idl_row *stage_hint, bool > > > > > > > is_discard_route, > > > > > > > int ofs, struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > @@ -10878,7 +11013,7 @@ add_route(struct lflow_table *lflows, > > > > > > > struct ovn_datapath *od, > > > > > > > priority, ds_cstr(&match), > > > > > > > ds_cstr(&actions), stage_hint, > > > > > > > lflow_ref); > > > > > > > - if (op && op->has_bfd) { > > > > > > > + if (op && bfd_is_port_running(bfd_connections, op->key)) { > > > > > > > ds_put_format(&match, " && udp.dst == 3784"); > > > > > > > ovn_lflow_add_with_hint(lflows, op->od, > > > > > > > S_ROUTER_IN_IP_ROUTING, > > > > > > > @@ -10895,6 +11030,7 @@ static void > > > > > > > build_static_route_flow(struct lflow_table *lflows, struct > > > > > > > ovn_datapath *od, > > > > > > > const struct hmap *lr_ports, > > > > > > > const struct parsed_route *route_, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > const char *lrp_addr_s = NULL; > > > > > > > @@ -10918,8 +11054,9 @@ build_static_route_flow(struct > > > > > > > lflow_table *lflows, struct ovn_datapath *od, > > > > > > > char *prefix_s = build_route_prefix_s(&route_->prefix, > > > > > > > route_->plen); > > > > > > > add_route(lflows, route_->is_discard_route ? od : > > > > > > > out_port->od, out_port, > > > > > > > lrp_addr_s, prefix_s, route_->plen, route->nexthop, > > > > > > > - route_->is_src_route, route_->route_table_id, > > > > > > > &route->header_, > > > > > > > - route_->is_discard_route, ofs, lflow_ref); > > > > > > > + route_->is_src_route, route_->route_table_id, > > > > > > > + bfd_connections, &route->header_, > > > > > > > route_->is_discard_route, > > > > > > > + ofs, lflow_ref); > > > > > > > > > > > > > > free(prefix_s); > > > > > > > } > > > > > > > @@ -12062,9 +12199,10 @@ build_lrouter_force_snat_flows_op(struct > > > > > > > ovn_port *op, > > > > > > > static void > > > > > > > build_lrouter_bfd_flows(struct lflow_table *lflows, struct > > > > > > > ovn_port *op, > > > > > > > const struct shash *meter_groups, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > - if (!op->has_bfd) { > > > > > > > + if (!bfd_is_port_running(bfd_connections, op->key)) { > > > > > > > return; > > > > > > > } > > > > > > > > > > > > > > @@ -12659,32 +12797,34 @@ > > > > > > > build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od, > > > > > > > * LRP 'op'. > > > > > > > */ > > > > > > > static void > > > > > > > -build_ip_routing_flows_for_lrp( > > > > > > > - struct ovn_port *op, struct lflow_table *lflows, > > > > > > > - struct lflow_ref *lflow_ref) > > > > > > > +build_ip_routing_flows_for_lrp(struct ovn_port *op, > > > > > > > + const struct hmap > > > > > > > *bfd_connections, > > > > > > > + struct lflow_table *lflows, > > > > > > > + struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > ovs_assert(op->nbrp); > > > > > > > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > > > > > > > add_route(lflows, op->od, op, > > > > > > > op->lrp_networks.ipv4_addrs[i].addr_s, > > > > > > > op->lrp_networks.ipv4_addrs[i].network_s, > > > > > > > op->lrp_networks.ipv4_addrs[i].plen, NULL, > > > > > > > false, 0, > > > > > > > - &op->nbrp->header_, false, > > > > > > > ROUTE_PRIO_OFFSET_CONNECTED, > > > > > > > - lflow_ref); > > > > > > > + bfd_connections, &op->nbrp->header_, false, > > > > > > > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > > > > > > > } > > > > > > > > > > > > > > for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > > > > > > > add_route(lflows, op->od, op, > > > > > > > op->lrp_networks.ipv6_addrs[i].addr_s, > > > > > > > op->lrp_networks.ipv6_addrs[i].network_s, > > > > > > > op->lrp_networks.ipv6_addrs[i].plen, NULL, > > > > > > > false, 0, > > > > > > > - &op->nbrp->header_, false, > > > > > > > ROUTE_PRIO_OFFSET_CONNECTED, > > > > > > > - lflow_ref); > > > > > > > + bfd_connections, &op->nbrp->header_, false, > > > > > > > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > > > > > > > } > > > > > > > } > > > > > > > > > > > > > > static void > > > > > > > build_static_route_flows_for_lrouter( > > > > > > > struct ovn_datapath *od, struct lflow_table *lflows, > > > > > > > - const struct hmap *lr_ports, const struct hmap > > > > > > > *bfd_connections, > > > > > > > + const struct hmap *lr_ports, struct hmap *parsed_routes, > > > > > > > + struct simap *route_tables, const struct hmap > > > > > > > *bfd_connections, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > ovs_assert(od->nbr); > > > > > > > @@ -12698,22 +12838,16 @@ build_static_route_flows_for_lrouter( > > > > > > > > > > > > > > struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups); > > > > > > > struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes); > > > > > > > - struct ovs_list parsed_routes = > > > > > > > OVS_LIST_INITIALIZER(&parsed_routes); > > > > > > > - struct simap route_tables = SIMAP_INITIALIZER(&route_tables); > > > > > > > struct ecmp_groups_node *group; > > > > > > > > > > > > > > for (int i = 0; i < od->nbr->n_ports; i++) { > > > > > > > build_route_table_lflow(od, lflows, od->nbr->ports[i], > > > > > > > - &route_tables, lflow_ref); > > > > > > > + route_tables, lflow_ref); > > > > > > > } > > > > > > > > > > > > > > - for (int i = 0; i < od->nbr->n_static_routes; i++) { > > > > > > > - struct parsed_route *route = > > > > > > > - parsed_routes_add(od, lr_ports, &parsed_routes, > > > > > > > &route_tables, > > > > > > > - od->nbr->static_routes[i], > > > > > > > bfd_connections); > > > > > > > - if (!route) { > > > > > > > - continue; > > > > > > > - } > > > > > > > + struct parsed_route *route; > > > > > > > + HMAP_FOR_EACH_WITH_HASH (route, key_node, > > > > > > > uuid_hash(&od->key), > > > > > > > + parsed_routes) { > > > > > > > group = ecmp_groups_find(&ecmp_groups, route); > > > > > > > if (group) { > > > > > > > ecmp_groups_add_route(group, route); > > > > > > > @@ -12737,12 +12871,11 @@ build_static_route_flows_for_lrouter( > > > > > > > } > > > > > > > const struct unique_routes_node *ur; > > > > > > > HMAP_FOR_EACH (ur, hmap_node, &unique_routes) { > > > > > > > - build_static_route_flow(lflows, od, lr_ports, ur->route, > > > > > > > lflow_ref); > > > > > > > + build_static_route_flow(lflows, od, lr_ports, ur->route, > > > > > > > + bfd_connections, lflow_ref); > > > > > > > } > > > > > > > ecmp_groups_destroy(&ecmp_groups); > > > > > > > unique_routes_destroy(&unique_routes); > > > > > > > - parsed_routes_destroy(&parsed_routes); > > > > > > > - simap_destroy(&route_tables); > > > > > > > } > > > > > > > > > > > > > > /* IP Multicast lookup. Here we set the output port, adjust TTL > > > > > > > and > > > > > > > @@ -12849,6 +12982,115 @@ build_mcast_lookup_flows_for_lrouter( > > > > > > > } > > > > > > > } > > > > > > > > > > > > > > +static struct route_policy * > > > > > > > +route_policies_lookup(struct hmap *route_policies, size_t hash, > > > > > > > + struct route_policy *new_rp) > > > > > > > +{ > > > > > > > + struct route_policy *rp; > > > > > > > + HMAP_FOR_EACH_WITH_HASH (rp, key_node, hash, route_policies) > > > > > > > { > > > > > > > + if (rp->rule != new_rp->rule) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + if (rp->n_valid_nexthops != new_rp->n_valid_nexthops) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + size_t i; > > > > > > > + for (i = 0; i < new_rp->n_valid_nexthops; i++) { > > > > > > > + size_t j; > > > > > > > + > > > > > > > + for (j = 0; j < rp->n_valid_nexthops; j++) { > > > > > > > + if (!strcmp(new_rp->valid_nexthops[i], > > > > > > > + rp->valid_nexthops[j])) { > > > > > > > + break; > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + if (j == rp->n_valid_nexthops) { > > > > > > > + break; > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + if (i == new_rp->n_valid_nexthops) { > > > > > > > + return rp; > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + return NULL; > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +build_route_policies(struct ovn_datapath *od, const struct hmap > > > > > > > *lr_ports, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > + struct hmap *route_policies, > > > > > > > + struct hmap *bfd_active_connections) > > > > > > > +{ > > > > > > > + struct route_policy *rp; > > > > > > > + > > > > > > > + HMAP_FOR_EACH (rp, key_node, route_policies) { > > > > > > > + if (rp->nbr == od->nbr) { > > > > > > > + rp->stale = true; > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + for (int i = 0; i < od->nbr->n_policies; i++) { > > > > > > > + const struct nbrec_logical_router_policy *rule = > > > > > > > od->nbr->policies[i]; > > > > > > > + size_t n_valid_nexthops = 0; > > > > > > > + char **valid_nexthops = NULL; > > > > > > > + > > > > > > > + if (!strcmp(rule->action, "reroute")) { > > > > > > > + size_t n_nexthops = rule->n_nexthops ? > > > > > > > rule->n_nexthops : 1; > > > > > > > + > > > > > > > + valid_nexthops = xcalloc(n_nexthops, sizeof > > > > > > > *valid_nexthops); > > > > > > > + for (size_t j = 0; j < n_nexthops; j++) { > > > > > > > + char *nexthop = rule->n_nexthops > > > > > > > + ? rule->nexthops[j] : rule->nexthop; > > > > > > > + struct ovn_port *out_port = > > > > > > > + get_outport_for_routing_policy_nexthop( > > > > > > > + od, lr_ports, rule->priority, > > > > > > > nexthop); > > > > > > > + if (!out_port || !check_bfd_state(rule, > > > > > > > out_port, nexthop, > > > > > > > + > > > > > > > bfd_connections, > > > > > > > + > > > > > > > bfd_active_connections)) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + valid_nexthops[n_valid_nexthops++] = nexthop; > > > > > > > + } > > > > > > > + > > > > > > > + if (!n_valid_nexthops) { > > > > > > > + free(valid_nexthops); > > > > > > > + continue; > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + struct route_policy *new_rp = xzalloc(sizeof *new_rp); > > > > > > > + new_rp->rule = rule; > > > > > > > + new_rp->n_valid_nexthops = n_valid_nexthops; > > > > > > > + new_rp->valid_nexthops = valid_nexthops; > > > > > > > + new_rp->nbr = od->nbr; > > > > > > > + > > > > > > > + size_t hash = uuid_hash(&od->key); > > > > > > > + rp = route_policies_lookup(route_policies, hash, new_rp); > > > > > > > + if (!rp) { > > > > > > > + hmap_insert(route_policies, &new_rp->key_node, hash); > > > > > > > + } else { > > > > > > > + rp->stale = false; > > > > > > > + free(valid_nexthops); > > > > > > > + free(new_rp); > > > > > > > + } > > > > > > > + } > > > > > > > + > > > > > > > + HMAP_FOR_EACH_SAFE (rp, key_node, route_policies) { > > > > > > > + if (!rp->stale) { > > > > > > > + continue; > > > > > > > + } > > > > > > > + > > > > > > > + hmap_remove(route_policies, &rp->key_node); > > > > > > > + free(rp->valid_nexthops); > > > > > > > + free(rp); > > > > > > > + } > > > > > > > +} > > > > > > > + > > > > > > > /* Logical router ingress table POLICY: Policy. > > > > > > > * > > > > > > > * A packet that arrives at this table is an IP packet that > > > > > > > should be > > > > > > > @@ -12862,7 +13104,7 @@ static void > > > > > > > build_ingress_policy_flows_for_lrouter( > > > > > > > struct ovn_datapath *od, struct lflow_table *lflows, > > > > > > > const struct hmap *lr_ports, > > > > > > > - const struct hmap *bfd_connections, > > > > > > > + struct hmap *route_policies, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > ovs_assert(od->nbr); > > > > > > > @@ -12879,21 +13121,20 @@ build_ingress_policy_flows_for_lrouter( > > > > > > > > > > > > > > /* Convert routing policies to flows. */ > > > > > > > uint16_t ecmp_group_id = 1; > > > > > > > - for (int i = 0; i < od->nbr->n_policies; i++) { > > > > > > > - const struct nbrec_logical_router_policy *rule > > > > > > > - = od->nbr->policies[i]; > > > > > > > + struct route_policy *rp; > > > > > > > + HMAP_FOR_EACH_WITH_HASH (rp, key_node, uuid_hash(&od->key), > > > > > > > + route_policies) { > > > > > > > + const struct nbrec_logical_router_policy *rule = > > > > > > > rp->rule; > > > > > > > bool is_ecmp_reroute = > > > > > > > (!strcmp(rule->action, "reroute") && > > > > > > > rule->n_nexthops > 1); > > > > > > > > > > > > > > if (is_ecmp_reroute) { > > > > > > > - build_ecmp_routing_policy_flows(lflows, od, > > > > > > > lr_ports, rule, > > > > > > > - bfd_connections, > > > > > > > ecmp_group_id, > > > > > > > - lflow_ref); > > > > > > > + build_ecmp_routing_policy_flows(lflows, od, > > > > > > > lr_ports, rp, > > > > > > > + ecmp_group_id, > > > > > > > lflow_ref); > > > > > > > ecmp_group_id++; > > > > > > > } else { > > > > > > > - build_routing_policy_flow(lflows, od, lr_ports, rule, > > > > > > > - bfd_connections, > > > > > > > &rule->header_, > > > > > > > - lflow_ref); > > > > > > > + build_routing_policy_flow(lflows, od, lr_ports, rp, > > > > > > > + &rule->header_, lflow_ref); > > > > > > > } > > > > > > > } > > > > > > > } > > > > > > > @@ -14105,6 +14346,7 @@ build_lrouter_ipv4_ip_input(struct > > > > > > > ovn_port *op, > > > > > > > struct lflow_table *lflows, > > > > > > > struct ds *match, struct ds *actions, > > > > > > > const struct shash *meter_groups, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > struct lflow_ref *lflow_ref) > > > > > > > { > > > > > > > ovs_assert(op->nbrp); > > > > > > > @@ -14146,7 +14388,8 @@ build_lrouter_ipv4_ip_input(struct > > > > > > > ovn_port *op, > > > > > > > } > > > > > > > > > > > > > > /* BFD msg handling */ > > > > > > > - build_lrouter_bfd_flows(lflows, op, meter_groups, lflow_ref); > > > > > > > + build_lrouter_bfd_flows(lflows, op, meter_groups, > > > > > > > bfd_connections, > > > > > > > + lflow_ref); > > > > > > > > > > > > > > /* ICMP time exceeded */ > > > > > > > struct ds ip_ds = DS_EMPTY_INITIALIZER; > > > > > > > @@ -15589,6 +15832,7 @@ build_lsp_lflows_for_lbnats(struct > > > > > > > ovn_port *lsp, > > > > > > > static void > > > > > > > build_routable_flows_for_router_port( > > > > > > > struct ovn_port *lrp, const struct lr_stateful_record > > > > > > > *lr_stateful_rec, > > > > > > > + const struct hmap *bfd_connections, > > > > > > > struct lflow_table *lflows, > > > > > > > struct ds *match, > > > > > > > struct ds *actions) > > > > > > > @@ -15625,8 +15869,8 @@ build_routable_flows_for_router_port( > > > > > > > > > > > > > > router_port->lrp_networks.ipv4_addrs[0].addr_s, > > > > > > > laddrs->ipv4_addrs[k].network_s, > > > > > > > laddrs->ipv4_addrs[k].plen, NULL, > > > > > > > false, 0, > > > > > > > - &router_port->nbrp->header_, false, > > > > > > > - ROUTE_PRIO_OFFSET_CONNECTED, > > > > > > > + bfd_connections, > > > > > > > &router_port->nbrp->header_, > > > > > > > + false, ROUTE_PRIO_OFFSET_CONNECTED, > > > > > > > lrp->stateful_lflow_ref); > > > > > > > } > > > > > > > } > > > > > > > @@ -15736,8 +15980,8 @@ build_lrp_lflows_for_lbnats(struct > > > > > > > ovn_port *op, > > > > > > > static void > > > > > > > build_lbnat_lflows_iterate_by_lrp( > > > > > > > struct ovn_port *op, const struct lr_stateful_table > > > > > > > *lr_stateful_table, > > > > > > > - const struct shash *meter_groups, struct ds *match, > > > > > > > - struct ds *actions, struct lflow_table *lflows) > > > > > > > + const struct shash *meter_groups, const struct hmap > > > > > > > *bfd_connections, > > > > > > > + struct ds *match, struct ds *actions, struct lflow_table > > > > > > > *lflows) > > > > > > > { > > > > > > > ovs_assert(op->nbrp); > > > > > > > > > > > > > > @@ -15749,8 +15993,8 @@ build_lbnat_lflows_iterate_by_lrp( > > > > > > > build_lrp_lflows_for_lbnats(op, lr_stateful_rec, > > > > > > > meter_groups, match, > > > > > > > actions, lflows); > > > > > > > > > > > > > > - build_routable_flows_for_router_port(op, lr_stateful_rec, > > > > > > > lflows, match, > > > > > > > - actions); > > > > > > > + build_routable_flows_for_router_port(op, lr_stateful_rec, > > > > > > > bfd_connections, > > > > > > > + lflows, match, actions); > > > > > > > } > > > > > > > > > > > > > > static void > > > > > > > @@ -15818,6 +16062,9 @@ struct lswitch_flow_build_info { > > > > > > > struct ds actions; > > > > > > > size_t thread_lflow_counter; > > > > > > > const char *svc_monitor_mac; > > > > > > > + struct hmap *parsed_routes; > > > > > > > + struct hmap *route_policies; > > > > > > > + struct simap *route_tables; > > > > > > > }; > > > > > > > > > > > > > > /* Helper function to combine all lflow generation which is > > > > > > > iterated by > > > > > > > @@ -15863,12 +16110,12 @@ > > > > > > > build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, > > > > > > > build_ND_RA_flows_for_lrouter(od, lsi->lflows, NULL); > > > > > > > build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, > > > > > > > NULL); > > > > > > > build_static_route_flows_for_lrouter(od, lsi->lflows, > > > > > > > lsi->lr_ports, > > > > > > > - lsi->bfd_connections, > > > > > > > - NULL); > > > > > > > + lsi->parsed_routes, > > > > > > > lsi->route_tables, > > > > > > > + lsi->bfd_connections, > > > > > > > NULL); > > > > > > > build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, > > > > > > > &lsi->match, > > > > > > > &lsi->actions, NULL); > > > > > > > build_ingress_policy_flows_for_lrouter(od, lsi->lflows, > > > > > > > lsi->lr_ports, > > > > > > > - lsi->bfd_connections, > > > > > > > NULL); > > > > > > > + lsi->route_policies, > > > > > > > NULL); > > > > > > > build_arp_resolve_flows_for_lrouter(od, lsi->lflows, NULL); > > > > > > > build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, > > > > > > > lsi->lr_ports, > > > > > > > &lsi->match, > > > > > > > &lsi->actions, > > > > > > > @@ -15935,7 +16182,8 @@ > > > > > > > build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > > > > > > > &lsi->actions, > > > > > > > op->lflow_ref); > > > > > > > build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, > > > > > > > &lsi->match, > > > > > > > &lsi->actions, > > > > > > > op->lflow_ref); > > > > > > > - build_ip_routing_flows_for_lrp(op, lsi->lflows, > > > > > > > op->lflow_ref); > > > > > > > + build_ip_routing_flows_for_lrp(op, lsi->bfd_connections, > > > > > > > + lsi->lflows, op->lflow_ref); > > > > > > > build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, > > > > > > > &lsi->match, > > > > > > > &lsi->actions, > > > > > > > lsi->meter_groups, > > > > > > > op->lflow_ref); > > > > > > > @@ -15953,7 +16201,8 @@ > > > > > > > build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > > > > > > > lsi->meter_groups, > > > > > > > op->lflow_ref); > > > > > > > build_lrouter_ipv4_ip_input(op, lsi->lflows, &lsi->match, > > > > > > > &lsi->actions, > > > > > > > - lsi->meter_groups, > > > > > > > op->lflow_ref); > > > > > > > + lsi->meter_groups, > > > > > > > lsi->bfd_connections, > > > > > > > + op->lflow_ref); > > > > > > > build_lrouter_icmp_packet_toobig_admin_flows(op, > > > > > > > lsi->lflows, &lsi->match, > > > > > > > &lsi->actions, > > > > > > > op->lflow_ref); > > > > > > > } > > > > > > > @@ -16042,7 +16291,8 @@ build_lflows_thread(void *arg) > > > > > > > build_lswitch_and_lrouter_iterate_by_lrp(op, > > > > > > > lsi); > > > > > > > build_lbnat_lflows_iterate_by_lrp( > > > > > > > op, lsi->lr_stateful_table, > > > > > > > lsi->meter_groups, > > > > > > > - &lsi->match, &lsi->actions, lsi->lflows); > > > > > > > + lsi->bfd_connections, &lsi->match, > > > > > > > &lsi->actions, > > > > > > > + lsi->lflows); > > > > > > > } > > > > > > > } > > > > > > > for (bnum = control->id; > > > > > > > @@ -16182,7 +16432,10 @@ build_lswitch_and_lrouter_flows( > > > > > > > const struct hmap *svc_monitor_map, > > > > > > > const struct hmap *bfd_connections, > > > > > > > const struct chassis_features *features, > > > > > > > - const char *svc_monitor_mac) > > > > > > > + const char *svc_monitor_mac, > > > > > > > + struct hmap *parsed_routes, > > > > > > > + struct hmap *route_policies, > > > > > > > + struct simap *route_tables) > > > > > > > { > > > > > > > > > > > > > > char *svc_check_match = xasprintf("eth.dst == %s", > > > > > > > svc_monitor_mac); > > > > > > > @@ -16216,6 +16469,9 @@ build_lswitch_and_lrouter_flows( > > > > > > > lsiv[index].svc_check_match = svc_check_match; > > > > > > > lsiv[index].thread_lflow_counter = 0; > > > > > > > lsiv[index].svc_monitor_mac = svc_monitor_mac; > > > > > > > + lsiv[index].parsed_routes = parsed_routes; > > > > > > > + lsiv[index].route_tables = route_tables; > > > > > > > + lsiv[index].route_policies = route_policies; > > > > > > > ds_init(&lsiv[index].match); > > > > > > > ds_init(&lsiv[index].actions); > > > > > > > > > > > > > > @@ -16256,6 +16512,9 @@ build_lswitch_and_lrouter_flows( > > > > > > > .features = features, > > > > > > > .svc_check_match = svc_check_match, > > > > > > > .svc_monitor_mac = svc_monitor_mac, > > > > > > > + .parsed_routes = parsed_routes, > > > > > > > + .route_tables = route_tables, > > > > > > > + .route_policies = route_policies, > > > > > > > .match = DS_EMPTY_INITIALIZER, > > > > > > > .actions = DS_EMPTY_INITIALIZER, > > > > > > > }; > > > > > > > @@ -16287,6 +16546,7 @@ build_lswitch_and_lrouter_flows( > > > > > > > build_lswitch_and_lrouter_iterate_by_lrp(op, &lsi); > > > > > > > build_lbnat_lflows_iterate_by_lrp(op, > > > > > > > lsi.lr_stateful_table, > > > > > > > lsi.meter_groups, > > > > > > > + > > > > > > > lsi.bfd_connections, > > > > > > > &lsi.match, > > > > > > > &lsi.actions, > > > > > > > lsi.lflows); > > > > > > > @@ -16417,7 +16677,10 @@ void build_lflows(struct ovsdb_idl_txn > > > > > > > *ovnsb_txn, > > > > > > > input_data->svc_monitor_map, > > > > > > > input_data->bfd_connections, > > > > > > > input_data->features, > > > > > > > - input_data->svc_monitor_mac); > > > > > > > + input_data->svc_monitor_mac, > > > > > > > + input_data->parsed_routes, > > > > > > > + input_data->route_policies, > > > > > > > + input_data->route_tables); > > > > > > > > > > > > > > if (parallelization_state == STATE_INIT_HASH_SIZES) { > > > > > > > parallelization_state = STATE_USE_PARALLELIZATION; > > > > > > > @@ -16779,6 +17042,7 @@ lflow_handle_lr_stateful_changes(struct > > > > > > > ovsdb_idl_txn *ovnsb_txn, > > > > > > > build_lbnat_lflows_iterate_by_lrp(op, > > > > > > > > > > > > > > lflow_input->lr_stateful_table, > > > > > > > > > > > > > > lflow_input->meter_groups, > > > > > > > + > > > > > > > lflow_input->bfd_connections, > > > > > > > &match, &actions, > > > > > > > lflows); > > > > > > > > > > > > > > @@ -17490,6 +17754,27 @@ northd_init(struct northd_data *data) > > > > > > > init_northd_tracked_data(data); > > > > > > > } > > > > > > > > > > > > > > +void > > > > > > > +route_policies_init(struct route_policies_data *data) > > > > > > > +{ > > > > > > > + hmap_init(&data->route_policies); > > > > > > > + hmap_init(&data->bfd_active_connections); > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +static_routes_init(struct static_routes_data *data) > > > > > > > +{ > > > > > > > + hmap_init(&data->parsed_routes); > > > > > > > + simap_init(&data->route_tables); > > > > > > > + hmap_init(&data->bfd_active_connections); > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +bfd_init(struct bfd_data *data) > > > > > > > +{ > > > > > > > + hmap_init(&data->bfd_connections); > > > > > > > +} > > > > > > > + > > > > > > > void > > > > > > > northd_destroy(struct northd_data *data) > > > > > > > { > > > > > > > @@ -17529,6 +17814,48 @@ northd_destroy(struct northd_data *data) > > > > > > > destroy_northd_tracked_data(data); > > > > > > > } > > > > > > > > > > > > > > +static void > > > > > > > +__bfd_destroy(struct hmap *bfd_connections) > > > > > > > +{ > > > > > > > + struct bfd_entry *bfd_e; > > > > > > > + > > > > > > > + HMAP_FOR_EACH_POP (bfd_e, hmap_node, bfd_connections) { > > > > > > > + bfd_erase_entry(bfd_e); > > > > > > > + } > > > > > > > + hmap_destroy(bfd_connections); > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +bfd_destroy(struct bfd_data *data) > > > > > > > +{ > > > > > > > + __bfd_destroy(&data->bfd_connections); > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +route_policies_destroy(struct route_policies_data *data) > > > > > > > +{ > > > > > > > + struct route_policy *rp; > > > > > > > + HMAP_FOR_EACH_POP (rp, key_node, &data->route_policies) { > > > > > > > + free(rp->valid_nexthops); > > > > > > > + free(rp); > > > > > > > + }; > > > > > > > + hmap_destroy(&data->route_policies); > > > > > > > + __bfd_destroy(&data->bfd_active_connections); > > > > > > > +} > > > > > > > + > > > > > > > +void > > > > > > > +static_routes_destroy(struct static_routes_data *data) > > > > > > > +{ > > > > > > > + struct parsed_route *r; > > > > > > > + HMAP_FOR_EACH_POP (r, key_node, &data->parsed_routes) { > > > > > > > + free(r); > > > > > > > + } > > > > > > > + hmap_destroy(&data->parsed_routes); > > > > > > > + > > > > > > > + simap_destroy(&data->route_tables); > > > > > > > + __bfd_destroy(&data->bfd_active_connections); > > > > > > > +} > > > > > > > + > > > > > > > void > > > > > > > ovnnb_db_run(struct northd_input *input_data, > > > > > > > struct northd_data *data, > > > > > > > diff --git a/northd/northd.h b/northd/northd.h > > > > > > > index d4a8d75ab..432072f9f 100644 > > > > > > > --- a/northd/northd.h > > > > > > > +++ b/northd/northd.h > > > > > > > @@ -23,6 +23,7 @@ > > > > > > > #include "northd/en-port-group.h" > > > > > > > #include "northd/ipam.h" > > > > > > > #include "openvswitch/hmap.h" > > > > > > > +#include "simap.h" > > > > > > > #include "ovs-thread.h" > > > > > > > > > > > > > > struct northd_input { > > > > > > > @@ -160,14 +161,34 @@ struct northd_data { > > > > > > > struct northd_tracked_data trk_data; > > > > > > > }; > > > > > > > > > > > > > > +struct route_policy { > > > > > > > + struct hmap_node key_node; > > > > > > > + const struct nbrec_logical_router_policy *rule; > > > > > > > + size_t n_valid_nexthops; > > > > > > > + char **valid_nexthops; > > > > > > > + const struct nbrec_logical_router *nbr; > > > > > > > + bool stale; > > > > > > > +}; > > > > > > > + > > > > > > > +struct static_routes_data { > > > > > > > + struct hmap parsed_routes; > > > > > > > + struct simap route_tables; > > > > > > > + struct hmap bfd_active_connections; > > > > > > > +}; > > > > > > > + > > > > > > > +struct route_policies_data { > > > > > > > + struct hmap route_policies; > > > > > > > + struct hmap bfd_active_connections; > > > > > > > +}; > > > > > > > + > > > > > > > +struct bfd_data { > > > > > > > + struct hmap bfd_connections; > > > > > > > +}; > > > > > > > + > > > > > > > struct lr_nat_table; > > > > > > > > > > > > > > struct lflow_input { > > > > > > > - /* Northbound table references */ > > > > > > > - const struct nbrec_bfd_table *nbrec_bfd_table; > > > > > > > - > > > > > > > /* Southbound table references */ > > > > > > > - const struct sbrec_bfd_table *sbrec_bfd_table; > > > > > > > const struct sbrec_logical_flow_table > > > > > > > *sbrec_logical_flow_table; > > > > > > > const struct sbrec_multicast_group_table > > > > > > > *sbrec_multicast_group_table; > > > > > > > const struct sbrec_igmp_group_table *sbrec_igmp_group_table; > > > > > > > @@ -190,6 +211,9 @@ struct lflow_input { > > > > > > > const struct hmap *svc_monitor_map; > > > > > > > bool ovn_internal_version_changed; > > > > > > > const char *svc_monitor_mac; > > > > > > > + struct hmap *parsed_routes; > > > > > > > + struct hmap *route_policies; > > > > > > > + struct simap *route_tables; > > > > > > > }; > > > > > > > > > > > > > > extern int parallelization_state; > > > > > > > @@ -593,8 +617,6 @@ struct ovn_port { > > > > > > > > > > > > > > bool has_unknown; /* If the addresses have 'unknown' > > > > > > > defined. */ > > > > > > > > > > > > > > - bool has_bfd; > > > > > > > - > > > > > > > /* The port's peer: > > > > > > > * > > > > > > > * - A switch port S of type "router" has a router port > > > > > > > R as a peer, > > > > > > > @@ -653,6 +675,20 @@ struct ovn_port { > > > > > > > struct lflow_ref *stateful_lflow_ref; > > > > > > > }; > > > > > > > > > > > > > > +struct parsed_route { > > > > > > > + struct hmap_node key_node; > > > > > > > + struct in6_addr prefix; > > > > > > > + unsigned int plen; > > > > > > > + bool is_src_route; > > > > > > > + uint32_t route_table_id; > > > > > > > + uint32_t hash; > > > > > > > + const struct nbrec_logical_router_static_route *route; > > > > > > > + bool ecmp_symmetric_reply; > > > > > > > + bool is_discard_route; > > > > > > > + const struct nbrec_logical_router *nbr; > > > > > > > + bool stale; > > > > > > > +}; > > > > > > > + > > > > > > > void ovnnb_db_run(struct northd_input *input_data, > > > > > > > struct northd_data *data, > > > > > > > struct ovsdb_idl_txn *ovnnb_txn, > > > > > > > @@ -674,6 +710,18 @@ void northd_init(struct northd_data *data); > > > > > > > void northd_indices_create(struct northd_data *data, > > > > > > > struct ovsdb_idl *ovnsb_idl); > > > > > > > > > > > > > > +void route_policies_init(struct route_policies_data *); > > > > > > > +void route_policies_destroy(struct route_policies_data *); > > > > > > > +void build_parsed_routes(struct ovn_datapath *, const struct > > > > > > > hmap *, > > > > > > > + struct hmap *, struct hmap *, struct > > > > > > > simap *, > > > > > > > + struct hmap *); > > > > > > > +uint32_t get_route_table_id(struct simap *, const char *); > > > > > > > +void static_routes_init(struct static_routes_data *); > > > > > > > +void static_routes_destroy(struct static_routes_data *); > > > > > > > + > > > > > > > +void bfd_init(struct bfd_data *); > > > > > > > +void bfd_destroy(struct bfd_data *); > > > > > > > + > > > > > > > struct lflow_table; > > > > > > > struct lr_stateful_tracked_data; > > > > > > > struct ls_stateful_tracked_data; > > > > > > > @@ -711,13 +759,13 @@ bool northd_handle_lb_data_changes(struct > > > > > > > tracked_lb_data *, > > > > > > > struct hmap > > > > > > > *lbgrp_datapaths_map, > > > > > > > struct northd_tracked_data *); > > > > > > > > > > > > > > -void build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn, > > > > > > > - const struct nbrec_bfd_table *, > > > > > > > - const struct sbrec_bfd_table *, > > > > > > > - const struct hmap *lr_ports, > > > > > > > - struct hmap *bfd_connections); > > > > > > > -void bfd_cleanup_connections(const struct nbrec_bfd_table *, > > > > > > > - struct hmap *bfd_map); > > > > > > > +void build_route_policies(struct ovn_datapath *, const struct > > > > > > > hmap *, > > > > > > > + const struct hmap *, struct hmap *, > > > > > > > struct hmap *); > > > > > > > +void bfd_table_sync(struct ovsdb_idl_txn *, const struct > > > > > > > nbrec_bfd_table *, > > > > > > > + const struct hmap *, const struct hmap *, > > > > > > > + const struct hmap *, const struct hmap *, > > > > > > > struct hmap *); > > > > > > > +void build_bfd_map(const struct nbrec_bfd_table *, > > > > > > > + const struct sbrec_bfd_table *, struct hmap > > > > > > > *); > > > > > > > void run_update_worker_pool(int n_threads); > > > > > > > > > > > > > > const struct ovn_datapath *northd_get_datapath_for_port( > > > > > > > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > > > > > > > index 199197f09..710500dce 100644 > > > > > > > --- a/tests/ovn-northd.at > > > > > > > +++ b/tests/ovn-northd.at > > > > > > > @@ -12,6 +12,7 @@ m4_define([_DUMP_DB_TABLES], [ > > > > > > > ovn-sbctl list meter >> $1 > > > > > > > ovn-sbctl list meter_band >> $1 > > > > > > > ovn-sbctl list port_group >> $1 > > > > > > > + ovn-sbctl list bfd >> $1 > > > > > > > ovn-sbctl dump-flows > lflows_$1 > > > > > > > ]) > > > > > > > > > > > > > > @@ -3861,6 +3862,7 @@ for i in $(seq 1 9); do > > > > > > > check ovn-nbctl --wait=sb lsp-set-addresses sw$i-r0 > > > > > > > 00:00:00:00:00:0$i > > > > > > > done > > > > > > > > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > uuid=$(ovn-nbctl create bfd logical_port=r0-sw1 > > > > > > > dst_ip=192.168.1.2 status=down min_tx=250 min_rx=250 > > > > > > > detect_mult=10) > > > > > > > ovn-nbctl create bfd logical_port=r0-sw2 dst_ip=192.168.2.2 > > > > > > > status=down min_tx=500 min_rx=500 detect_mult=20 > > > > > > > ovn-nbctl create bfd logical_port=r0-sw3 dst_ip=192.168.3.2 > > > > > > > status=down > > > > > > > @@ -3873,6 +3875,13 @@ wait_row_count bfd 1 logical_port=r0-sw2 > > > > > > > detect_mult=20 dst_ip=192.168.2.2 \ > > > > > > > wait_row_count bfd 1 logical_port=r0-sw3 detect_mult=5 > > > > > > > dst_ip=192.168.3.2 \ > > > > > > > min_rx=1000 min_tx=1000 status=admin_down > > > > > > > > > > > > > > +check_engine_stats northd norecompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw1) > > > > > > > check ovn-nbctl set bfd $uuid min_tx=1000 min_rx=1000 > > > > > > > detect_mult=100 > > > > > > > > > > > > > > @@ -3881,10 +3890,25 @@ check ovn-nbctl clear bfd $uuid_2 min_rx > > > > > > > wait_row_count bfd 1 logical_port=r0-sw2 min_rx=1000 > > > > > > > wait_row_count bfd 1 logical_port=r0-sw1 min_rx=1000 min_tx=1000 > > > > > > > detect_mult=100 > > > > > > > > > > > > > > +check_engine_stats northd norecompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > check ovn-nbctl --bfd=$uuid lr-route-add r0 100.0.0.0/8 > > > > > > > 192.168.1.2 > > > > > > > wait_column down bfd status logical_port=r0-sw1 > > > > > > > AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.1.2 | grep > > > > > > > -q bfd],[0]) > > > > > > > > > > > > > > +check_engine_stats northd recompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats static_routes recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > check ovn-nbctl --bfd lr-route-add r0 200.0.0.0/8 192.168.2.2 > > > > > > > wait_column down bfd status logical_port=r0-sw2 > > > > > > > AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.2.2 | grep > > > > > > > -q bfd],[0]) > > > > > > > @@ -3893,10 +3917,26 @@ check ovn-nbctl --bfd lr-route-add r0 > > > > > > > 240.0.0.0/8 192.168.5.2 r0-sw5 > > > > > > > wait_column down bfd status logical_port=r0-sw5 > > > > > > > AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.5.2 | grep > > > > > > > -q bfd],[0]) > > > > > > > > > > > > > > +check_engine_stats northd recompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats static_routes recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > check ovn-nbctl --bfd --policy=src-ip lr-route-add r0 > > > > > > > 192.168.6.1/32 192.168.10.10 r0-sw6 > > > > > > > wait_column down bfd status logical_port=r0-sw6 > > > > > > > AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.6.1 | grep > > > > > > > -q bfd],[0]) > > > > > > > > > > > > > > +check_engine_stats northd recompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats route_policies recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > check ovn-nbctl --bfd --policy=src-ip lr-route-add r0 > > > > > > > 192.168.7.1/32 192.168.10.10 r0-sw7 > > > > > > > wait_column down bfd status logical_port=r0-sw7 > > > > > > > AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.7.1 | grep > > > > > > > -q bfd],[0]) > > > > > > > @@ -3924,6 +3964,14 @@ wait_column down bfd status > > > > > > > logical_port=r0-sw8 > > > > > > > bfd_route_policy_uuid=$(fetch_column nb:bfd _uuid > > > > > > > logical_port=r0-sw8) > > > > > > > AT_CHECK([ovn-nbctl list logical_router_policy | grep -q > > > > > > > $bfd_route_policy_uuid]) > > > > > > > > > > > > > > +check_engine_stats northd recompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats static_routes recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > check ovn-nbctl lr-policy-del r0 > > > > > > > check ovn-nbctl --bfd lr-policy-add r0 100 "ip4.src == > > > > > > > 2.3.4.0/24" reroute 192.168.9.2,192.168.9.3,192.168.9.4 > > > > > > > > > > > > > > @@ -3931,6 +3979,14 @@ wait_column down bfd status > > > > > > > dst_ip=192.168.9.2 > > > > > > > wait_column down bfd status dst_ip=192.168.9.3 > > > > > > > wait_column down bfd status dst_ip=192.168.9.4 > > > > > > > > > > > > > > +check_engine_stats northd recompute nocompute > > > > > > > +check_engine_stats bfd recompute nocompute > > > > > > > +check_engine_stats route_policies recompute nocompute > > > > > > > +check_engine_stats lflow recompute nocompute > > > > > > > +check_engine_stats northd_output norecompute compute > > > > > > > +CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > > > > > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats > > > > > > > + > > > > > > > bfd_route_policy_uuid=$(fetch_column nb:bfd _uuid > > > > > > > logical_port=r0-sw9) > > > > > > > AT_CHECK([ovn-nbctl list logical_router_policy | sed s/,//g | > > > > > > > grep -q "$bfd_route_policy_uuid"]) > > > > > > > > > > > > > > -- > > > > > > > 2.45.2 > > > > > > > > > > > > > > > > > >
_______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
