Hi Lorenzo,

On 4/16/25 1:07 PM, Lorenzo Bianconi wrote:
> Avoid recirculating IGMP/MLD packets more than one time from stage
> ls_out_pre_lb in the egress pipeline to ovn table 37 in order to avoid
> packet looping for ovn-ic deployment.
> 
> Reported-at: https://issues.redhat.com/browse/FDP-58
> Acked-by: Mohammad Heib <mh...@redhat.com>

I assume this ack is a leftover from the old attempt (that got reverted
in the meantime).  I removed it, I hope that's fine.

> Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
> ---
>  controller/pinctrl.c         |  2 ++
>  include/ovn/logical-fields.h |  3 +++
>  lib/logical-fields.c         |  5 +++++
>  northd/en-multicast.c        |  2 +-
>  northd/northd.c              | 11 +++++++----
>  tests/ovn-ic.at              | 32 +++++++++++++++++++++++++++++++-
>  6 files changed, 49 insertions(+), 6 deletions(-)
> 
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index bdb619b4d..5e24d97c8 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -727,6 +727,8 @@ pinctrl_forward_pkt(struct rconn *swconn, int64_t dp_key,
>      put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts);
>      put_load(in_port_key, MFF_LOG_INPORT, 0, 32, &ofpacts);
>      put_load(out_port_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts);
> +    /* Avoid re-injecting packet already consumed. */
> +    put_load(1, MFF_LOG_FLAGS, MLF_IGMP_IGMP_SNOOP_INJECT_BIT, 1, &ofpacts);
>  
>      struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
>      resubmit->in_port = OFPP_CONTROLLER;
> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
> index 17154d38b..653145ddd 100644
> --- a/include/ovn/logical-fields.h
> +++ b/include/ovn/logical-fields.h
> @@ -103,6 +103,7 @@ enum mff_log_flags_bits {
>      MLF_FROM_CTRL_BIT = 19,
>      MLF_UNSNAT_NEW_BIT = 20,
>      MLF_UNSNAT_NOT_TRACKED_BIT = 21,
> +    MLF_IGMP_IGMP_SNOOP_INJECT_BIT = 22,
>      MLF_NETWORK_ID_START_BIT = 28,
>      MLF_NETWORK_ID_END_BIT = 31,
>  };
> @@ -169,6 +170,8 @@ enum mff_log_flags {
>      /* Indicate that the packet didn't go through unSNAT. */
>      MLF_UNSNAT_NOT_TRACKED = (1 << MLF_UNSNAT_NOT_TRACKED_BIT),
>  


I added a comment here:

/* Indicate that this is an IGMP packet reinjected by ovn-controller. */

> +    MLF_IGMP_IGMP_SNOOP = (1 << MLF_IGMP_IGMP_SNOOP_INJECT_BIT),
> +
>      /* Assign network ID to packet to choose correct network for snat when
>       * lb_force_snat_ip=router_ip. */
>      MLF_NETWORK_ID = (OVN_MAX_NETWORK_ID << MLF_NETWORK_ID_START_BIT),
> diff --git a/lib/logical-fields.c b/lib/logical-fields.c
> index db2d08ada..a74e18e0f 100644
> --- a/lib/logical-fields.c
> +++ b/lib/logical-fields.c
> @@ -154,6 +154,11 @@ ovn_init_symtab(struct shash *symtab)
>      snprintf(flags_str, sizeof flags_str, "flags[%d]", MLF_FROM_CTRL_BIT);
>      expr_symtab_add_subfield(symtab, "flags.from_ctrl", NULL, flags_str);
>  
> +    snprintf(flags_str, sizeof flags_str, "flags[%d]",
> +             MLF_IGMP_IGMP_SNOOP_INJECT_BIT);
> +    expr_symtab_add_subfield(symtab, "flags.igmp_loopback", NULL,
> +                             flags_str);

Nit: this fits on one line.

> +
>      /* Connection tracking state. */
>      expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false,
>                                   WR_CT_COMMIT);
> diff --git a/northd/en-multicast.c b/northd/en-multicast.c
> index 7f3a6077c..657e20b39 100644
> --- a/northd/en-multicast.c
> +++ b/northd/en-multicast.c
> @@ -625,7 +625,7 @@ ovn_igmp_group_get_ports(const struct sbrec_igmp_group 
> *sb_igmp_group,
>          }
>  
>          /* If this is already a flood port skip it for the group. */
> -        if (port->mcast_info.flood) {
> +        if (port->mcast_info.flood || port->mcast_info.flood_reports) {
>              continue;
>          }
>  
> diff --git a/northd/northd.c b/northd/northd.c
> index 1f9340e55..5416244cc 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -6125,7 +6125,8 @@ build_interconn_mcast_snoop_flows(struct ovn_datapath 
> *od,
>              continue;
>          }
>          /* Punt IGMP traffic to controller. */
> -        char *match = xasprintf("inport == %s && igmp", op->json_key);
> +        char *match = xasprintf("inport == %s && igmp && "
> +                                "flags.igmp_loopback == 0", op->json_key);
>          ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
>                            "clone { igmp; }; next;",
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
> @@ -6134,7 +6135,8 @@ build_interconn_mcast_snoop_flows(struct ovn_datapath 
> *od,
>          free(match);
>  
>          /* Punt MLD traffic to controller. */
> -        match = xasprintf("inport == %s && (mldv1 || mldv2)", op->json_key);
> +        match = xasprintf("inport == %s && (mldv1 || mldv2) && "
> +                          "flags.igmp_loopback == 0", op->json_key);
>          ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
>                            "clone { igmp; }; next;",
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
> @@ -9994,14 +9996,15 @@ build_lswitch_destination_lookup_bmcast(struct 
> ovn_datapath *od,
>          ds_put_cstr(actions, "igmp;");
>          /* Punt IGMP traffic to controller. */
>          ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
> -                          "igmp", ds_cstr(actions),
> +                          "flags.igmp_loopback == 0 && igmp", 
> ds_cstr(actions),
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
>                                           meter_groups),
>                            lflow_ref);
>  
>          /* Punt MLD traffic to controller. */
>          ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
> -                          "mldv1 || mldv2", ds_cstr(actions),
> +                          "flags.igmp_loopback == 0 && (mldv1 || mldv2)",
> +                          ds_cstr(actions),
>                            copp_meter_get(COPP_IGMP, od->nbs->copp,
>                                           meter_groups),
>                            lflow_ref);
> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
> index c8276189c..401a71580 100644
> --- a/tests/ovn-ic.at
> +++ b/tests/ovn-ic.at
> @@ -2043,6 +2043,10 @@ check ovs-vsctl -- add-port br-int hv2-vif2 \
>      -- set interface hv2-vif2 external-ids:iface-id=lsp3 \
>         options:tx_pcap=hv2/vif2-tx.pcap \
>         options:rxq_pcap=hv2/vif2-rx.pcap
> +check ovs-vsctl -- add-port br-int hv2-vif3 \
> +    -- set interface hv2-vif3 external-ids:iface-id=lsp4 \
> +       options:tx_pcap=hv2/vif3-tx.pcap \
> +       options:rxq_pcap=hv2/vif3-rx.pcap
>  check ovs-vsctl set open . external-ids:ovn-is-interconn=true
>  
>  AT_CHECK([ovn-ic-nbctl --wait=sb create Transit_Switch name=ts], [0], 
> [ignore])
> @@ -2081,6 +2085,8 @@ check ovn-nbctl lsp-add ts ts-lr2 \
>      -- lsp-set-addresses ts-lr2 router \
>      -- lsp-set-type ts-lr2 router \
>      -- lsp-set-options ts-lr2 router-port=lr2-ts
> +check ovn-nbctl lsp-add ts lsp4 \
> +    -- lsp-set-addresses lsp4 unknown
>  
>  check ovn-nbctl lr-add lr3 \
>      -- lrp-add lr3 lr3-ts 00:00:00:02:00:02 42.42.42.3/24 4242::3/64 \
> @@ -2165,6 +2171,18 @@ send_mld_v2_report hv2-vif2 hv2 \
>      ff0adeadbeef00000000000000000001 04 c0e4 \
>      /dev/null
>  
> +# Inject IGMP Join for 239.0.1.68 on LSP4.
> +send_igmp_v3_report hv2-vif3 hv2 \
> +    000000000001 $(ip_to_hex 10 0 0 42) f9cf \
> +    $(ip_to_hex 239 0 1 68) 04 e9b9 \
> +    /dev/null
> +
> +# Inject MLD Join for ff0a:dead:beef::1 on LSP3.
> +send_mld_v2_report hv2-vif3 hv2 \
> +    000000000001 10000000000000000000000000000042 \
> +    ff0adeadbeef00000000000000000001 04 c0a3 \
> +    /dev/null
> +
>  # Check that the IGMP and MLD groups are learned on both AZs (on the LS
>  # and TS).
>  ovn_as az1
> @@ -2181,6 +2199,7 @@ check ovn-nbctl --wait=hv sync
>  # to lsp1 and lsp3.
>  > expected_az1
>  > expected_az2
> +> expected_az2-lsp4
>  send_ip_multicast_pkt hv2-vif1 hv2 \
>      000000000001 01005e000144 \
>      $(ip_to_hex 44 44 44 2) $(ip_to_hex 239 0 1 68) 1e 20 7c6b 11 \
> @@ -2193,6 +2212,10 @@ store_ip_multicast_pkt \
>      000000020200 01005e000144 \
>      $(ip_to_hex 44 44 44 2) $(ip_to_hex 239 0 1 68) 1e 1e 7e6b 11 \
>      e518e518000aed350000 expected_az2
> +store_ip_multicast_pkt \
> +    000000020001 01005e000144 \
> +    $(ip_to_hex 44 44 44 2) $(ip_to_hex 239 0 1 68) 1e 1f 7d6b 11 \
> +    e518e518000aed350000 expected_az2-lsp4
>  
>  send_ip6_multicast_pkt hv2-vif1 hv2 \
>      000000000001 333300000001 \
> @@ -2211,10 +2234,17 @@ store_ip6_multicast_pkt \
>      000e 3e 11 \
>      93407a69000e2b4e61736461640a \
>      expected_az2
> +store_ip6_multicast_pkt \
> +    000000020001 333300000001 \
> +    00100000000000000000000000000042 ff0adeadbeef00000000000000000001 \
> +    000e 3f 11 \
> +    93407a69000e2b4e61736461640a \
> +    expected_az2-lsp4
>  
>  OVS_WAIT_UNTIL(
>    [check_packets 'hv1/vif1-tx.pcap expected_az1' \
> -                 'hv2/vif2-tx.pcap expected_az2'],
> +                 'hv2/vif2-tx.pcap expected_az2' \
> +                 'hv2/vif3-tx.pcap expected_az2-lsp4'],
>    [$at_diff -F'^---' exp rcv])
>  
>  OVN_CLEANUP_SBOX([hv1], ["/IGMP Querier enabled without a valid IPv4/d

With the minor comments I had above addressed I went ahead and pushed
this patch to main.

Even though it's a bug fix, I chose not to backport it because:
1. it introduces new logical fields and we'd need to be careful handling
those during minor upgrades
2. as far as I know there's no user configuring OVN IC and IGMP in this
specific way yet.

If there's a need to backport this in the future we can revisit it and
maybe add a feature flag to be checked by ovn-northd in case of minor
upgrades that first upgrade ovn-northd.

Regards,
Dumitru


_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to