diff --git a/NEWS b/NEWS index 40a1b9867b..19d4d8f594 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ Post v26.09.09 -------------- + - ovn-controller now injects locally generated IGMP/MLD membership + queries using the MC_FLOOD_L2 group (L2 ports only) instead of + MC_FLOOD. This matches snooped-query forwarding (RFC 4541) and + avoids exceeding the OVS 4096 resubmit limit when a logical switch + has many local ports or connected logical routers. - Mark tunnel ports as transient (other_config:transient=true) when the local chassis is a member of an HA chassis group. Systems which invoke ovs-ctl --delete-transient-ports during OVS startup diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 333dcedb6e..0170f63135 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -151,7 +151,10 @@ VLOG_DEFINE_THIS_MODULE(pinctrl); * contents and stores them in mcast_query_list. * * pinctrl_handler thread sends the periodic IGMP queries - * by walking the mcast_query_list. + * by walking the mcast_query_list. Locally generated + * queries are injected with outport MC_FLOOD_L2 so they + * stay in the L2 broadcast domain (RFC 4541) and are + * not flooded towards logical router ports. * * Notification between pinctrl_handler() and pinctrl_run() * ------------------------------------------------------- @@ -6211,12 +6214,16 @@ ip_mcast_querier_send_igmp(struct rconn *swconn, struct ip_mcast_snoop *ip_ms) uint8_t qqic = max_response; packet_set_igmp3_query(&packet, max_response, 0, false, 0, qqic); - /* Inject multicast query. */ + /* Inject multicast query. Use MC_FLOOD_L2 rather than MC_FLOOD so the + * query is not flooded to connected logical routers. Flooding to every + * local port (including router patch ports) can exceed the OVS 4096 + * resubmit limit in scaled topologies. Snooped queries already use + * MC_FLOOD_L2 via ip_mcast_forward_query(). */ uint64_t ofpacts_stub[4096 / 8]; struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); enum ofp_version version = rconn_get_version(swconn); put_load(ip_ms->dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); - put_load(OVN_MCAST_FLOOD_TUNNEL_KEY, MFF_LOG_OUTPORT, 0, 32, &ofpacts); + put_load(OVN_MCAST_FLOOD_L2_TUNNEL_KEY, MFF_LOG_OUTPORT, 0, 32, &ofpacts); put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY, 1, &ofpacts); struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); resubmit->in_port = OFPP_CONTROLLER; @@ -6261,12 +6268,12 @@ ip_mcast_querier_send_mld(struct rconn *swconn, struct ip_mcast_snoop *ip_ms) struct in6_addr unspecified = { { { 0 } } }; packet_set_mld_query(&packet, max_response, &unspecified, false, 0, qqic); - /* Inject multicast query. */ + /* Inject multicast query. See ip_mcast_querier_send_igmp(). */ uint64_t ofpacts_stub[4096 / 8]; struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); enum ofp_version version = rconn_get_version(swconn); put_load(ip_ms->dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); - put_load(OVN_MCAST_FLOOD_TUNNEL_KEY, MFF_LOG_OUTPORT, 0, 32, &ofpacts); + put_load(OVN_MCAST_FLOOD_L2_TUNNEL_KEY, MFF_LOG_OUTPORT, 0, 32, &ofpacts); put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY, 1, &ofpacts); struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); resubmit->in_port = OFPP_CONTROLLER; diff --git a/tests/ovn.at b/tests/ovn.at index a88a077c61..d9301d8cf5 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -24633,8 +24633,11 @@ check ovn-nbctl set Logical_Switch sw2 \ other_config:mcast_ip4_src="20.0.0.254" AS_BOX([IGMP traffic test 4]) -# Check that multiple queries are generated over time. +# Check that multiple queries are generated over time and stay in the +# L2 domain (MC_FLOOD_L2): they must reach sw2 VIFs and must not be +# flooded towards the router onto sw1/sw3. > expected +> expected_empty store_igmp_v3_query 0000000002fe $(ip_to_hex 20 0 0 254) 84dd expected store_igmp_v3_query 0000000002fe $(ip_to_hex 20 0 0 254) 84dd expected @@ -24650,7 +24653,13 @@ for count in 1 2 3; do OVS_WAIT_UNTIL( [check_packets --uniq \ 'hv1/vif3-tx.pcap expected' \ - 'hv2/vif3-tx.pcap expected'], + 'hv2/vif3-tx.pcap expected' \ + 'hv1/vif1-tx.pcap expected_empty' \ + 'hv1/vif2-tx.pcap expected_empty' \ + 'hv1/vif4-tx.pcap expected_empty' \ + 'hv2/vif1-tx.pcap expected_empty' \ + 'hv2/vif2-tx.pcap expected_empty' \ + 'hv2/vif4-tx.pcap expected_empty'], [$at_diff -F'^---' exp rcv]) done @@ -25364,8 +25373,11 @@ check ovn-nbctl --wait=hv set Logical_Switch sw2 \ AT_CAPTURE_FILE([sbflows4]) ovn-sbctl dump-flows > sbflows4 -# Check that multiple queries are generated over time. +# Check that multiple queries are generated over time and stay in the +# L2 domain (MC_FLOOD_L2): they must reach sw2 VIFs and must not be +# flooded towards the router onto sw1/sw3. > expected +> expected_empty store_mld_query 0000000002fe fe8000000000000000000000000000fe expected store_mld_query 0000000002fe fe8000000000000000000000000000fe expected for count in 1 2 3; do @@ -25380,7 +25392,13 @@ for count in 1 2 3; do OVS_WAIT_UNTIL( [check_packets --uniq \ 'hv1/vif3-tx.pcap expected' \ - 'hv2/vif3-tx.pcap expected'], + 'hv2/vif3-tx.pcap expected' \ + 'hv1/vif1-tx.pcap expected_empty' \ + 'hv1/vif2-tx.pcap expected_empty' \ + 'hv1/vif4-tx.pcap expected_empty' \ + 'hv2/vif1-tx.pcap expected_empty' \ + 'hv2/vif2-tx.pcap expected_empty' \ + 'hv2/vif4-tx.pcap expected_empty'], [$at_diff -F'^---' exp rcv]) done