|
|
bbaaef |
From 5e165afe5eca8e093879df006a6d61be2cbdda53 Mon Sep 17 00:00:00 2001
|
|
|
bbaaef |
From: Dumitru Ceara <dceara@redhat.com>
|
|
|
bbaaef |
Date: Fri, 16 Aug 2019 14:20:45 +0200
|
|
|
bbaaef |
Subject: [PATCH 2/4] ovn-northd: Add IGMP Relay support
|
|
|
bbaaef |
|
|
|
bbaaef |
Add a new configuration option 'mcast_relay' to the Logical_Router:options
|
|
|
bbaaef |
in the OVN Northbound database.
|
|
|
bbaaef |
|
|
|
bbaaef |
If a router is configured with 'mcast_relay' enabled then ovn-northd
|
|
|
bbaaef |
will install Logical_Flows to allow IP multicast traffic to be routed
|
|
|
bbaaef |
between Logical_Switches. The logical router will aggregate all IGMP
|
|
|
bbaaef |
groups from attached logical switches and modify the routing pipeline in
|
|
|
bbaaef |
the following way:
|
|
|
bbaaef |
- Table S_ROUTER_IN_IP_INPUT: add flow allowing IP multicast traffic
|
|
|
bbaaef |
if mcast_relay is enabled on the datapath.
|
|
|
bbaaef |
- Table S_ROUTER_IN_IP_ROUTING: add flow matching the group address,
|
|
|
bbaaef |
update TTL and set outport="<Multicast_Group> associated with the
|
|
|
bbaaef |
IGMP group". Continue to next table.
|
|
|
bbaaef |
- Table S_ROUTER_IN_ARP_RESOLVE: bypass ARP resolve for IP multicast
|
|
|
bbaaef |
traffic and continue to next table.
|
|
|
bbaaef |
- Table S_ROUTER_OUT_DELIVERY: add flow matching IP multicast traffic
|
|
|
bbaaef |
and set ETH.SRC to the MAC address of the logical port on which
|
|
|
bbaaef |
traffic is forwarded.
|
|
|
bbaaef |
|
|
|
bbaaef |
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
|
|
|
bbaaef |
Acked-by: Mark Michelson <mmichels@redhat.com>
|
|
|
bbaaef |
Signed-off-by: Numan Siddique <nusiddiq@redhat.com>
|
|
|
bbaaef |
|
|
|
bbaaef |
(cherry-picked from ovn commit 5d1527b11e9420a36adc2410f78be6b6674c098e)
|
|
|
bbaaef |
---
|
|
|
bbaaef |
NEWS | 1 +
|
|
|
bbaaef |
ovn/lib/logical-fields.c | 2 +
|
|
|
bbaaef |
ovn/lib/mcast-group-index.h | 13 +-
|
|
|
bbaaef |
ovn/northd/ovn-northd.8.xml | 79 +++++-
|
|
|
bbaaef |
ovn/northd/ovn-northd.c | 499 +++++++++++++++++++++++++++---------
|
|
|
bbaaef |
ovn/ovn-nb.xml | 6 +
|
|
|
bbaaef |
ovn/ovn-sb.xml | 2 +
|
|
|
bbaaef |
tests/ovn.at | 199 ++++++++++++--
|
|
|
bbaaef |
8 files changed, 650 insertions(+), 151 deletions(-)
|
|
|
bbaaef |
|
|
|
bbaaef |
diff --git a/NEWS b/NEWS
|
|
|
bbaaef |
index c81890b7e..754ac2e71 100644
|
|
|
bbaaef |
--- a/NEWS
|
|
|
bbaaef |
+++ b/NEWS
|
|
|
bbaaef |
@@ -64,6 +64,7 @@ v2.12.0 - 03 Sep 2019
|
|
|
bbaaef |
members of the same transport zone(s).
|
|
|
bbaaef |
* Support for IGMP Snooping and IGMP Querier.
|
|
|
bbaaef |
* Support for new logical switch port type - 'virtual'.
|
|
|
bbaaef |
+ * Support for IGMP Snooping/Querier and Relay.
|
|
|
bbaaef |
- New QoS type "linux-netem" on Linux.
|
|
|
bbaaef |
- Added support for TLS Server Name Indication (SNI).
|
|
|
bbaaef |
- Linux datapath:
|
|
|
bbaaef |
diff --git a/ovn/lib/logical-fields.c b/ovn/lib/logical-fields.c
|
|
|
bbaaef |
index 4ad5bf481..8fb591c0a 100644
|
|
|
bbaaef |
--- a/ovn/lib/logical-fields.c
|
|
|
bbaaef |
+++ b/ovn/lib/logical-fields.c
|
|
|
bbaaef |
@@ -156,6 +156,8 @@ ovn_init_symtab(struct shash *symtab)
|
|
|
bbaaef |
|
|
|
bbaaef |
expr_symtab_add_field(symtab, "ip4.src", MFF_IPV4_SRC, "ip4", false);
|
|
|
bbaaef |
expr_symtab_add_field(symtab, "ip4.dst", MFF_IPV4_DST, "ip4", false);
|
|
|
bbaaef |
+ expr_symtab_add_predicate(symtab, "ip4.src_mcast",
|
|
|
bbaaef |
+ "ip4.src[28..31] == 0xe");
|
|
|
bbaaef |
expr_symtab_add_predicate(symtab, "ip4.mcast", "ip4.dst[28..31] == 0xe");
|
|
|
bbaaef |
|
|
|
bbaaef |
expr_symtab_add_predicate(symtab, "icmp4", "ip4 && ip.proto == 1");
|
|
|
bbaaef |
diff --git a/ovn/lib/mcast-group-index.h b/ovn/lib/mcast-group-index.h
|
|
|
bbaaef |
index 859e6a72f..6249cac99 100644
|
|
|
bbaaef |
--- a/ovn/lib/mcast-group-index.h
|
|
|
bbaaef |
+++ b/ovn/lib/mcast-group-index.h
|
|
|
bbaaef |
@@ -20,8 +20,17 @@ struct ovsdb_idl;
|
|
|
bbaaef |
|
|
|
bbaaef |
struct sbrec_datapath_binding;
|
|
|
bbaaef |
|
|
|
bbaaef |
-#define OVN_MCAST_FLOOD_TUNNEL_KEY 65535
|
|
|
bbaaef |
-#define OVN_MCAST_UNKNOWN_TUNNEL_KEY (OVN_MCAST_FLOOD_TUNNEL_KEY - 1)
|
|
|
bbaaef |
+#define OVN_MIN_MULTICAST 32768
|
|
|
bbaaef |
+#define OVN_MAX_MULTICAST 65535
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+enum ovn_mcast_tunnel_keys {
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ OVN_MCAST_FLOOD_TUNNEL_KEY = OVN_MIN_MULTICAST,
|
|
|
bbaaef |
+ OVN_MCAST_UNKNOWN_TUNNEL_KEY,
|
|
|
bbaaef |
+ OVN_MCAST_MROUTER_FLOOD_TUNNEL_KEY,
|
|
|
bbaaef |
+ OVN_MIN_IP_MULTICAST,
|
|
|
bbaaef |
+ OVN_MAX_IP_MULTICAST = OVN_MAX_MULTICAST,
|
|
|
bbaaef |
+};
|
|
|
bbaaef |
|
|
|
bbaaef |
struct ovsdb_idl_index *mcast_group_index_create(struct ovsdb_idl *);
|
|
|
bbaaef |
const struct sbrec_multicast_group *
|
|
|
bbaaef |
diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
|
|
|
bbaaef |
index 0435dae26..ec2b6454c 100644
|
|
|
bbaaef |
--- a/ovn/northd/ovn-northd.8.xml
|
|
|
bbaaef |
+++ b/ovn/northd/ovn-northd.8.xml
|
|
|
bbaaef |
@@ -952,10 +952,40 @@ output;
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
- A priority-100 flow that outputs all packets with an Ethernet broadcast
|
|
|
bbaaef |
+ A priority-100 flow that punts all IGMP packets to
|
|
|
bbaaef |
+ ovn-controller if IGMP snooping is enabled on the
|
|
|
bbaaef |
+ logical switch.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ Priority-90 flows that forward registered IP multicast traffic to
|
|
|
bbaaef |
+ their corresponding multicast group, which ovn-northd
|
|
|
bbaaef |
+ creates based on learnt <ref table="IGMP_Group" db="OVN_Southbound"/>
|
|
|
bbaaef |
+ entries. The flows also forward packets to the
|
|
|
bbaaef |
+ MC_MROUTER_FLOOD multicast group, which
|
|
|
bbaaef |
+ ovn-nortdh populates with all the logical ports that
|
|
|
bbaaef |
+ are connected to logical routers with
|
|
|
bbaaef |
+ <ref column="options" table="Logical_Router"/>:mcast_relay='true'.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ A priority-85 flow that forwards all IP multicast traffic destined to
|
|
|
bbaaef |
+ 224.0.0.X to the MC_FLOOD multicast group, which
|
|
|
bbaaef |
+ ovn-northd populates with all enabled logical ports.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ A priority-80 flow that forwards all unregistered IP multicast traffic
|
|
|
bbaaef |
+ to the MC_MROUTER_FLOOD multicast group, if any.
|
|
|
bbaaef |
+ Otherwise the flow drops all unregistered IP multicast packets. This
|
|
|
bbaaef |
+ flow is added only if
|
|
|
bbaaef |
+ table="Logical_Switch"/>:mcast_flood_unregistered='false'.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ A priority-70 flow that outputs all packets with an Ethernet broadcast
|
|
|
bbaaef |
or multicast eth.dst to the MC_FLOOD
|
|
|
bbaaef |
- multicast group, which ovn-northd populates with all
|
|
|
bbaaef |
- enabled logical ports.
|
|
|
bbaaef |
+ multicast group.
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
@@ -1236,6 +1266,14 @@ output;
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ A priority-95 flow allows IP multicast traffic if
|
|
|
bbaaef |
+ <ref column="options" table="Logical_Router"/>:mcast_relay='true',
|
|
|
bbaaef |
+ otherwise drops it.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
ICMP echo reply. These flows reply to ICMP echo requests received
|
|
|
bbaaef |
@@ -1982,6 +2020,16 @@ output;
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ Priority-500 flows that match IP multicast traffic destined to
|
|
|
bbaaef |
+ groups registered on any of the attached switches and sets
|
|
|
bbaaef |
+ outport to the associated multicast group that will
|
|
|
bbaaef |
+ eventually flood the traffic to all interested attached logical
|
|
|
bbaaef |
+ switches. The flows also decrement TTL.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
For distributed logical routers where one of the logical router
|
|
|
bbaaef |
@@ -2115,6 +2163,15 @@ next;
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ A priority-500 flow that matches IP multicast traffic that was
|
|
|
bbaaef |
+ allowed in the routing pipeline. For this kind of traffic the
|
|
|
bbaaef |
+ outport was already set so the flow just advances to
|
|
|
bbaaef |
+ the next table.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
For distributed logical routers where one of the logical router
|
|
|
bbaaef |
@@ -2684,9 +2741,19 @@ clone {
|
|
|
bbaaef |
Egress Table 3: Delivery
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
- Packets that reach this table are ready for delivery. It contains
|
|
|
bbaaef |
- priority-100 logical flows that match packets on each enabled logical
|
|
|
bbaaef |
- router port, with action output; .
|
|
|
bbaaef |
+ Packets that reach this table are ready for delivery. It contains:
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ Priority-110 logical flows that match IP multicast packets on each
|
|
|
bbaaef |
+ enabled logical router port and modify the Ethernet source address
|
|
|
bbaaef |
+ of the packets to the Ethernet address of the port and then execute
|
|
|
bbaaef |
+ action output; .
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ Priority-100 logical flows that match packets on each enabled
|
|
|
bbaaef |
+ logical router port, with action output; .
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+
|
|
|
bbaaef |
|
|
|
bbaaef |
|
|
|
bbaaef |
</manpage>
|
|
|
bbaaef |
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
|
|
|
bbaaef |
index d81cfd893..83a7ec14f 100644
|
|
|
bbaaef |
--- a/ovn/northd/ovn-northd.c
|
|
|
bbaaef |
+++ b/ovn/northd/ovn-northd.c
|
|
|
bbaaef |
@@ -440,32 +440,52 @@ struct ipam_info {
|
|
|
bbaaef |
bool mac_only;
|
|
|
bbaaef |
};
|
|
|
bbaaef |
|
|
|
bbaaef |
-#define OVN_MIN_MULTICAST 32768
|
|
|
bbaaef |
-#define OVN_MAX_MULTICAST OVN_MCAST_FLOOD_TUNNEL_KEY
|
|
|
bbaaef |
-BUILD_ASSERT_DECL(OVN_MIN_MULTICAST < OVN_MAX_MULTICAST);
|
|
|
bbaaef |
-
|
|
|
bbaaef |
-#define OVN_MIN_IP_MULTICAST OVN_MIN_MULTICAST
|
|
|
bbaaef |
-#define OVN_MAX_IP_MULTICAST (OVN_MCAST_UNKNOWN_TUNNEL_KEY - 1)
|
|
|
bbaaef |
-BUILD_ASSERT_DECL(OVN_MAX_IP_MULTICAST >= OVN_MIN_MULTICAST);
|
|
|
bbaaef |
-
|
|
|
bbaaef |
/*
|
|
|
bbaaef |
* Multicast snooping and querier per datapath configuration.
|
|
|
bbaaef |
*/
|
|
|
bbaaef |
+struct mcast_switch_info {
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ bool enabled; /* True if snooping enabled. */
|
|
|
bbaaef |
+ bool querier; /* True if querier enabled. */
|
|
|
bbaaef |
+ bool flood_unregistered; /* True if unregistered multicast should be
|
|
|
bbaaef |
+ * flooded.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ bool flood_relay; /* True if the switch is connected to a
|
|
|
bbaaef |
+ * multicast router and unregistered multicast
|
|
|
bbaaef |
+ * should be flooded to the mrouter. Only
|
|
|
bbaaef |
+ * applicable if flood_unregistered == false.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ int64_t table_size; /* Max number of IP multicast groups. */
|
|
|
bbaaef |
+ int64_t idle_timeout; /* Timeout after which an idle group is
|
|
|
bbaaef |
+ * flushed.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ int64_t query_interval; /* Interval between multicast queries. */
|
|
|
bbaaef |
+ char *eth_src; /* ETH src address of the multicast queries. */
|
|
|
bbaaef |
+ char *ipv4_src; /* IP src address of the multicast queries. */
|
|
|
bbaaef |
+ int64_t query_max_response; /* Expected time after which reports should
|
|
|
bbaaef |
+ * be received for queries that were sent out.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ uint32_t active_flows; /* Current number of active IP multicast
|
|
|
bbaaef |
+ * flows.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+};
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+struct mcast_router_info {
|
|
|
bbaaef |
+ bool relay; /* True if the router should relay IP multicast. */
|
|
|
bbaaef |
+};
|
|
|
bbaaef |
+
|
|
|
bbaaef |
struct mcast_info {
|
|
|
bbaaef |
- bool enabled;
|
|
|
bbaaef |
- bool querier;
|
|
|
bbaaef |
- bool flood_unregistered;
|
|
|
bbaaef |
-
|
|
|
bbaaef |
- int64_t table_size;
|
|
|
bbaaef |
- int64_t idle_timeout;
|
|
|
bbaaef |
- int64_t query_interval;
|
|
|
bbaaef |
- char *eth_src;
|
|
|
bbaaef |
- char *ipv4_src;
|
|
|
bbaaef |
- int64_t query_max_response;
|
|
|
bbaaef |
-
|
|
|
bbaaef |
- struct hmap group_tnlids;
|
|
|
bbaaef |
- uint32_t group_tnlid_hint;
|
|
|
bbaaef |
- uint32_t active_flows;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ struct hmap group_tnlids; /* Group tunnel IDs in use on this DP. */
|
|
|
bbaaef |
+ uint32_t group_tnlid_hint; /* Hint for allocating next group tunnel ID. */
|
|
|
bbaaef |
+ struct ovs_list groups; /* List of groups learnt on this DP. */
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ union {
|
|
|
bbaaef |
+ struct mcast_switch_info sw; /* Switch specific multicast info. */
|
|
|
bbaaef |
+ struct mcast_router_info rtr; /* Router specific multicast info. */
|
|
|
bbaaef |
+ };
|
|
|
bbaaef |
};
|
|
|
bbaaef |
|
|
|
bbaaef |
static uint32_t
|
|
|
bbaaef |
@@ -566,6 +586,7 @@ ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
static void ovn_ls_port_group_destroy(struct hmap *nb_pgs);
|
|
|
bbaaef |
+static void destroy_mcast_info_for_datapath(struct ovn_datapath *od);
|
|
|
bbaaef |
|
|
|
bbaaef |
static void
|
|
|
bbaaef |
ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
|
|
|
bbaaef |
@@ -579,12 +600,7 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
|
|
|
bbaaef |
bitmap_free(od->ipam_info.allocated_ipv4s);
|
|
|
bbaaef |
free(od->router_ports);
|
|
|
bbaaef |
ovn_ls_port_group_destroy(&od->nb_pgs);
|
|
|
bbaaef |
-
|
|
|
bbaaef |
- if (od->nbs) {
|
|
|
bbaaef |
- free(od->mcast_info.eth_src);
|
|
|
bbaaef |
- free(od->mcast_info.ipv4_src);
|
|
|
bbaaef |
- destroy_tnlids(&od->mcast_info.group_tnlids);
|
|
|
bbaaef |
- }
|
|
|
bbaaef |
+ destroy_mcast_info_for_datapath(od);
|
|
|
bbaaef |
|
|
|
bbaaef |
free(od);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
@@ -721,23 +737,28 @@ init_ipam_info_for_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
static void
|
|
|
bbaaef |
-init_mcast_info_for_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
+init_mcast_info_for_router_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
{
|
|
|
bbaaef |
- if (!od->nbs) {
|
|
|
bbaaef |
- return;
|
|
|
bbaaef |
- }
|
|
|
bbaaef |
+ struct mcast_router_info *mcast_rtr_info = &od->mcast_info.rtr;
|
|
|
bbaaef |
|
|
|
bbaaef |
- struct mcast_info *mcast_info = &od->mcast_info;
|
|
|
bbaaef |
+ mcast_rtr_info->relay = smap_get_bool(&od->nbr->options, "mcast_relay",
|
|
|
bbaaef |
+ false);
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
|
|
|
bbaaef |
- mcast_info->enabled =
|
|
|
bbaaef |
+static void
|
|
|
bbaaef |
+init_mcast_info_for_switch_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ mcast_sw_info->enabled =
|
|
|
bbaaef |
smap_get_bool(&od->nbs->other_config, "mcast_snoop", false);
|
|
|
bbaaef |
- mcast_info->querier =
|
|
|
bbaaef |
+ mcast_sw_info->querier =
|
|
|
bbaaef |
smap_get_bool(&od->nbs->other_config, "mcast_querier", true);
|
|
|
bbaaef |
- mcast_info->flood_unregistered =
|
|
|
bbaaef |
+ mcast_sw_info->flood_unregistered =
|
|
|
bbaaef |
smap_get_bool(&od->nbs->other_config, "mcast_flood_unregistered",
|
|
|
bbaaef |
false);
|
|
|
bbaaef |
|
|
|
bbaaef |
- mcast_info->table_size =
|
|
|
bbaaef |
+ mcast_sw_info->table_size =
|
|
|
bbaaef |
smap_get_ullong(&od->nbs->other_config, "mcast_table_size",
|
|
|
bbaaef |
OVN_MCAST_DEFAULT_MAX_ENTRIES);
|
|
|
bbaaef |
|
|
|
bbaaef |
@@ -749,54 +770,94 @@ init_mcast_info_for_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
} else if (idle_timeout > OVN_MCAST_MAX_IDLE_TIMEOUT_S) {
|
|
|
bbaaef |
idle_timeout = OVN_MCAST_MAX_IDLE_TIMEOUT_S;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
- mcast_info->idle_timeout = idle_timeout;
|
|
|
bbaaef |
+ mcast_sw_info->idle_timeout = idle_timeout;
|
|
|
bbaaef |
|
|
|
bbaaef |
uint32_t query_interval =
|
|
|
bbaaef |
smap_get_ullong(&od->nbs->other_config, "mcast_query_interval",
|
|
|
bbaaef |
- mcast_info->idle_timeout / 2);
|
|
|
bbaaef |
+ mcast_sw_info->idle_timeout / 2);
|
|
|
bbaaef |
if (query_interval < OVN_MCAST_MIN_QUERY_INTERVAL_S) {
|
|
|
bbaaef |
query_interval = OVN_MCAST_MIN_QUERY_INTERVAL_S;
|
|
|
bbaaef |
} else if (query_interval > OVN_MCAST_MAX_QUERY_INTERVAL_S) {
|
|
|
bbaaef |
query_interval = OVN_MCAST_MAX_QUERY_INTERVAL_S;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
- mcast_info->query_interval = query_interval;
|
|
|
bbaaef |
+ mcast_sw_info->query_interval = query_interval;
|
|
|
bbaaef |
|
|
|
bbaaef |
- mcast_info->eth_src =
|
|
|
bbaaef |
+ mcast_sw_info->eth_src =
|
|
|
bbaaef |
nullable_xstrdup(smap_get(&od->nbs->other_config, "mcast_eth_src"));
|
|
|
bbaaef |
- mcast_info->ipv4_src =
|
|
|
bbaaef |
+ mcast_sw_info->ipv4_src =
|
|
|
bbaaef |
nullable_xstrdup(smap_get(&od->nbs->other_config, "mcast_ip4_src"));
|
|
|
bbaaef |
|
|
|
bbaaef |
- mcast_info->query_max_response =
|
|
|
bbaaef |
+ mcast_sw_info->query_max_response =
|
|
|
bbaaef |
smap_get_ullong(&od->nbs->other_config, "mcast_query_max_response",
|
|
|
bbaaef |
OVN_MCAST_DEFAULT_QUERY_MAX_RESPONSE_S);
|
|
|
bbaaef |
|
|
|
bbaaef |
- hmap_init(&mcast_info->group_tnlids);
|
|
|
bbaaef |
- mcast_info->group_tnlid_hint = OVN_MIN_IP_MULTICAST;
|
|
|
bbaaef |
- mcast_info->active_flows = 0;
|
|
|
bbaaef |
+ mcast_sw_info->active_flows = 0;
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static void
|
|
|
bbaaef |
+init_mcast_info_for_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ if (!od->nbr && !od->nbs) {
|
|
|
bbaaef |
+ return;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ hmap_init(&od->mcast_info.group_tnlids);
|
|
|
bbaaef |
+ od->mcast_info.group_tnlid_hint = OVN_MIN_IP_MULTICAST;
|
|
|
bbaaef |
+ ovs_list_init(&od->mcast_info.groups);
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (od->nbs) {
|
|
|
bbaaef |
+ init_mcast_info_for_switch_datapath(od);
|
|
|
bbaaef |
+ } else {
|
|
|
bbaaef |
+ init_mcast_info_for_router_datapath(od);
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static void
|
|
|
bbaaef |
+destroy_mcast_info_for_switch_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ free(mcast_sw_info->eth_src);
|
|
|
bbaaef |
+ free(mcast_sw_info->ipv4_src);
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static void
|
|
|
bbaaef |
+destroy_mcast_info_for_datapath(struct ovn_datapath *od)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ if (!od->nbr && !od->nbs) {
|
|
|
bbaaef |
+ return;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (od->nbs) {
|
|
|
bbaaef |
+ destroy_mcast_info_for_switch_datapath(od);
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ destroy_tnlids(&od->mcast_info.group_tnlids);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
static void
|
|
|
bbaaef |
-store_mcast_info_for_datapath(const struct sbrec_ip_multicast *sb,
|
|
|
bbaaef |
- struct ovn_datapath *od)
|
|
|
bbaaef |
+store_mcast_info_for_switch_datapath(const struct sbrec_ip_multicast *sb,
|
|
|
bbaaef |
+ struct ovn_datapath *od)
|
|
|
bbaaef |
{
|
|
|
bbaaef |
- struct mcast_info *mcast_info = &od->mcast_info;
|
|
|
bbaaef |
+ struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
|
|
|
bbaaef |
|
|
|
bbaaef |
sbrec_ip_multicast_set_datapath(sb, od->sb);
|
|
|
bbaaef |
- sbrec_ip_multicast_set_enabled(sb, &mcast_info->enabled, 1);
|
|
|
bbaaef |
- sbrec_ip_multicast_set_querier(sb, &mcast_info->querier, 1);
|
|
|
bbaaef |
- sbrec_ip_multicast_set_table_size(sb, &mcast_info->table_size, 1);
|
|
|
bbaaef |
- sbrec_ip_multicast_set_idle_timeout(sb, &mcast_info->idle_timeout, 1);
|
|
|
bbaaef |
+ sbrec_ip_multicast_set_enabled(sb, &mcast_sw_info->enabled, 1);
|
|
|
bbaaef |
+ sbrec_ip_multicast_set_querier(sb, &mcast_sw_info->querier, 1);
|
|
|
bbaaef |
+ sbrec_ip_multicast_set_table_size(sb, &mcast_sw_info->table_size, 1);
|
|
|
bbaaef |
+ sbrec_ip_multicast_set_idle_timeout(sb, &mcast_sw_info->idle_timeout, 1);
|
|
|
bbaaef |
sbrec_ip_multicast_set_query_interval(sb,
|
|
|
bbaaef |
- &mcast_info->query_interval, 1);
|
|
|
bbaaef |
+ &mcast_sw_info->query_interval, 1);
|
|
|
bbaaef |
sbrec_ip_multicast_set_query_max_resp(sb,
|
|
|
bbaaef |
- &mcast_info->query_max_response, 1);
|
|
|
bbaaef |
+ &mcast_sw_info->query_max_response,
|
|
|
bbaaef |
+ 1);
|
|
|
bbaaef |
|
|
|
bbaaef |
- if (mcast_info->eth_src) {
|
|
|
bbaaef |
- sbrec_ip_multicast_set_eth_src(sb, mcast_info->eth_src);
|
|
|
bbaaef |
+ if (mcast_sw_info->eth_src) {
|
|
|
bbaaef |
+ sbrec_ip_multicast_set_eth_src(sb, mcast_sw_info->eth_src);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
- if (mcast_info->ipv4_src) {
|
|
|
bbaaef |
- sbrec_ip_multicast_set_ip4_src(sb, mcast_info->ipv4_src);
|
|
|
bbaaef |
+ if (mcast_sw_info->ipv4_src) {
|
|
|
bbaaef |
+ sbrec_ip_multicast_set_ip4_src(sb, mcast_sw_info->ipv4_src);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
@@ -913,6 +974,7 @@ join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
|
|
|
bbaaef |
NULL, nbr, NULL);
|
|
|
bbaaef |
ovs_list_push_back(nb_only, &od->list);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
+ init_mcast_info_for_datapath(od);
|
|
|
bbaaef |
ovs_list_push_back(lr_list, &od->lr_list);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
@@ -2006,6 +2068,13 @@ join_logical_ports(struct northd_context *ctx,
|
|
|
bbaaef |
break;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ /* If the router is multicast enabled then set relay on the switch
|
|
|
bbaaef |
+ * datapath.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ if (peer->od && peer->od->mcast_info.rtr.relay) {
|
|
|
bbaaef |
+ op->od->mcast_info.sw.flood_relay = true;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
} else if (op->nbrp && op->nbrp->peer && !op->derived) {
|
|
|
bbaaef |
struct ovn_port *peer = ovn_port_find(ports, op->nbrp->peer);
|
|
|
bbaaef |
if (peer) {
|
|
|
bbaaef |
@@ -2861,6 +2930,10 @@ struct multicast_group {
|
|
|
bbaaef |
static const struct multicast_group mc_flood =
|
|
|
bbaaef |
{ MC_FLOOD, OVN_MCAST_FLOOD_TUNNEL_KEY };
|
|
|
bbaaef |
|
|
|
bbaaef |
+#define MC_MROUTER_FLOOD "_MC_mrouter_flood"
|
|
|
bbaaef |
+static const struct multicast_group mc_mrouter_flood =
|
|
|
bbaaef |
+ { MC_MROUTER_FLOOD, OVN_MCAST_MROUTER_FLOOD_TUNNEL_KEY };
|
|
|
bbaaef |
+
|
|
|
bbaaef |
#define MC_UNKNOWN "_MC_unknown"
|
|
|
bbaaef |
static const struct multicast_group mc_unknown =
|
|
|
bbaaef |
{ MC_UNKNOWN, OVN_MCAST_UNKNOWN_TUNNEL_KEY };
|
|
|
bbaaef |
@@ -2970,7 +3043,8 @@ ovn_multicast_update_sbrec(const struct ovn_multicast *mc,
|
|
|
bbaaef |
*/
|
|
|
bbaaef |
struct ovn_igmp_group_entry {
|
|
|
bbaaef |
struct ovs_list list_node; /* Linkage in the list of entries. */
|
|
|
bbaaef |
- const struct sbrec_igmp_group *sb;
|
|
|
bbaaef |
+ size_t n_ports;
|
|
|
bbaaef |
+ struct ovn_port **ports;
|
|
|
bbaaef |
};
|
|
|
bbaaef |
|
|
|
bbaaef |
/*
|
|
|
bbaaef |
@@ -2979,12 +3053,13 @@ struct ovn_igmp_group_entry {
|
|
|
bbaaef |
*/
|
|
|
bbaaef |
struct ovn_igmp_group {
|
|
|
bbaaef |
struct hmap_node hmap_node; /* Index on 'datapath' and 'address'. */
|
|
|
bbaaef |
+ struct ovs_list list_node; /* Linkage in the per-dp igmp group list. */
|
|
|
bbaaef |
|
|
|
bbaaef |
struct ovn_datapath *datapath;
|
|
|
bbaaef |
struct in6_addr address; /* Multicast IPv6-mapped-IPv4 or IPv4 address. */
|
|
|
bbaaef |
struct multicast_group mcgroup;
|
|
|
bbaaef |
|
|
|
bbaaef |
- struct ovs_list sb_entries; /* List of SB entries for this group. */
|
|
|
bbaaef |
+ struct ovs_list entries; /* List of SB entries for this group. */
|
|
|
bbaaef |
};
|
|
|
bbaaef |
|
|
|
bbaaef |
static uint32_t
|
|
|
bbaaef |
@@ -3012,77 +3087,120 @@ ovn_igmp_group_find(struct hmap *igmp_groups,
|
|
|
bbaaef |
return NULL;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
-static void
|
|
|
bbaaef |
+static struct ovn_igmp_group *
|
|
|
bbaaef |
ovn_igmp_group_add(struct northd_context *ctx, struct hmap *igmp_groups,
|
|
|
bbaaef |
struct ovn_datapath *datapath,
|
|
|
bbaaef |
- const struct sbrec_igmp_group *sb_igmp_group)
|
|
|
bbaaef |
+ const struct in6_addr *address,
|
|
|
bbaaef |
+ const char *address_s)
|
|
|
bbaaef |
{
|
|
|
bbaaef |
- struct in6_addr group_address;
|
|
|
bbaaef |
- ovs_be32 ipv4;
|
|
|
bbaaef |
-
|
|
|
bbaaef |
- if (ip_parse(sb_igmp_group->address, &ipv4)) {
|
|
|
bbaaef |
- group_address = in6_addr_mapped_ipv4(ipv4);
|
|
|
bbaaef |
- } else if (!ipv6_parse(sb_igmp_group->address, &group_address)) {
|
|
|
bbaaef |
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
|
|
|
bbaaef |
- VLOG_WARN_RL(&rl, "invalid IGMP group address: %s",
|
|
|
bbaaef |
- sb_igmp_group->address);
|
|
|
bbaaef |
- return;
|
|
|
bbaaef |
- }
|
|
|
bbaaef |
-
|
|
|
bbaaef |
struct ovn_igmp_group *igmp_group =
|
|
|
bbaaef |
- ovn_igmp_group_find(igmp_groups, datapath, &group_address);
|
|
|
bbaaef |
+ ovn_igmp_group_find(igmp_groups, datapath, address);
|
|
|
bbaaef |
|
|
|
bbaaef |
if (!igmp_group) {
|
|
|
bbaaef |
igmp_group = xmalloc(sizeof *igmp_group);
|
|
|
bbaaef |
|
|
|
bbaaef |
const struct sbrec_multicast_group *mcgroup =
|
|
|
bbaaef |
- mcast_group_lookup(ctx->sbrec_mcast_group_by_name_dp,
|
|
|
bbaaef |
- sb_igmp_group->address, datapath->sb);
|
|
|
bbaaef |
+ mcast_group_lookup(ctx->sbrec_mcast_group_by_name_dp, address_s,
|
|
|
bbaaef |
+ datapath->sb);
|
|
|
bbaaef |
|
|
|
bbaaef |
igmp_group->datapath = datapath;
|
|
|
bbaaef |
- igmp_group->address = group_address;
|
|
|
bbaaef |
+ igmp_group->address = *address;
|
|
|
bbaaef |
if (mcgroup) {
|
|
|
bbaaef |
igmp_group->mcgroup.key = mcgroup->tunnel_key;
|
|
|
bbaaef |
add_tnlid(&datapath->mcast_info.group_tnlids, mcgroup->tunnel_key);
|
|
|
bbaaef |
} else {
|
|
|
bbaaef |
igmp_group->mcgroup.key = 0;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
- igmp_group->mcgroup.name = sb_igmp_group->address;
|
|
|
bbaaef |
- ovs_list_init(&igmp_group->sb_entries);
|
|
|
bbaaef |
+ igmp_group->mcgroup.name = address_s;
|
|
|
bbaaef |
+ ovs_list_init(&igmp_group->entries);
|
|
|
bbaaef |
|
|
|
bbaaef |
hmap_insert(igmp_groups, &igmp_group->hmap_node,
|
|
|
bbaaef |
- ovn_igmp_group_hash(datapath, &group_address));
|
|
|
bbaaef |
+ ovn_igmp_group_hash(datapath, address));
|
|
|
bbaaef |
+ ovs_list_push_back(&datapath->mcast_info.groups,
|
|
|
bbaaef |
+ &igmp_group->list_node);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
+ return igmp_group;
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static bool
|
|
|
bbaaef |
+ovn_igmp_group_get_address(const struct sbrec_igmp_group *sb_igmp_group,
|
|
|
bbaaef |
+ struct in6_addr *address)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ ovs_be32 ipv4;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (ip_parse(sb_igmp_group->address, &ipv4)) {
|
|
|
bbaaef |
+ *address = in6_addr_mapped_ipv4(ipv4);
|
|
|
bbaaef |
+ return true;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+ if (!ipv6_parse(sb_igmp_group->address, address)) {
|
|
|
bbaaef |
+ return false;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+ return true;
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static struct ovn_port **
|
|
|
bbaaef |
+ovn_igmp_group_get_ports(const struct sbrec_igmp_group *sb_igmp_group,
|
|
|
bbaaef |
+ size_t *n_ports, struct hmap *ovn_ports)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ struct ovn_port **ports = xmalloc(sb_igmp_group->n_ports * sizeof *ports);
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ *n_ports = 0;
|
|
|
bbaaef |
+ for (size_t i = 0; i < sb_igmp_group->n_ports; i++) {
|
|
|
bbaaef |
+ ports[(*n_ports)] =
|
|
|
bbaaef |
+ ovn_port_find(ovn_ports, sb_igmp_group->ports[i]->logical_port);
|
|
|
bbaaef |
+ if (ports[(*n_ports)]) {
|
|
|
bbaaef |
+ (*n_ports)++;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ return ports;
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static void
|
|
|
bbaaef |
+ovn_igmp_group_add_entry(struct ovn_igmp_group *igmp_group,
|
|
|
bbaaef |
+ struct ovn_port **ports, size_t n_ports)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
struct ovn_igmp_group_entry *entry = xmalloc(sizeof *entry);
|
|
|
bbaaef |
|
|
|
bbaaef |
- entry->sb = sb_igmp_group;
|
|
|
bbaaef |
- ovs_list_push_back(&igmp_group->sb_entries , &entry->list_node);
|
|
|
bbaaef |
+ entry->ports = ports;
|
|
|
bbaaef |
+ entry->n_ports = n_ports;
|
|
|
bbaaef |
+ ovs_list_push_back(&igmp_group->entries, &entry->list_node);
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static void
|
|
|
bbaaef |
+ovn_igmp_group_destroy_entry(struct ovn_igmp_group_entry *entry)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ free(entry->ports);
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+static bool
|
|
|
bbaaef |
+ovn_igmp_group_allocate_id(struct ovn_igmp_group *igmp_group)
|
|
|
bbaaef |
+{
|
|
|
bbaaef |
+ if (igmp_group->mcgroup.key == 0) {
|
|
|
bbaaef |
+ struct mcast_info *mcast_info = &igmp_group->datapath->mcast_info;
|
|
|
bbaaef |
+ igmp_group->mcgroup.key = ovn_mcast_group_allocate_key(mcast_info);
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (igmp_group->mcgroup.key == 0) {
|
|
|
bbaaef |
+ return false;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ return true;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
static void
|
|
|
bbaaef |
ovn_igmp_group_aggregate_ports(struct ovn_igmp_group *igmp_group,
|
|
|
bbaaef |
- struct hmap *ovn_ports,
|
|
|
bbaaef |
struct hmap *mcast_groups)
|
|
|
bbaaef |
{
|
|
|
bbaaef |
struct ovn_igmp_group_entry *entry;
|
|
|
bbaaef |
|
|
|
bbaaef |
- LIST_FOR_EACH_POP (entry, list_node, &igmp_group->sb_entries) {
|
|
|
bbaaef |
- size_t n_oports = 0;
|
|
|
bbaaef |
- struct ovn_port **oports =
|
|
|
bbaaef |
- xmalloc(entry->sb->n_ports * sizeof *oports);
|
|
|
bbaaef |
-
|
|
|
bbaaef |
- for (size_t i = 0; i < entry->sb->n_ports; i++) {
|
|
|
bbaaef |
- oports[n_oports] =
|
|
|
bbaaef |
- ovn_port_find(ovn_ports, entry->sb->ports[i]->logical_port);
|
|
|
bbaaef |
- if (oports[n_oports]) {
|
|
|
bbaaef |
- n_oports++;
|
|
|
bbaaef |
- }
|
|
|
bbaaef |
- }
|
|
|
bbaaef |
-
|
|
|
bbaaef |
+ LIST_FOR_EACH_POP (entry, list_node, &igmp_group->entries) {
|
|
|
bbaaef |
ovn_multicast_add_ports(mcast_groups, igmp_group->datapath,
|
|
|
bbaaef |
- &igmp_group->mcgroup, oports, n_oports);
|
|
|
bbaaef |
- free(oports);
|
|
|
bbaaef |
+ &igmp_group->mcgroup, entry->ports,
|
|
|
bbaaef |
+ entry->n_ports);
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ ovn_igmp_group_destroy_entry(entry);
|
|
|
bbaaef |
free(entry);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
@@ -3094,10 +3212,12 @@ ovn_igmp_group_destroy(struct hmap *igmp_groups,
|
|
|
bbaaef |
if (igmp_group) {
|
|
|
bbaaef |
struct ovn_igmp_group_entry *entry;
|
|
|
bbaaef |
|
|
|
bbaaef |
- LIST_FOR_EACH_POP (entry, list_node, &igmp_group->sb_entries) {
|
|
|
bbaaef |
+ LIST_FOR_EACH_POP (entry, list_node, &igmp_group->entries) {
|
|
|
bbaaef |
+ ovn_igmp_group_destroy_entry(entry);
|
|
|
bbaaef |
free(entry);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
hmap_remove(igmp_groups, &igmp_group->hmap_node);
|
|
|
bbaaef |
+ ovs_list_remove(&igmp_group->list_node);
|
|
|
bbaaef |
free(igmp_group);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
@@ -5404,7 +5524,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
- if (od->mcast_info.enabled) {
|
|
|
bbaaef |
+ struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (mcast_sw_info->enabled) {
|
|
|
bbaaef |
/* Punt IGMP traffic to controller. */
|
|
|
bbaaef |
ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
|
|
|
bbaaef |
"ip4 && ip.proto == 2", "igmp;");
|
|
|
bbaaef |
@@ -5417,9 +5539,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
"outport = \""MC_FLOOD"\"; output;");
|
|
|
bbaaef |
|
|
|
bbaaef |
/* Drop unregistered IP multicast if not allowed. */
|
|
|
bbaaef |
- if (!od->mcast_info.flood_unregistered) {
|
|
|
bbaaef |
- ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80,
|
|
|
bbaaef |
- "ip4 && ip4.mcast", "drop;");
|
|
|
bbaaef |
+ if (!mcast_sw_info->flood_unregistered) {
|
|
|
bbaaef |
+ /* Forward unregistered IP multicast to mrouter (if any). */
|
|
|
bbaaef |
+ if (mcast_sw_info->flood_relay) {
|
|
|
bbaaef |
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80,
|
|
|
bbaaef |
+ "ip4 && ip4.mcast",
|
|
|
bbaaef |
+ "outport = \""MC_MROUTER_FLOOD"\"; output;");
|
|
|
bbaaef |
+ } else {
|
|
|
bbaaef |
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80,
|
|
|
bbaaef |
+ "ip4 && ip4.mcast", "drop;");
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
@@ -5436,18 +5565,26 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
- struct mcast_info *mcast_info = &igmp_group->datapath->mcast_info;
|
|
|
bbaaef |
+ struct mcast_switch_info *mcast_sw_info =
|
|
|
bbaaef |
+ &igmp_group->datapath->mcast_info.sw;
|
|
|
bbaaef |
|
|
|
bbaaef |
- if (mcast_info->active_flows >= mcast_info->table_size) {
|
|
|
bbaaef |
+ if (mcast_sw_info->active_flows >= mcast_sw_info->table_size) {
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
- mcast_info->active_flows++;
|
|
|
bbaaef |
+ mcast_sw_info->active_flows++;
|
|
|
bbaaef |
|
|
|
bbaaef |
ds_clear(&match);
|
|
|
bbaaef |
ds_clear(&actions);
|
|
|
bbaaef |
|
|
|
bbaaef |
ds_put_format(&match, "eth.mcast && ip4 && ip4.dst == %s ",
|
|
|
bbaaef |
igmp_group->mcgroup.name);
|
|
|
bbaaef |
+ /* Also flood traffic to all multicast routers with relay enabled. */
|
|
|
bbaaef |
+ if (mcast_sw_info->flood_relay) {
|
|
|
bbaaef |
+ ds_put_cstr(&actions,
|
|
|
bbaaef |
+ "clone { "
|
|
|
bbaaef |
+ "outport = \""MC_MROUTER_FLOOD "\"; output; "
|
|
|
bbaaef |
+ "};");
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
ds_put_format(&actions, "outport = \"%s\"; output; ",
|
|
|
bbaaef |
igmp_group->mcgroup.name);
|
|
|
bbaaef |
|
|
|
bbaaef |
@@ -6293,7 +6430,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
* source or destination, and zero network source or destination
|
|
|
bbaaef |
* (priority 100). */
|
|
|
bbaaef |
ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 100,
|
|
|
bbaaef |
- "ip4.mcast || "
|
|
|
bbaaef |
+ "ip4.src_mcast ||"
|
|
|
bbaaef |
"ip4.src == 255.255.255.255 || "
|
|
|
bbaaef |
"ip4.src == 127.0.0.0/8 || "
|
|
|
bbaaef |
"ip4.dst == 127.0.0.0/8 || "
|
|
|
bbaaef |
@@ -6301,6 +6438,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
"ip4.dst == 0.0.0.0/8",
|
|
|
bbaaef |
"drop;");
|
|
|
bbaaef |
|
|
|
bbaaef |
+ /* Allow multicast if relay enabled (priority 95). */
|
|
|
bbaaef |
+ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 95, "ip4.mcast",
|
|
|
bbaaef |
+ od->mcast_info.rtr.relay ? "next;" : "drop;");
|
|
|
bbaaef |
+
|
|
|
bbaaef |
/* ARP reply handling. Use ARP replies to populate the logical
|
|
|
bbaaef |
* router's ARP table. */
|
|
|
bbaaef |
ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "arp.op == 2",
|
|
|
bbaaef |
@@ -7608,6 +7749,27 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
+ /* IP Multicast lookup. Here we set the output port, adjust TTL and
|
|
|
bbaaef |
+ * advance to next table (priority 500).
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ HMAP_FOR_EACH (od, key_node, datapaths) {
|
|
|
bbaaef |
+ if (!od->nbr || !od->mcast_info.rtr.relay) {
|
|
|
bbaaef |
+ continue;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+ struct ovn_igmp_group *igmp_group;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) {
|
|
|
bbaaef |
+ ds_clear(&match);
|
|
|
bbaaef |
+ ds_clear(&actions);
|
|
|
bbaaef |
+ ds_put_format(&match, "ip4 && ip4.dst == %s ",
|
|
|
bbaaef |
+ igmp_group->mcgroup.name);
|
|
|
bbaaef |
+ ds_put_format(&actions, "outport = \"%s\"; ip.ttl--; next;",
|
|
|
bbaaef |
+ igmp_group->mcgroup.name);
|
|
|
bbaaef |
+ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 500,
|
|
|
bbaaef |
+ ds_cstr(&match), ds_cstr(&actions));
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
/* Logical router ingress table 8: Policy.
|
|
|
bbaaef |
*
|
|
|
bbaaef |
* A packet that arrives at this table is an IP packet that should be
|
|
|
bbaaef |
@@ -7638,10 +7800,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
|
|
|
bbaaef |
/* Local router ingress table 9: ARP Resolution.
|
|
|
bbaaef |
*
|
|
|
bbaaef |
- * Any packet that reaches this table is an IP packet whose next-hop IP
|
|
|
bbaaef |
- * address is in reg0. (ip4.dst is the final destination.) This table
|
|
|
bbaaef |
- * resolves the IP address in reg0 into an output port in outport and an
|
|
|
bbaaef |
- * Ethernet address in eth.dst. */
|
|
|
bbaaef |
+ * Multicast packets already have the outport set so just advance to next
|
|
|
bbaaef |
+ * table (priority 500). */
|
|
|
bbaaef |
+ HMAP_FOR_EACH (od, key_node, datapaths) {
|
|
|
bbaaef |
+ if (!od->nbr) {
|
|
|
bbaaef |
+ continue;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500,
|
|
|
bbaaef |
+ "ip4.mcast", "next;");
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ /* Local router ingress table 9: ARP Resolution.
|
|
|
bbaaef |
+ *
|
|
|
bbaaef |
+ * Any unicast packet that reaches this table is an IP packet whose
|
|
|
bbaaef |
+ * next-hop IP address is in reg0. (ip4.dst is the final destination.)
|
|
|
bbaaef |
+ * This table resolves the IP address in reg0 into an output port in
|
|
|
bbaaef |
+ * outport and an Ethernet address in eth.dst.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
HMAP_FOR_EACH (op, key_node, ports) {
|
|
|
bbaaef |
if (op->nbsp && !lsp_is_enabled(op->nbsp)) {
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
@@ -8123,9 +8299,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;");
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
- /* Logical router egress table 1: Delivery (priority 100).
|
|
|
bbaaef |
+ /* Logical router egress table 1: Delivery (priority 100-110).
|
|
|
bbaaef |
*
|
|
|
bbaaef |
- * Priority 100 rules deliver packets to enabled logical ports. */
|
|
|
bbaaef |
+ * Priority 100 rules deliver packets to enabled logical ports.
|
|
|
bbaaef |
+ * Priority 110 rules match multicast packets and update the source
|
|
|
bbaaef |
+ * mac before delivering to enabled logical ports. IP multicast traffic
|
|
|
bbaaef |
+ * bypasses S_ROUTER_IN_IP_ROUTING route lookups.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
HMAP_FOR_EACH (op, key_node, ports) {
|
|
|
bbaaef |
if (!op->nbrp) {
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
@@ -8145,6 +8325,20 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
+ /* If multicast relay is enabled then also adjust source mac for IP
|
|
|
bbaaef |
+ * multicast traffic.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ if (op->od->mcast_info.rtr.relay) {
|
|
|
bbaaef |
+ ds_clear(&match);
|
|
|
bbaaef |
+ ds_clear(&actions);
|
|
|
bbaaef |
+ ds_put_format(&match, "ip4.mcast && outport == %s",
|
|
|
bbaaef |
+ op->json_key);
|
|
|
bbaaef |
+ ds_put_format(&actions, "eth.src = %s; output;",
|
|
|
bbaaef |
+ op->lrp_networks.ea_s);
|
|
|
bbaaef |
+ ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110,
|
|
|
bbaaef |
+ ds_cstr(&match), ds_cstr(&actions));
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
ds_clear(&match);
|
|
|
bbaaef |
ds_put_format(&match, "outport == %s", op->json_key);
|
|
|
bbaaef |
ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100,
|
|
|
bbaaef |
@@ -8696,7 +8890,7 @@ build_ip_mcast(struct northd_context *ctx, struct hmap *datapaths)
|
|
|
bbaaef |
if (!ip_mcast) {
|
|
|
bbaaef |
ip_mcast = sbrec_ip_multicast_insert(ctx->ovnsb_txn);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
- store_mcast_info_for_datapath(ip_mcast, od);
|
|
|
bbaaef |
+ store_mcast_info_for_switch_datapath(ip_mcast, od);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
/* Delete southbound records without northbound matches. */
|
|
|
bbaaef |
@@ -8728,6 +8922,14 @@ build_mcast_groups(struct northd_context *ctx,
|
|
|
bbaaef |
|
|
|
bbaaef |
if (lsp_is_enabled(op->nbsp)) {
|
|
|
bbaaef |
ovn_multicast_add(mcast_groups, &mc_flood, op);
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ /* If this port is connected to a multicast router then add it
|
|
|
bbaaef |
+ * to the MC_MROUTER_FLOOD group.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ if (op->od->mcast_info.sw.flood_relay && op->peer &&
|
|
|
bbaaef |
+ op->peer->od && op->peer->od->mcast_info.rtr.relay) {
|
|
|
bbaaef |
+ ovn_multicast_add(mcast_groups, &mc_mrouter_flood, op);
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
@@ -8750,10 +8952,61 @@ build_mcast_groups(struct northd_context *ctx,
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
+ struct in6_addr group_address;
|
|
|
bbaaef |
+ if (!ovn_igmp_group_get_address(sb_igmp, &group_address)) {
|
|
|
bbaaef |
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
|
|
|
bbaaef |
+ VLOG_WARN_RL(&rl, "invalid IGMP group address: %s",
|
|
|
bbaaef |
+ sb_igmp->address);
|
|
|
bbaaef |
+ continue;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
/* Add the IGMP group entry. Will also try to allocate an ID for it
|
|
|
bbaaef |
* if the multicast group already exists.
|
|
|
bbaaef |
*/
|
|
|
bbaaef |
- ovn_igmp_group_add(ctx, igmp_groups, od, sb_igmp);
|
|
|
bbaaef |
+ struct ovn_igmp_group *igmp_group =
|
|
|
bbaaef |
+ ovn_igmp_group_add(ctx, igmp_groups, od, &group_address,
|
|
|
bbaaef |
+ sb_igmp->address);
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ /* Extract the IGMP group ports from the SB entry and store them
|
|
|
bbaaef |
+ * in the IGMP group.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ size_t n_igmp_ports;
|
|
|
bbaaef |
+ struct ovn_port **igmp_ports =
|
|
|
bbaaef |
+ ovn_igmp_group_get_ports(sb_igmp, &n_igmp_ports, ports);
|
|
|
bbaaef |
+ ovn_igmp_group_add_entry(igmp_group, igmp_ports, n_igmp_ports);
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ /* Build IGMP groups for multicast routers with relay enabled. The router
|
|
|
bbaaef |
+ * IGMP groups are based on the groups learnt by their multicast enabled
|
|
|
bbaaef |
+ * peers.
|
|
|
bbaaef |
+ */
|
|
|
bbaaef |
+ struct ovn_datapath *od;
|
|
|
bbaaef |
+ HMAP_FOR_EACH (od, key_node, datapaths) {
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (ovs_list_is_empty(&od->mcast_info.groups)) {
|
|
|
bbaaef |
+ continue;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ for (size_t i = 0; i < od->n_router_ports; i++) {
|
|
|
bbaaef |
+ struct ovn_port *router_port = od->router_ports[i]->peer;
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ if (!router_port || !router_port->od ||
|
|
|
bbaaef |
+ !router_port->od->mcast_info.rtr.relay) {
|
|
|
bbaaef |
+ continue;
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ struct ovn_igmp_group *igmp_group;
|
|
|
bbaaef |
+ LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) {
|
|
|
bbaaef |
+ struct ovn_igmp_group *igmp_group_rtr =
|
|
|
bbaaef |
+ ovn_igmp_group_add(ctx, igmp_groups, router_port->od,
|
|
|
bbaaef |
+ &igmp_group->address,
|
|
|
bbaaef |
+ igmp_group->mcgroup.name);
|
|
|
bbaaef |
+ struct ovn_port **router_igmp_ports =
|
|
|
bbaaef |
+ xmalloc(sizeof *router_igmp_ports);
|
|
|
bbaaef |
+ router_igmp_ports[0] = router_port;
|
|
|
bbaaef |
+ ovn_igmp_group_add_entry(igmp_group_rtr, router_igmp_ports, 1);
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
+ }
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
/* Walk the aggregated IGMP groups and allocate IDs for new entries.
|
|
|
bbaaef |
@@ -8761,21 +9014,17 @@ build_mcast_groups(struct northd_context *ctx,
|
|
|
bbaaef |
*/
|
|
|
bbaaef |
struct ovn_igmp_group *igmp_group, *igmp_group_next;
|
|
|
bbaaef |
HMAP_FOR_EACH_SAFE (igmp_group, igmp_group_next, hmap_node, igmp_groups) {
|
|
|
bbaaef |
- if (igmp_group->mcgroup.key == 0) {
|
|
|
bbaaef |
- struct mcast_info *mcast_info = &igmp_group->datapath->mcast_info;
|
|
|
bbaaef |
- igmp_group->mcgroup.key = ovn_mcast_group_allocate_key(mcast_info);
|
|
|
bbaaef |
- }
|
|
|
bbaaef |
|
|
|
bbaaef |
- /* If we ran out of keys just destroy the entry. */
|
|
|
bbaaef |
- if (igmp_group->mcgroup.key == 0) {
|
|
|
bbaaef |
+ if (!ovn_igmp_group_allocate_id(igmp_group)) {
|
|
|
bbaaef |
+ /* If we ran out of keys just destroy the entry. */
|
|
|
bbaaef |
ovn_igmp_group_destroy(igmp_groups, igmp_group);
|
|
|
bbaaef |
continue;
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
- /* Aggregate the ports from all SB entries corresponding to this
|
|
|
bbaaef |
+ /* Aggregate the ports from all entries corresponding to this
|
|
|
bbaaef |
* group.
|
|
|
bbaaef |
*/
|
|
|
bbaaef |
- ovn_igmp_group_aggregate_ports(igmp_group, ports, mcast_groups);
|
|
|
bbaaef |
+ ovn_igmp_group_aggregate_ports(igmp_group, mcast_groups);
|
|
|
bbaaef |
}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
|
|
|
bbaaef |
index b457b6efc..c2472a04a 100644
|
|
|
bbaaef |
--- a/ovn/ovn-nb.xml
|
|
|
bbaaef |
+++ b/ovn/ovn-nb.xml
|
|
|
bbaaef |
@@ -1535,6 +1535,12 @@
|
|
|
bbaaef |
address.
|
|
|
bbaaef |
|
|
|
bbaaef |
</column>
|
|
|
bbaaef |
+ <column name="options" key="mcast_relay" type='{"type": "boolean"}'>
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ Enables/disables IP multicast relay between logical switches
|
|
|
bbaaef |
+ connected to the logical router. Default: False.
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ </column>
|
|
|
bbaaef |
</group>
|
|
|
bbaaef |
|
|
|
bbaaef |
<group title="Common Columns">
|
|
|
bbaaef |
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
|
|
|
bbaaef |
index 71bd08665..477e7bc7a 100644
|
|
|
bbaaef |
--- a/ovn/ovn-sb.xml
|
|
|
bbaaef |
+++ b/ovn/ovn-sb.xml
|
|
|
bbaaef |
@@ -1017,6 +1017,8 @@
|
|
|
bbaaef |
eth.mcast expands to eth.dst[40]
|
|
|
bbaaef |
vlan.present expands to vlan.tci[12]
|
|
|
bbaaef |
ip4 expands to eth.type == 0x800
|
|
|
bbaaef |
+ ip4.src_mcast expands to
|
|
|
bbaaef |
+ ip4.src[28..31] == 0xe
|
|
|
bbaaef |
ip4.mcast expands to ip4.dst[28..31] == 0xe
|
|
|
bbaaef |
ip6 expands to eth.type == 0x86dd
|
|
|
bbaaef |
ip expands to ip4 || ip6
|
|
|
bbaaef |
diff --git a/tests/ovn.at b/tests/ovn.at
|
|
|
bbaaef |
index 3f7e06cf5..df41a7549 100644
|
|
|
bbaaef |
--- a/tests/ovn.at
|
|
|
bbaaef |
+++ b/tests/ovn.at
|
|
|
bbaaef |
@@ -15900,12 +15900,12 @@ AT_CHECK([ovn-sbctl get controller_event $uuid event_info:vip], [0], [dnl
|
|
|
bbaaef |
OVN_CLEANUP([hv1], [hv2])
|
|
|
bbaaef |
AT_CLEANUP
|
|
|
bbaaef |
|
|
|
bbaaef |
-AT_SETUP([ovn -- IGMP snoop/querier])
|
|
|
bbaaef |
+AT_SETUP([ovn -- IGMP snoop/querier/relay])
|
|
|
bbaaef |
AT_SKIP_IF([test $HAVE_PYTHON = no])
|
|
|
bbaaef |
ovn_start
|
|
|
bbaaef |
|
|
|
bbaaef |
# Logical network:
|
|
|
bbaaef |
-# Two independent logical switches (sw1 and sw2).
|
|
|
bbaaef |
+# Three logical switches (sw1-sw3) connected to a logical router (rtr).
|
|
|
bbaaef |
# sw1:
|
|
|
bbaaef |
# - subnet 10.0.0.0/8
|
|
|
bbaaef |
# - 2 ports bound on hv1 (sw1-p11, sw1-p12)
|
|
|
bbaaef |
@@ -15915,6 +15915,10 @@ ovn_start
|
|
|
bbaaef |
# - 1 port bound on hv1 (sw2-p1)
|
|
|
bbaaef |
# - 1 port bound on hv2 (sw2-p2)
|
|
|
bbaaef |
# - IGMP Querier from 20.0.0.254
|
|
|
bbaaef |
+# sw3:
|
|
|
bbaaef |
+# - subnet 30.0.0.0/8
|
|
|
bbaaef |
+# - 1 port bound on hv1 (sw3-p1)
|
|
|
bbaaef |
+# - 1 port bound on hv2 (sw3-p2)
|
|
|
bbaaef |
|
|
|
bbaaef |
reset_pcap_file() {
|
|
|
bbaaef |
local iface=$1
|
|
|
bbaaef |
@@ -15991,29 +15995,47 @@ store_igmp_v3_query() {
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
#
|
|
|
bbaaef |
-# send_ip_multicast_pkt INPORT HV ETH_SRC ETH_DST IP_SRC IP_DST IP_LEN
|
|
|
bbaaef |
-# IP_PROTO DATA OUTFILE
|
|
|
bbaaef |
+# send_ip_multicast_pkt INPORT HV ETH_SRC ETH_DST IP_SRC IP_DST IP_LEN TTL
|
|
|
bbaaef |
+# IP_CHKSUM IP_PROTO DATA
|
|
|
bbaaef |
#
|
|
|
bbaaef |
# This shell function causes an IP multicast packet to be received on INPORT
|
|
|
bbaaef |
# of HV.
|
|
|
bbaaef |
# The hexdump of the packet is stored in OUTFILE.
|
|
|
bbaaef |
#
|
|
|
bbaaef |
send_ip_multicast_pkt() {
|
|
|
bbaaef |
- local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ip_src=$5 ip_dst=$6
|
|
|
bbaaef |
- local ip_len=$7 ip_chksum=$8 proto=$9 data=${10} outfile=${11}
|
|
|
bbaaef |
-
|
|
|
bbaaef |
- local ip_ttl=20
|
|
|
bbaaef |
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4
|
|
|
bbaaef |
+ local ip_src=$5 ip_dst=$6 ip_len=$7 ip_ttl=$8 ip_chksum=$9 proto=${10}
|
|
|
bbaaef |
+ local data=${11}
|
|
|
bbaaef |
|
|
|
bbaaef |
local eth=${eth_dst}${eth_src}0800
|
|
|
bbaaef |
local ip=450000${ip_len}95f14000${ip_ttl}${proto}${ip_chksum}${ip_src}${ip_dst}
|
|
|
bbaaef |
local packet=${eth}${ip}${data}
|
|
|
bbaaef |
|
|
|
bbaaef |
as $hv ovs-appctl netdev-dummy/receive ${inport} ${packet}
|
|
|
bbaaef |
+}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+#
|
|
|
bbaaef |
+# store_ip_multicast_pkt ETH_SRC ETH_DST IP_SRC IP_DST IP_LEN TTL
|
|
|
bbaaef |
+# IP_CHKSUM IP_PROTO DATA OUTFILE
|
|
|
bbaaef |
+#
|
|
|
bbaaef |
+# This shell function builds an IP multicast packet and stores the hexdump of
|
|
|
bbaaef |
+# the packet in OUTFILE.
|
|
|
bbaaef |
+#
|
|
|
bbaaef |
+store_ip_multicast_pkt() {
|
|
|
bbaaef |
+ local eth_src=$1 eth_dst=$2
|
|
|
bbaaef |
+ local ip_src=$3 ip_dst=$4 ip_len=$5 ip_ttl=$6 ip_chksum=$7 proto=$8
|
|
|
bbaaef |
+ local data=$9 outfile=${10}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ local eth=${eth_dst}${eth_src}0800
|
|
|
bbaaef |
+ local ip=450000${ip_len}95f14000${ip_ttl}${proto}${ip_chksum}${ip_src}${ip_dst}
|
|
|
bbaaef |
+ local packet=${eth}${ip}${data}
|
|
|
bbaaef |
+
|
|
|
bbaaef |
echo ${packet} >> ${outfile}
|
|
|
bbaaef |
}
|
|
|
bbaaef |
|
|
|
bbaaef |
ovn-nbctl ls-add sw1
|
|
|
bbaaef |
ovn-nbctl ls-add sw2
|
|
|
bbaaef |
+ovn-nbctl ls-add sw3
|
|
|
bbaaef |
|
|
|
bbaaef |
ovn-nbctl lsp-add sw1 sw1-p11
|
|
|
bbaaef |
ovn-nbctl lsp-add sw1 sw1-p12
|
|
|
bbaaef |
@@ -16021,6 +16043,26 @@ ovn-nbctl lsp-add sw1 sw1-p21
|
|
|
bbaaef |
ovn-nbctl lsp-add sw1 sw1-p22
|
|
|
bbaaef |
ovn-nbctl lsp-add sw2 sw2-p1
|
|
|
bbaaef |
ovn-nbctl lsp-add sw2 sw2-p2
|
|
|
bbaaef |
+ovn-nbctl lsp-add sw3 sw3-p1
|
|
|
bbaaef |
+ovn-nbctl lsp-add sw3 sw3-p2
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ovn-nbctl lr-add rtr
|
|
|
bbaaef |
+ovn-nbctl lrp-add rtr rtr-sw1 00:00:00:00:01:00 10.0.0.254/24
|
|
|
bbaaef |
+ovn-nbctl lrp-add rtr rtr-sw2 00:00:00:00:02:00 20.0.0.254/24
|
|
|
bbaaef |
+ovn-nbctl lrp-add rtr rtr-sw3 00:00:00:00:03:00 30.0.0.254/24
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+ovn-nbctl lsp-add sw1 sw1-rtr \
|
|
|
bbaaef |
+ -- lsp-set-type sw1-rtr router \
|
|
|
bbaaef |
+ -- lsp-set-addresses sw1-rtr 00:00:00:00:01:00 \
|
|
|
bbaaef |
+ -- lsp-set-options sw1-rtr router-port=rtr-sw1
|
|
|
bbaaef |
+ovn-nbctl lsp-add sw2 sw2-rtr \
|
|
|
bbaaef |
+ -- lsp-set-type sw2-rtr router \
|
|
|
bbaaef |
+ -- lsp-set-addresses sw2-rtr 00:00:00:00:02:00 \
|
|
|
bbaaef |
+ -- lsp-set-options sw2-rtr router-port=rtr-sw2
|
|
|
bbaaef |
+ovn-nbctl lsp-add sw3 sw3-rtr \
|
|
|
bbaaef |
+ -- lsp-set-type sw3-rtr router \
|
|
|
bbaaef |
+ -- lsp-set-addresses sw3-rtr 00:00:00:00:03:00 \
|
|
|
bbaaef |
+ -- lsp-set-options sw3-rtr router-port=rtr-sw3
|
|
|
bbaaef |
|
|
|
bbaaef |
net_add n1
|
|
|
bbaaef |
sim_add hv1
|
|
|
bbaaef |
@@ -16042,6 +16084,11 @@ ovs-vsctl -- add-port br-int hv1-vif3 -- \
|
|
|
bbaaef |
options:tx_pcap=hv1/vif3-tx.pcap \
|
|
|
bbaaef |
options:rxq_pcap=hv1/vif3-rx.pcap \
|
|
|
bbaaef |
ofport-request=1
|
|
|
bbaaef |
+ovs-vsctl -- add-port br-int hv1-vif4 -- \
|
|
|
bbaaef |
+ set interface hv1-vif4 external-ids:iface-id=sw3-p1 \
|
|
|
bbaaef |
+ options:tx_pcap=hv1/vif4-tx.pcap \
|
|
|
bbaaef |
+ options:rxq_pcap=hv1/vif4-rx.pcap \
|
|
|
bbaaef |
+ ofport-request=1
|
|
|
bbaaef |
|
|
|
bbaaef |
sim_add hv2
|
|
|
bbaaef |
as hv2
|
|
|
bbaaef |
@@ -16062,12 +16109,18 @@ ovs-vsctl -- add-port br-int hv2-vif3 -- \
|
|
|
bbaaef |
options:tx_pcap=hv2/vif3-tx.pcap \
|
|
|
bbaaef |
options:rxq_pcap=hv2/vif3-rx.pcap \
|
|
|
bbaaef |
ofport-request=1
|
|
|
bbaaef |
+ovs-vsctl -- add-port br-int hv2-vif4 -- \
|
|
|
bbaaef |
+ set interface hv2-vif4 external-ids:iface-id=sw3-p2 \
|
|
|
bbaaef |
+ options:tx_pcap=hv2/vif4-tx.pcap \
|
|
|
bbaaef |
+ options:rxq_pcap=hv2/vif4-rx.pcap \
|
|
|
bbaaef |
+ ofport-request=1
|
|
|
bbaaef |
|
|
|
bbaaef |
OVN_POPULATE_ARP
|
|
|
bbaaef |
|
|
|
bbaaef |
# Enable IGMP snooping on sw1.
|
|
|
bbaaef |
-ovn-nbctl set Logical_Switch sw1 other_config:mcast_querier="false"
|
|
|
bbaaef |
-ovn-nbctl set Logical_Switch sw1 other_config:mcast_snoop="true"
|
|
|
bbaaef |
+ovn-nbctl set Logical_Switch sw1 \
|
|
|
bbaaef |
+ other_config:mcast_querier="false" \
|
|
|
bbaaef |
+ other_config:mcast_snoop="true"
|
|
|
bbaaef |
|
|
|
bbaaef |
# No IGMP query should be generated by sw1 (mcast_querier="false").
|
|
|
bbaaef |
truncate -s 0 expected
|
|
|
bbaaef |
@@ -16100,9 +16153,12 @@ truncate -s 0 expected
|
|
|
bbaaef |
truncate -s 0 expected_empty
|
|
|
bbaaef |
send_ip_multicast_pkt hv1-vif2 hv1 \
|
|
|
bbaaef |
000000000001 01005e000144 \
|
|
|
bbaaef |
- $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e ca70 11 \
|
|
|
bbaaef |
- e518e518000a3b3a0000 \
|
|
|
bbaaef |
- expected
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000
|
|
|
bbaaef |
+store_ip_multicast_pkt \
|
|
|
bbaaef |
+ 000000000001 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000 expected
|
|
|
bbaaef |
|
|
|
bbaaef |
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected])
|
|
|
bbaaef |
OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
|
|
|
bbaaef |
@@ -16123,17 +16179,19 @@ OVS_WAIT_UNTIL([
|
|
|
bbaaef |
test "${total_entries}" = "1"
|
|
|
bbaaef |
])
|
|
|
bbaaef |
|
|
|
bbaaef |
-# Send traffic traffic and make sure it gets forwarded only on the port that
|
|
|
bbaaef |
-# joined.
|
|
|
bbaaef |
+# Send traffic and make sure it gets forwarded only on the port that joined.
|
|
|
bbaaef |
as hv1 reset_pcap_file hv1-vif1 hv1/vif1
|
|
|
bbaaef |
as hv2 reset_pcap_file hv2-vif1 hv2/vif1
|
|
|
bbaaef |
truncate -s 0 expected
|
|
|
bbaaef |
truncate -s 0 expected_empty
|
|
|
bbaaef |
send_ip_multicast_pkt hv1-vif2 hv1 \
|
|
|
bbaaef |
000000000001 01005e000144 \
|
|
|
bbaaef |
- $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e ca70 11 \
|
|
|
bbaaef |
- e518e518000a3b3a0000 \
|
|
|
bbaaef |
- expected
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000
|
|
|
bbaaef |
+store_ip_multicast_pkt \
|
|
|
bbaaef |
+ 000000000001 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000 expected
|
|
|
bbaaef |
|
|
|
bbaaef |
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected_empty])
|
|
|
bbaaef |
OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
|
|
|
bbaaef |
@@ -16167,5 +16225,110 @@ sleep 1
|
|
|
bbaaef |
OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected])
|
|
|
bbaaef |
OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected])
|
|
|
bbaaef |
|
|
|
bbaaef |
+# Dissable IGMP querier on sw2.
|
|
|
bbaaef |
+ovn-nbctl set Logical_Switch sw2 \
|
|
|
bbaaef |
+ other_config:mcast_querier="false"
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Enable IGMP snooping on sw3.
|
|
|
bbaaef |
+ovn-nbctl set Logical_Switch sw3 \
|
|
|
bbaaef |
+ other_config:mcast_querier="false" \
|
|
|
bbaaef |
+ other_config:mcast_snoop="true"
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Send traffic from sw3 and make sure rtr doesn't relay it.
|
|
|
bbaaef |
+truncate -s 0 expected_empty
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif1 hv1/vif1
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif2 hv1/vif2
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif3 hv1/vif3
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif4 hv1/vif4
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif1 hv2/vif1
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif2 hv2/vif2
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif3 hv2/vif3
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif4 hv2/vif4
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+send_ip_multicast_pkt hv2-vif4 hv2 \
|
|
|
bbaaef |
+ 000000000001 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Sleep a bit to make sure no traffic is received and then check.
|
|
|
bbaaef |
+sleep 1
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Enable IGMP relay on rtr
|
|
|
bbaaef |
+ovn-nbctl set logical_router rtr \
|
|
|
bbaaef |
+ options:mcast_relay="true"
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Inject IGMP Join for 239.0.1.68 on sw1-p11.
|
|
|
bbaaef |
+send_igmp_v3_report hv1-vif1 hv1 \
|
|
|
bbaaef |
+ 000000000001 $(ip_to_hex 10 0 0 1) f9f8 \
|
|
|
bbaaef |
+ $(ip_to_hex 239 0 1 68) 04 e9b9 \
|
|
|
bbaaef |
+ /dev/null
|
|
|
bbaaef |
+# Inject IGMP Join for 239.0.1.68 on sw2-p2.
|
|
|
bbaaef |
+send_igmp_v3_report hv2-vif3 hv2 \
|
|
|
bbaaef |
+ 000000000001 $(ip_to_hex 10 0 0 1) f9f8 \
|
|
|
bbaaef |
+ $(ip_to_hex 239 0 1 68) 04 e9b9 \
|
|
|
bbaaef |
+ /dev/null
|
|
|
bbaaef |
+# Inject IGMP Join for 239.0.1.68 on sw3-p1.
|
|
|
bbaaef |
+send_igmp_v3_report hv1-vif4 hv1 \
|
|
|
bbaaef |
+ 000000000001 $(ip_to_hex 10 0 0 1) f9f8 \
|
|
|
bbaaef |
+ $(ip_to_hex 239 0 1 68) 04 e9b9 \
|
|
|
bbaaef |
+ /dev/null
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Check that the IGMP Group is learned by all switches.
|
|
|
bbaaef |
+OVS_WAIT_UNTIL([
|
|
|
bbaaef |
+ total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l`
|
|
|
bbaaef |
+ test "${total_entries}" = "3"
|
|
|
bbaaef |
+])
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+# Send traffic from sw3 and make sure it is relayed by rtr.
|
|
|
bbaaef |
+# and ports that joined.
|
|
|
bbaaef |
+truncate -s 0 expected_routed_sw1
|
|
|
bbaaef |
+truncate -s 0 expected_routed_sw2
|
|
|
bbaaef |
+truncate -s 0 expected_switched
|
|
|
bbaaef |
+truncate -s 0 expected_empty
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif1 hv1/vif1
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif2 hv1/vif2
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif3 hv1/vif3
|
|
|
bbaaef |
+as hv1 reset_pcap_file hv1-vif4 hv1/vif4
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif1 hv2/vif1
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif2 hv2/vif2
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif3 hv2/vif3
|
|
|
bbaaef |
+as hv2 reset_pcap_file hv2-vif4 hv2/vif4
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+send_ip_multicast_pkt hv2-vif4 hv2 \
|
|
|
bbaaef |
+ 000000000001 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000
|
|
|
bbaaef |
+store_ip_multicast_pkt \
|
|
|
bbaaef |
+ 000000000100 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 1f cb70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000 expected_routed_sw1
|
|
|
bbaaef |
+store_ip_multicast_pkt \
|
|
|
bbaaef |
+ 000000000200 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 1f cb70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000 expected_routed_sw2
|
|
|
bbaaef |
+store_ip_multicast_pkt \
|
|
|
bbaaef |
+ 000000000001 01005e000144 \
|
|
|
bbaaef |
+ $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
|
|
|
bbaaef |
+ e518e518000a3b3a0000 expected_switched
|
|
|
bbaaef |
+
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected_routed_sw1])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_routed_sw2])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [expected_switched])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [expected_empty])
|
|
|
bbaaef |
+
|
|
|
bbaaef |
OVN_CLEANUP([hv1], [hv2])
|
|
|
bbaaef |
AT_CLEANUP
|
|
|
bbaaef |
--
|
|
|
bbaaef |
2.21.0
|
|
|
bbaaef |
|