From patchwork Tue Sep 24 08:02:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dumitru Ceara X-Patchwork-Id: 1166447 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46ctwZ0cQpz9sP3 for ; Tue, 24 Sep 2019 18:03:09 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 57187B79; Tue, 24 Sep 2019 08:03:06 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 7C3AFB62 for ; Tue, 24 Sep 2019 08:03:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id EF94A8B0 for ; Tue, 24 Sep 2019 08:02:52 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7815A2A09DB for ; Tue, 24 Sep 2019 08:02:52 +0000 (UTC) Received: from dceara.remote.csb (ovpn-117-103.ams2.redhat.com [10.36.117.103]) by smtp.corp.redhat.com (Postfix) with ESMTP id AEB476017E for ; Tue, 24 Sep 2019 08:02:51 +0000 (UTC) From: Dumitru Ceara To: dev@openvswitch.org Date: Tue, 24 Sep 2019 10:02:49 +0200 Message-Id: <1569312169-27322-1-git-send-email-dceara@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 24 Sep 2019 08:02:52 +0000 (UTC) X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2] ovn-northd: Add static IP multicast flood configuration X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add the following new configuration options to the Logical_Switch_Port:options column in the OVN Northbound database: - mcast_flood: if set to 'true' all incoming IP multicast traffic (except IP multicast reports) entering the switch will also be flooded on the logical switch port. - mcast_flood_reports: if set to 'true' all incoming IP multicast entering the switch will also be flooded on the logical switch port. A clone of the packets is also processed by ovn-controller for snooping. Add the following new configuration option to the Logical_Router_Port:options column in the OVN Northbound database: - mcast_flood: if set to 'true' all incoming IP multicast traffic (including IP multicast reports) entering the router will be also flooded on the logical router port. Due to the fact that in the router pipeline multicast reports are not treated in a special way there's no need for an explicit 'mcast_flood_reports' option for router ports. Signed-off-by: Dumitru Ceara Acked-by: Mark Michelson --- v2: Rebase & fix tag in ovn-nb.xml --- lib/mcast-group-index.h | 2 + northd/ovn-northd.8.xml | 30 +++++-- northd/ovn-northd.c | 212 ++++++++++++++++++++++++++++++++++++++++++------ ovn-nb.xml | 33 ++++++++ tests/ovn.at | 81 +++++++++++++++++- 5 files changed, 324 insertions(+), 34 deletions(-) diff --git a/lib/mcast-group-index.h b/lib/mcast-group-index.h index cb49ad7..ba995ba 100644 --- a/lib/mcast-group-index.h +++ b/lib/mcast-group-index.h @@ -28,6 +28,8 @@ enum ovn_mcast_tunnel_keys { OVN_MCAST_FLOOD_TUNNEL_KEY = OVN_MIN_MULTICAST, OVN_MCAST_UNKNOWN_TUNNEL_KEY, OVN_MCAST_MROUTER_FLOOD_TUNNEL_KEY, + OVN_MCAST_MROUTER_STATIC_TUNNEL_KEY, + OVN_MCAST_STATIC_TUNNEL_KEY, OVN_MIN_IP_MULTICAST, OVN_MAX_IP_MULTICAST = OVN_MAX_MULTICAST, }; diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 0f4f1c1..429ed7e 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -954,7 +954,11 @@ output;
  • A priority-100 flow that punts all IGMP packets to ovn-controller if IGMP snooping is enabled on the - logical switch. + logical switch. The flow also forwards the IGMP packets to the + MC_MROUTER_STATIC multicast group, which + ovn-northd populates with all the logical ports that + have + :mcast_flood_reports='true'.
  • @@ -976,10 +980,15 @@ output;
  • A priority-80 flow that forwards all unregistered IP multicast traffic - to the MC_MROUTER_FLOOD multicast group, if any. - Otherwise the flow drops all unregistered IP multicast packets. This - flow is added only if :mcast_flood_unregistered='false'. + to the MC_STATIC multicast group, which + ovn-northd populates with all the logical ports that + have + :mcast_flood='true'. The flow also forwards + unregistered IP multicast traffic to the MC_MROUTER_FLOOD + multicast group, which ovn-northd populates with all the + logical ports connected to logical routers that have + + :mcast_relay='true'.
  • @@ -2027,6 +2036,17 @@ output;
  • + Priority-450 flow that matches unregistered IP multicast traffic + and sets outport to the MC_STATIC + multicast group, which ovn-northd populates with the + logical ports that have + + :mcast_flood='true'. +

    +
  • + +
  • +

    For distributed logical routers where one of the logical router ports specifies a redirect-chassis, a priority-400 logical flow for each ip source/destination couple that matches the diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index f393ceb..538daa1 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -448,7 +448,12 @@ struct mcast_switch_info { * should be flooded to the mrouter. Only * applicable if flood_unregistered == false. */ - + bool flood_reports; /* True if the switch has at least one port + * configured to flood reports. + */ + bool flood_static; /* True if the switch has at least one port + * configured to flood traffic. + */ int64_t table_size; /* Max number of IP multicast groups. */ int64_t idle_timeout; /* Timeout after which an idle group is * flushed. @@ -466,7 +471,10 @@ struct mcast_switch_info { }; struct mcast_router_info { - bool relay; /* True if the router should relay IP multicast. */ + bool relay; /* True if the router should relay IP multicast. */ + bool flood_static; /* True if the router has at least one port configured + * to flood traffic. + */ }; struct mcast_info { @@ -481,6 +489,34 @@ struct mcast_info { }; }; +struct mcast_port_info { + bool flood; /* True if the port should flood IP multicast traffic + * regardless if it's registered or not. */ + bool flood_reports; /* True if the port should flood IP multicast reports + * (e.g., IGMP join/leave). */ +}; + +static void +init_mcast_port_info(struct mcast_port_info *mcast_info, + const struct nbrec_logical_switch_port *nbsp, + const struct nbrec_logical_router_port *nbrp) +{ + if (nbsp) { + mcast_info->flood = + smap_get_bool( ->options, "mcast_flood", false); + mcast_info->flood_reports = + smap_get_bool( ->options, "mcast_flood_reports", + false); + } else if (nbrp) { + /* We don't process multicast reports in any special way on logical + * routers so just treat them as regular multicast traffic. + */ + mcast_info->flood = + smap_get_bool(&nbrp->options, "mcast_flood", false); + mcast_info->flood_reports = mcast_info->flood; + } +} + static uint32_t ovn_mcast_group_allocate_key(struct mcast_info *mcast_info) { @@ -1022,7 +1058,7 @@ build_datapaths(struct northd_context *ctx, struct hmap *datapaths, ovn_datapath_destroy(datapaths, od); } } - + struct ovn_port { struct hmap_node key_node; /* Index on 'key'. */ char *key; /* nbs->name, nbr->name, sb->logical_port. */ @@ -1044,6 +1080,9 @@ struct ovn_port { struct lport_addresses lrp_networks; + /* Logical port multicast data. */ + struct mcast_port_info mcast_info; + bool derived; /* Indicates whether this is an additional port * derived from nbsp or nbrp. */ @@ -1060,6 +1099,23 @@ struct ovn_port { struct ovs_list list; /* In list of similar records. */ }; +static void +ovn_port_set_sb(struct ovn_port *op, + const struct sbrec_port_binding *sb) +{ + op->sb = sb; +} + +static void +ovn_port_set_nb(struct ovn_port *op, + const struct nbrec_logical_switch_port *nbsp, + const struct nbrec_logical_router_port *nbrp) +{ + op->nbsp = nbsp; + op->nbrp = nbrp; + init_mcast_port_info(&op->mcast_info, op->nbsp, op->nbrp); +} + static struct ovn_port * ovn_port_create(struct hmap *ports, const char *key, const struct nbrec_logical_switch_port *nbsp, @@ -1073,9 +1129,8 @@ ovn_port_create(struct hmap *ports, const char *key, op->json_key = ds_steal_cstr(&json_key); op->key = xstrdup(key); - op->sb = sb; - op->nbsp = nbsp; - op->nbrp = nbrp; + ovn_port_set_sb(op, sb); + ovn_port_set_nb(op, nbsp, nbrp); op->derived = false; hmap_insert(ports, &op->key_node, hash_string(op->key, 0)); return op; @@ -1878,7 +1933,7 @@ join_logical_ports(struct northd_context *ctx, nbsp->name); continue; } - op->nbsp = nbsp; + ovn_port_set_nb(op, nbsp, NULL); ovs_list_remove(&op->list); uint32_t queue_id = smap_get_int(&op->sb->options, @@ -1969,7 +2024,7 @@ join_logical_ports(struct northd_context *ctx, nbrp->name); continue; } - op->nbrp = nbrp; + ovn_port_set_nb(op, NULL, nbrp); ovs_list_remove(&op->list); ovs_list_push_back(both, &op->list); @@ -2014,7 +2069,7 @@ join_logical_ports(struct northd_context *ctx, struct ovn_port *crp = ovn_port_find(ports, redirect_name); if (crp) { crp->derived = true; - crp->nbrp = nbrp; + ovn_port_set_nb(crp, NULL, nbrp); ovs_list_remove(&crp->list); ovs_list_push_back(both, &crp->list); } else { @@ -2890,7 +2945,7 @@ build_ports(struct northd_context *ctx, continue; } - op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn); + ovn_port_set_sb(op, sbrec_port_binding_insert(ctx->ovnsb_txn)); ovn_port_update_sbrec(ctx, sbrec_chassis_by_name, op, &chassis_qdisc_queues, &active_ha_chassis_grps); @@ -2932,6 +2987,14 @@ static const struct multicast_group mc_flood = static const struct multicast_group mc_mrouter_flood = { MC_MROUTER_FLOOD, OVN_MCAST_MROUTER_FLOOD_TUNNEL_KEY }; +#define MC_MROUTER_STATIC "_MC_mrouter_static" +static const struct multicast_group mc_mrouter_static = + { MC_MROUTER_STATIC, OVN_MCAST_MROUTER_STATIC_TUNNEL_KEY }; + +#define MC_STATIC "_MC_static" +static const struct multicast_group mc_static = + { MC_STATIC, OVN_MCAST_STATIC_TUNNEL_KEY }; + #define MC_UNKNOWN "_MC_unknown" static const struct multicast_group mc_unknown = { MC_UNKNOWN, OVN_MCAST_UNKNOWN_TUNNEL_KEY }; @@ -3145,7 +3208,23 @@ ovn_igmp_group_get_ports(const struct sbrec_igmp_group *sb_igmp_group, *n_ports = 0; for (size_t i = 0; i < sb_igmp_group->n_ports; i++) { - ports[(*n_ports)] = + struct ovn_port *port = + ovn_port_find(ovn_ports, sb_igmp_group->ports[i]->logical_port); + + /* If this is already a flood port skip it for the group. */ + if (port->mcast_info.flood) { + continue; + } + + /* If this is already a port of a router on which relay is enabled, + * skip it for the group. Traffic is flooded there anyway. + */ + if (port->peer && port->peer->od && + port->peer->od->mcast_info.rtr.relay) { + continue; + } + + ports[(*n_ports)] = port; ovn_port_find(ovn_ports, sb_igmp_group->ports[i]->logical_port); if (ports[(*n_ports)]) { (*n_ports)++; @@ -5440,9 +5519,18 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw; if (mcast_sw_info->enabled) { + ds_clear(&actions); + if (mcast_sw_info->flood_reports) { + ds_put_cstr(&actions, + "clone { " + "outport = \""MC_MROUTER_STATIC"\"; " + "output; " + "};"); + } + ds_put_cstr(&actions, "igmp;"); /* Punt IGMP traffic to controller. */ ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 100, - "ip4 && ip.proto == 2", "igmp;"); + "ip4 && ip.proto == 2", ds_cstr(&actions)); /* Flood all IP multicast traffic destined to 224.0.0.X to all * ports - RFC 4541, section 2.1.2, item 2. @@ -5451,17 +5539,30 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "ip4 && ip4.dst == 224.0.0.0/24", "outport = \""MC_FLOOD"\"; output;"); - /* Drop unregistered IP multicast if not allowed. */ + /* 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) { - /* Forward unregistered IP multicast to mrouter (if any). */ + ds_clear(&actions); + if (mcast_sw_info->flood_relay) { - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, - "ip4 && ip4.mcast", - "outport = \""MC_MROUTER_FLOOD"\"; output;"); + ds_put_cstr(&actions, + "clone { " + "outport = \""MC_MROUTER_FLOOD"\"; " + "output; " + "}; "); + } + + if (mcast_sw_info->flood_static) { + ds_put_cstr(&actions, "outport =\""MC_STATIC"\"; output;"); } else { - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, - "ip4 && ip4.mcast", "drop;"); + ds_put_cstr(&actions, "drop;"); } + + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, + "ip4 && ip4.mcast", ds_cstr(&actions)); } } @@ -5491,11 +5592,20 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, "eth.mcast && ip4 && ip4.dst == %s ", igmp_group->mcgroup.name); + /* Also flood traffic to all multicast routers with relay enabled. */ if (mcast_sw_info->flood_relay) { ds_put_cstr(&actions, "clone { " - "outport = \""MC_MROUTER_FLOOD "\"; output; " + "outport = \""MC_MROUTER_FLOOD "\"; " + "output; " + "};"); + } + if (mcast_sw_info->flood_static) { + ds_put_cstr(&actions, + "clone { " + "outport =\""MC_STATIC"\"; " + "output; " "};"); } ds_put_format(&actions, "outport = \"%s\"; output; ", @@ -7711,6 +7821,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (!od->nbr || !od->mcast_info.rtr.relay) { continue; } + struct ovn_igmp_group *igmp_group; LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) { @@ -7718,11 +7829,35 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&actions); ds_put_format(&match, "ip4 && ip4.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, 500, ds_cstr(&match), ds_cstr(&actions)); } + + /* If needed, flood unregistered multicast on statically configured + * ports. + */ + if (od->mcast_info.rtr.flood_static) { + ds_clear(&match); + ds_clear(&actions); + ds_put_format(&match, "ip4.mcast"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 450, + "ip4.mcast", + "clone { " + "outport = \""MC_STATIC"\"; " + "ip.ttl--; " + "next; " + "};"); + } } /* Logical router ingress table 8: Policy. @@ -8893,11 +9028,15 @@ build_mcast_groups(struct northd_context *ctx, hmap_init(igmp_groups); HMAP_FOR_EACH (op, key_node, ports) { - if (!op->nbsp) { - continue; - } - - if (lsp_is_enabled(op->nbsp)) { + if (op->nbrp && lrport_is_enabled(op->nbrp)) { + /* If this port is configured to always flood multicast traffic + * add it to the MC_STATIC group. + */ + if (op->mcast_info.flood) { + ovn_multicast_add(mcast_groups, &mc_static, op); + op->od->mcast_info.rtr.flood_static = true; + } + } else if (op->nbsp && lsp_is_enabled(op->nbsp)) { ovn_multicast_add(mcast_groups, &mc_flood, op); /* If this port is connected to a multicast router then add it @@ -8907,6 +9046,22 @@ build_mcast_groups(struct northd_context *ctx, op->peer->od && op->peer->od->mcast_info.rtr.relay) { ovn_multicast_add(mcast_groups, &mc_mrouter_flood, op); } + + /* If this port is configured to always flood multicast reports + * add it to the MC_MROUTER_STATIC group. + */ + if (op->mcast_info.flood_reports) { + ovn_multicast_add(mcast_groups, &mc_mrouter_static, op); + op->od->mcast_info.sw.flood_reports = true; + } + + /* If this port is configured to always flood multicast traffic + * add it to the MC_STATIC group. + */ + if (op->mcast_info.flood) { + ovn_multicast_add(mcast_groups, &mc_static, op); + op->od->mcast_info.sw.flood_static = true; + } } } @@ -8967,8 +9122,13 @@ build_mcast_groups(struct northd_context *ctx, for (size_t i = 0; i < od->n_router_ports; i++) { struct ovn_port *router_port = od->router_ports[i]->peer; + /* If the router the port connects to doesn't have multicast + * relay enabled or if it was already configured to flood + * multicast traffic then skip it. + */ if (!router_port || !router_port->od || - !router_port->od->mcast_info.rtr.relay) { + !router_port->od->mcast_info.rtr.relay || + router_port->mcast_info.flood) { continue; } diff --git a/ovn-nb.xml b/ovn-nb.xml index b41b579..1504f8f 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -671,6 +671,26 @@ + +

    + These options apply when the port is part of a logical switch + which has + :mcast_snoop set to true. +

    + + + If set to true, multicast packets (except reports) are + unconditionally forwarded to the specific port. + + + + If set to true, multicast reports are unconditionally + forwarded to the specific port. + + + @@ -2005,6 +2025,19 @@ + +

    + If set to true, multicast traffic (including reports) + are unconditionally forwarded to the specific port. +

    + +

    + This option applies when the port is part of a logical router which + has :mcast_relay set + to true. +

    +
    diff --git a/tests/ovn.at b/tests/ovn.at index 04898dd..f03e701 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -15122,7 +15122,6 @@ OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_empty]) # Flush IGMP groups. ovn-sbctl ip-multicast-flush sw1 -ovn-nbctl --wait=hv -t 3 sync OVS_WAIT_UNTIL([ total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l` test "${total_entries}" = "0" @@ -15174,12 +15173,12 @@ send_ip_multicast_pkt hv2-vif4 hv2 \ # Sleep a bit to make sure no traffic is received and then check. sleep 1 OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected_empty]) -OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_empty]) -OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected_empty]) +OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [expected_empty]) +OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [expected_empty]) # Enable IGMP relay on rtr @@ -15250,6 +15249,82 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [expected_empty]) OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [expected_empty]) +# Flush IGMP groups. +ovn-sbctl ip-multicast-flush sw1 +ovn-sbctl ip-multicast-flush sw2 +ovn-sbctl ip-multicast-flush sw3 +OVS_WAIT_UNTIL([ + total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l` + test "${total_entries}" = "0" +]) + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +as hv1 reset_pcap_file hv1-vif2 hv1/vif2 +as hv1 reset_pcap_file hv1-vif3 hv1/vif3 +as hv1 reset_pcap_file hv1-vif4 hv1/vif4 +as hv2 reset_pcap_file hv2-vif1 hv2/vif1 +as hv2 reset_pcap_file hv2-vif2 hv2/vif2 +as hv2 reset_pcap_file hv2-vif3 hv2/vif3 +as hv2 reset_pcap_file hv2-vif4 hv2/vif4 + +truncate -s 0 expected_empty +truncate -s 0 expected_switched +truncate -s 0 expected_routed +truncate -s 0 expected_reports + +# Enable mcast_flood on sw1-p11 +ovn-nbctl set Logical_Switch_Port sw1-p11 options:mcast_flood='true' + +# Enable mcast_flood_reports on sw1-p21 +ovn-nbctl set Logical_Switch_Port sw1-p21 options:mcast_flood_reports='true' +# Enable mcast_flood on rtr-sw2 +ovn-nbctl set Logical_Router_Port rtr-sw2 options:mcast_flood='true' +# Enable mcast_flood on sw2-p1 +ovn-nbctl set Logical_Switch_Port sw2-p1 options:mcast_flood='true' + +ovn-nbctl --wait=hv sync + +# Inject IGMP Join for 239.0.1.68 on sw1-p12. +send_igmp_v3_report hv1-vif2 hv1 \ + 000000000001 $(ip_to_hex 10 0 0 1) f9f8 \ + $(ip_to_hex 239 0 1 68) 04 e9b9 \ + expected_reports + +# Check that the IGMP Group is learned. +OVS_WAIT_UNTIL([ + total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l` + test "${total_entries}" = "1" +]) + +# Send traffic from sw1-p21 +send_ip_multicast_pkt hv2-vif1 hv2 \ + 000000000001 01005e000144 \ + $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \ + e518e518000a3b3a0000 +store_ip_multicast_pkt \ + 000000000001 01005e000144 \ + $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \ + e518e518000a3b3a0000 expected_switched +store_ip_multicast_pkt \ + 000000000200 01005e000144 \ + $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 1f cb70 11 \ + e518e518000a3b3a0000 expected_routed + +# Sleep a bit to make sure no duplicate traffic is received +sleep 1 + +# Check that traffic is switched to sw1-p11 and sw1-p12 +# Check that IGMP join is flooded on sw1-p21 +# Check that traffic is routed by rtr to rtr-sw2 and then switched to sw2-p1 +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected_switched]) +OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [expected_switched]) +OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected_routed]) +OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [expected_empty]) +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected_reports]) +OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [expected_empty]) +OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_empty]) +OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [expected_empty]) + OVN_CLEANUP([hv1], [hv2]) AT_CLEANUP