On 1/28/25 8:22 AM, Ales Musil wrote: > The removal is needed for IGMP I-P node, because the ovn_datapath > shouldn't hold reference to struct that might have different lifetime > and might be freed during different node run. The same logic applies > in the opposite direction, the list holds pointer to list inside > ovn_datapath. > > This also allows to better isolate logical flows that are related > to igmp in functions that can be reused for the IGMP handler. > > Co-authored-by: Jacob Tanenbaum <jtane...@redhat.com> > Signed-off-by: Jacob Tanenbaum <jtane...@redhat.com> > Suggested-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com> > Signed-off-by: Ales Musil <amu...@redhat.com> > --- > v3: Rebase on top of latest main. > ---
Hi Ales, > northd/en-multicast.c | 68 ++++++---------- > northd/en-multicast.h | 1 - > northd/northd.c | 185 ++++++++++++++++++++++++------------------ > northd/northd.h | 1 - > 4 files changed, 132 insertions(+), 123 deletions(-) > > diff --git a/northd/en-multicast.c b/northd/en-multicast.c > index deb192a82..0f07cf2fe 100644 > --- a/northd/en-multicast.c > +++ b/northd/en-multicast.c > @@ -207,18 +207,24 @@ build_mcast_groups(const struct sbrec_igmp_group_table > *sbrec_igmp_group_table, > > /* Add the extracted ports to the IGMP group. */ > ovn_igmp_group_add_entry(igmp_group, igmp_ports, n_igmp_ports); > - } > > - /* Build IGMP groups for multicast routers with relay enabled. The router > - * IGMP groups are based on the groups learnt by their multicast enabled > - * peers. > - */ > - HMAP_FOR_EACH (od, key_node, ls_datapaths) { > + /* Skip mrouter entries. */ > + if (!strcmp(igmp_group->mcgroup.name, OVN_IGMP_GROUP_MROUTERS)) { > + continue; > + } > > - if (ovs_list_is_empty(&od->mcast_info.groups)) { > + /* For IPv6 only relay routable multicast groups > + * (RFC 4291 2.7). > + */ > + if (!IN6_IS_ADDR_V4MAPPED(&group_address) && > + !ipv6_addr_is_routable_multicast(&group_address)) { > continue; > } > > + /* Build IGMP groups for multicast routers with relay enabled. > + * The router IGMP groups are based on the groups learnt by their > + * multicast enabled peers. > + */ > for (size_t i = 0; i < od->n_router_ports; i++) { > struct ovn_port *router_port = od->router_ports[i]->peer; > > @@ -232,38 +238,19 @@ build_mcast_groups(const struct sbrec_igmp_group_table > *sbrec_igmp_group_table, > continue; > } > > - struct ovn_igmp_group *igmp_group; > - LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) { > - struct in6_addr *address = &igmp_group->address; > - > - /* Skip mrouter entries. */ > - if (!strcmp(igmp_group->mcgroup.name, > - OVN_IGMP_GROUP_MROUTERS)) { > - continue; > - } > - > - /* For IPv6 only relay routable multicast groups > - * (RFC 4291 2.7). > - */ > - if (!IN6_IS_ADDR_V4MAPPED(address) && > - !ipv6_addr_is_routable_multicast(address)) { > - continue; > - } > - > - struct ovn_igmp_group *igmp_group_rtr = > - ovn_igmp_group_add(sbrec_mcast_group_by_name_dp, > - igmp_groups, router_port->od, > - address, igmp_group->mcgroup.name); > - struct ovn_port **router_igmp_ports = > - xmalloc(sizeof *router_igmp_ports); > - /* Store the chassis redirect port otherwise traffic will > not > - * be tunneled properly. > - */ > - router_igmp_ports[0] = router_port->cr_port > - ? router_port->cr_port > - : router_port; > - ovn_igmp_group_add_entry(igmp_group_rtr, router_igmp_ports, > 1); > - } > + struct ovn_igmp_group *igmp_group_rtr = > + ovn_igmp_group_add(sbrec_mcast_group_by_name_dp, > + igmp_groups, router_port->od, > + &group_address, igmp_group->mcgroup.name); > + struct ovn_port **router_igmp_ports = > + xmalloc(sizeof *router_igmp_ports); > + /* Store the chassis redirect port otherwise traffic will not > + * be tunneled properly. > + */ > + router_igmp_ports[0] = router_port->cr_port > + ? router_port->cr_port > + : router_port; > + ovn_igmp_group_add_entry(igmp_group_rtr, router_igmp_ports, 1); > } > } > > @@ -522,8 +509,6 @@ ovn_igmp_group_add(struct ovsdb_idl_index > *sbrec_mcast_group_by_name_dp, > > hmap_insert(igmp_groups, &igmp_group->hmap_node, > ovn_igmp_group_hash(datapath, address)); > - ovs_list_push_back(&datapath->mcast_info.groups, > - &igmp_group->list_node); > } > > return igmp_group; > @@ -656,7 +641,6 @@ ovn_igmp_group_destroy(struct hmap *igmp_groups, > free(entry); > } > hmap_remove(igmp_groups, &igmp_group->hmap_node); > - ovs_list_remove(&igmp_group->list_node); > free(igmp_group); > } > } > diff --git a/northd/en-multicast.h b/northd/en-multicast.h > index 5fa4d8976..9a6848f78 100644 > --- a/northd/en-multicast.h > +++ b/northd/en-multicast.h > @@ -62,7 +62,6 @@ struct ovn_igmp_group_entry { > */ > struct ovn_igmp_group { > struct hmap_node hmap_node; /* Index on 'datapath' and 'address'. */ > - struct ovs_list list_node; /* Linkage in the per-dp igmp group list. */ > > struct ovn_datapath *datapath; > struct in6_addr address; /* Multicast IPv6-mapped-IPv4 or IPv4 address. > */ > diff --git a/northd/northd.c b/northd/northd.c > index 59495717d..db62a2bfc 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -668,7 +668,6 @@ init_mcast_info_for_datapath(struct ovn_datapath *od) > hmap_init(&od->mcast_info.group_tnlids); > /* allocations start from hint + 1 */ > od->mcast_info.group_tnlid_hint = OVN_MIN_IP_MULTICAST - 1; > - ovs_list_init(&od->mcast_info.groups); > > if (od->nbs) { > init_mcast_info_for_switch_datapath(od); > @@ -9768,39 +9767,6 @@ build_lswitch_destination_lookup_bmcast(struct > ovn_datapath *od, > "ip6.mcast_flood", > "outport = \""MC_FLOOD"\"; output;", > lflow_ref); > - > - /* Forward uregistered IP multicast to routers with relay enabled > - * and to any ports configured to flood IP multicast traffic. > - * If configured to flood unregistered traffic this will be > - * handled by the L2 multicast flow. > - */ > - if (!mcast_sw_info->flood_unregistered) { > - ds_clear(actions); > - > - if (mcast_sw_info->flood_relay) { > - ds_put_cstr(actions, > - "clone { " > - "outport = \""MC_MROUTER_FLOOD"\"; " > - "output; " > - "}; "); > - } > - > - if (mcast_sw_info->flood_static) { > - ds_put_cstr(actions, "outport =\""MC_STATIC"\"; output;"); > - } > - > - /* Explicitly drop the traffic if relay or static flooding > - * is not configured. > - */ > - if (!mcast_sw_info->flood_relay && > - !mcast_sw_info->flood_static) { > - ds_put_cstr(actions, debug_drop_action()); > - } > - > - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, > - "ip4.mcast || ip6.mcast", > - ds_cstr(actions), lflow_ref); > - } > } > > if (!smap_get_bool(&od->nbs->other_config, > @@ -9815,6 +9781,48 @@ build_lswitch_destination_lookup_bmcast(struct > ovn_datapath *od, > "outport = \""MC_FLOOD"\"; output;", lflow_ref); > } > > +/* Ingress table destination lookup, multicast handling (priority 80). */ > +static void > +build_mcast_flood_lswitch(struct ovn_datapath *od, struct lflow_table > *lflows, > + struct ds *actions, struct lflow_ref *lflow_ref) > +{ > + ovs_assert(od->nbs); > + struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw; > + if (!mcast_sw_info->enabled || mcast_sw_info->flood_unregistered) { > + return; > + } > + > + ds_clear(actions); > + > + /* Forward unregistered IP multicast to routers with relay enabled > + * and to any ports configured to flood IP multicast traffic. > + * If configured to flood unregistered traffic this will be > + * handled by the L2 multicast flow. > + */ > + if (mcast_sw_info->flood_relay) { > + ds_put_cstr(actions, > + "clone { " > + "outport = \""MC_MROUTER_FLOOD"\"; " > + "output; " > + "}; "); > + } > + > + if (mcast_sw_info->flood_static) { > + ds_put_cstr(actions, "outport =\""MC_STATIC"\"; output;"); > + } > + > + /* Explicitly drop the traffic if relay or static flooding > + * is not configured. > + */ > + if (!mcast_sw_info->flood_relay && > + !mcast_sw_info->flood_static) { > + ds_put_cstr(actions, debug_drop_action()); > + } > + > + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, > + "ip4.mcast || ip6.mcast", ds_cstr(actions), lflow_ref); > +} > + > > /* Ingress table 25: Add IP multicast flows learnt from IGMP/MLD > * (priority 90). */ > @@ -9822,11 +9830,10 @@ static void > build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, > struct lflow_table *lflows, > struct ds *actions, > - struct ds *match) > + struct ds *match, > + struct lflow_ref *lflow_ref) > { > - if (!(igmp_group->datapath && igmp_group->datapath->nbs)) { > - return; > - } > + ovs_assert(igmp_group->datapath->nbs); > > uint64_t dummy; > > @@ -9896,7 +9903,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group > *igmp_group, > igmp_group->mcgroup.name); > > ovn_lflow_add(lflows, igmp_group->datapath, S_SWITCH_IN_L2_LKUP, > - 90, ds_cstr(match), ds_cstr(actions), NULL); > + 90, ds_cstr(match), ds_cstr(actions), lflow_ref); > } > > /* Ingress table 25: Destination lookup, unicast handling (priority 50), */ > @@ -13499,14 +13506,50 @@ build_route_flows_for_lrouter( > unique_routes_destroy(&unique_routes); > } > > +static void > +build_igmp_flows_for_lrouter(struct ovn_igmp_group *igmp_group, > + struct lflow_table *lflows, > + struct ds *match, struct ds *actions, > + struct lflow_ref *lflow_ref) > +{ > + ovs_assert(igmp_group->datapath->nbr); > + > + if (!igmp_group->datapath->mcast_info.rtr.relay) { > + return; > + } > + > + ds_clear(match); > + ds_clear(actions); > + if (IN6_IS_ADDR_V4MAPPED(&igmp_group->address)) { > + ds_put_format(match, "ip4 && ip4.dst == %s ", > + igmp_group->mcgroup.name); > + } else { > + ds_put_format(match, "ip6 && ip6.dst == %s ", > + igmp_group->mcgroup.name); > + } > + if (igmp_group->datapath->mcast_info.rtr.flood_static) { > + ds_put_cstr(actions, > + "clone { " > + "outport = \""MC_STATIC"\"; " > + "ip.ttl--; " > + "next; " > + "};"); > + } > + ds_put_format(actions, "outport = \"%s\"; ip.ttl--; next;", > + igmp_group->mcgroup.name); > + ovn_lflow_add(lflows, igmp_group->datapath, S_ROUTER_IN_IP_ROUTING, > 10500, > + ds_cstr(match), ds_cstr(actions), > + lflow_ref); > +} > + > /* IP Multicast lookup. Here we set the output port, adjust TTL and > * advance to next table (priority 500). > */ > static void > -build_mcast_lookup_flows_for_lrouter( > - struct ovn_datapath *od, struct lflow_table *lflows, > - struct ds *match, struct ds *actions, > - struct lflow_ref *lflow_ref) > +build_mcast_lookup_flows_for_lrouter(struct ovn_datapath *od, > + struct lflow_table *lflows, > + struct ds *match, > + struct lflow_ref *lflow_ref) > { > ovs_assert(od->nbr); > > @@ -13520,33 +13563,6 @@ build_mcast_lookup_flows_for_lrouter( > return; > } > > - struct ovn_igmp_group *igmp_group; > - > - LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) { > - ds_clear(match); > - ds_clear(actions); > - if (IN6_IS_ADDR_V4MAPPED(&igmp_group->address)) { > - ds_put_format(match, "ip4 && ip4.dst == %s ", > - igmp_group->mcgroup.name); > - } else { > - ds_put_format(match, "ip6 && ip6.dst == %s ", > - igmp_group->mcgroup.name); > - } > - if (od->mcast_info.rtr.flood_static) { > - ds_put_cstr(actions, > - "clone { " > - "outport = \""MC_STATIC"\"; " > - "ip.ttl--; " > - "next; " > - "};"); > - } > - ds_put_format(actions, "outport = \"%s\"; ip.ttl--; next;", > - igmp_group->mcgroup.name); > - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10500, > - ds_cstr(match), ds_cstr(actions), > - lflow_ref); > - } > - > /* If needed, flood unregistered multicast on statically configured > * ports. Otherwise drop any multicast traffic. > */ > @@ -16961,6 +16977,7 @@ build_lswitch_and_lrouter_iterate_by_ls(struct > ovn_datapath *od, > build_lswitch_output_port_sec_od(od, lsi->lflows, NULL); > build_lswitch_lb_affinity_default_flows(od, lsi->lflows, NULL); > build_lswitch_lflows_l2_unknown(od, lsi->lflows, NULL); > + build_mcast_flood_lswitch(od, lsi->lflows, &lsi->actions, NULL); > } > > /* Helper function to combine all lflow generation which is iterated by > @@ -16980,8 +16997,7 @@ build_lswitch_and_lrouter_iterate_by_lr(struct > ovn_datapath *od, > build_route_flows_for_lrouter(od, lsi->lflows, > lsi->parsed_routes, lsi->route_tables, > lsi->bfd_ports, NULL); > - build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, > - &lsi->actions, NULL); > + build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, NULL); > build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports, > lsi->route_policies, NULL); > build_arp_resolve_flows_for_lrouter(od, lsi->lflows, NULL); > @@ -17243,9 +17259,16 @@ build_lflows_thread(void *arg) > if (stop_parallel_processing()) { > return NULL; > } > - build_lswitch_ip_mcast_igmp_mld(igmp_group, lsi->lflows, > - &lsi->match, > - &lsi->actions); > + if (igmp_group->datapath->nbs) { > + build_lswitch_ip_mcast_igmp_mld(igmp_group, > + lsi->lflows, > + &lsi->actions, > + &lsi->match, NULL); > + } else { > + build_igmp_flows_for_lrouter(igmp_group, lsi->lflows, > + &lsi->actions, > + &lsi->match, NULL); Nit: The "name mismatch" between the switch and router case is not that nice. I renamed this function to build_lrouter_ip_mcast_igmp_mld(). With this small modification, I applied the patch to main. Thanks, Dumitru _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev