We need to be able to monitor two vxlan interfaces (one for IPv4 and one
for IPv6) for dual stack EVPN logical switches since we can't configure a
single vxlan interface with multiple local IPs (one for v4 one for v6).
Fix the probelm allowing the CMS to specify a list of vxlan device names
using the following syntax:
dynamic-routing-vxlan-ifname=vxlan-if1,vxlan-if2,..,vxlan-ifn
Fixes: 36737306806e ("Add the capability to specify EVPN device names.")
Signed-off-by: Lorenzo Bianconi <[email protected]>
---
controller/neighbor.c | 78 ++++++++++++++++++++---------
northd/en-datapath-logical-switch.c | 57 ++++++++++-----------
ovn-nb.xml | 4 +-
3 files changed, 85 insertions(+), 54 deletions(-)
diff --git a/controller/neighbor.c b/controller/neighbor.c
index 075e672fa..6022cec82 100644
--- a/controller/neighbor.c
+++ b/controller/neighbor.c
@@ -21,10 +21,13 @@
#include "local_data.h"
#include "lport.h"
#include "openvswitch/ofp-parse.h"
+#include "openvswitch/vlog.h"
#include "ovn-sb-idl.h"
#include "neighbor.h"
+VLOG_DEFINE_THIS_MODULE(neighbor);
+
static const char *neighbor_interface_prefixes[] = {
[NEIGH_IFACE_BRIDGE] = "br-",
[NEIGH_IFACE_VXLAN] = "vxlan-",
@@ -43,10 +46,9 @@ static bool neighbor_interface_with_vni_exists(
struct vector *monitored_interfaces,
uint32_t vni);
static struct neighbor_interface_monitor *
-neighbor_interface_monitor_alloc(struct local_datapath *ld,
- enum neighbor_family family,
+neighbor_interface_monitor_alloc(enum neighbor_family family,
enum neighbor_interface_type type,
- uint32_t vni);
+ uint32_t vni, const char *if_name);
static void neighbor_collect_mac_to_advertise(
const struct neighbor_ctx_in *, struct hmap *neighbors,
struct sset *advertised_pbs, const struct sbrec_datapath_binding *);
@@ -83,6 +85,23 @@ advertise_neigh_find(const struct hmap *neighbors, struct
eth_addr mac,
return NULL;
}
+static void
+neigh_parse_device_name(struct sset *device_names, struct local_datapath *ld,
+ enum neighbor_interface_type type, uint32_t vni)
+{
+ const char *names = smap_get_def(&ld->datapath->external_ids,
+ neighbor_opt_name[type], "");
+ sset_clear(device_names);
+ sset_from_delimited_string(device_names, names, ",");
+ if (sset_is_empty(device_names)) {
+ /* Default device name if not specified. */
+ char if_name[IFNAMSIZ + 1];
+ snprintf(if_name, sizeof if_name, "%s%"PRIu32,
+ neighbor_interface_prefixes[type], vni);
+ sset_add(device_names, if_name);
+ }
+}
+
void
neighbor_run(struct neighbor_ctx_in *n_ctx_in,
struct neighbor_ctx_out *n_ctx_out)
@@ -104,25 +123,44 @@ neighbor_run(struct neighbor_ctx_in *n_ctx_in,
continue;
}
- struct neighbor_interface_monitor *vxlan =
- neighbor_interface_monitor_alloc(ld, NEIGH_AF_BRIDGE,
- NEIGH_IFACE_VXLAN, vni);
- vector_push(n_ctx_out->monitored_interfaces, &vxlan);
+ struct sset device_names = SSET_INITIALIZER(&device_names);
+ neigh_parse_device_name(&device_names, ld, NEIGH_IFACE_VXLAN, vni);
+ const char *name;
+ SSET_FOR_EACH (name, &device_names) {
+ struct neighbor_interface_monitor *vxlan =
+ neighbor_interface_monitor_alloc(NEIGH_AF_BRIDGE,
+ NEIGH_IFACE_VXLAN, vni, name);
+ vector_push(n_ctx_out->monitored_interfaces, &vxlan);
+ }
+ neigh_parse_device_name(&device_names, ld, NEIGH_IFACE_LOOPBACK, vni);
+ if (sset_count(&device_names) > 1) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_WARN_RL(&rl, "too many names provided for loopback device");
+ }
struct neighbor_interface_monitor *lo =
- neighbor_interface_monitor_alloc(ld, NEIGH_AF_BRIDGE,
- NEIGH_IFACE_LOOPBACK, vni);
+ neighbor_interface_monitor_alloc(NEIGH_AF_BRIDGE,
+ NEIGH_IFACE_LOOPBACK, vni,
+ SSET_FIRST(&device_names));
vector_push(n_ctx_out->monitored_interfaces, &lo);
+ neigh_parse_device_name(&device_names, ld, NEIGH_IFACE_BRIDGE, vni);
+ if (sset_count(&device_names) > 1) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_WARN_RL(&rl, "too many names provided for bridge device");
+ }
struct neighbor_interface_monitor *br_v4 =
- neighbor_interface_monitor_alloc(ld, NEIGH_AF_INET,
- NEIGH_IFACE_BRIDGE, vni);
+ neighbor_interface_monitor_alloc(NEIGH_AF_INET,
+ NEIGH_IFACE_BRIDGE, vni,
+ SSET_FIRST(&device_names));
vector_push(n_ctx_out->monitored_interfaces, &br_v4);
struct neighbor_interface_monitor *br_v6 =
- neighbor_interface_monitor_alloc(ld, NEIGH_AF_INET6,
- NEIGH_IFACE_BRIDGE, vni);
+ neighbor_interface_monitor_alloc(NEIGH_AF_INET6,
+ NEIGH_IFACE_BRIDGE, vni,
+ SSET_FIRST(&device_names));
vector_push(n_ctx_out->monitored_interfaces, &br_v6);
+ sset_destroy(&device_names);
enum neigh_redistribute_mode mode =
parse_neigh_dynamic_redistribute(&ld->datapath->external_ids);
@@ -200,10 +238,9 @@ neighbor_interface_with_vni_exists(struct vector
*monitored_interfaces,
}
static struct neighbor_interface_monitor *
-neighbor_interface_monitor_alloc(struct local_datapath *ld,
- enum neighbor_family family,
+neighbor_interface_monitor_alloc(enum neighbor_family family,
enum neighbor_interface_type type,
- uint32_t vni)
+ uint32_t vni, const char *if_name)
{
struct neighbor_interface_monitor *nim = xmalloc(sizeof *nim);
*nim = (struct neighbor_interface_monitor) {
@@ -212,15 +249,8 @@ neighbor_interface_monitor_alloc(struct local_datapath *ld,
.type = type,
.vni = vni,
};
+ snprintf(nim->if_name, sizeof nim->if_name, "%s", if_name);
- const char *if_name = smap_get(&ld->datapath->external_ids,
- neighbor_opt_name[type]);
- if (if_name) {
- snprintf(nim->if_name, sizeof nim->if_name, "%s", if_name);
- } else {
- snprintf(nim->if_name, sizeof nim->if_name, "%s%"PRIu32,
- neighbor_interface_prefixes[type], vni);
- }
return nim;
}
diff --git a/northd/en-datapath-logical-switch.c
b/northd/en-datapath-logical-switch.c
index ed0385a48..0ad5ad261 100644
--- a/northd/en-datapath-logical-switch.c
+++ b/northd/en-datapath-logical-switch.c
@@ -58,6 +58,26 @@ get_requested_tunnel_key(const struct nbrec_logical_switch
*nbs,
return requested_tunnel_key;
}
+static bool
+check_dynamic_device_name(const char *if_names)
+{
+ struct sset device_names;
+ sset_from_delimited_string(&device_names, if_names, ",");
+
+ bool ret = true;
+ const char *name;
+ SSET_FOR_EACH (name, &device_names) {
+ if (strlen(name) > IFNAMSIZ) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_WARN_RL(&rl, "dynamic-routing-ifname %s is too long", name);
+ ret = false;
+ break;
+ }
+ }
+ sset_destroy(&device_names);
+ return ret;
+}
+
static void
gather_external_ids(const struct nbrec_logical_switch *nbs,
struct smap *external_ids)
@@ -95,42 +115,23 @@ gather_external_ids(const struct nbrec_logical_switch *nbs,
const char *bridge_ifname = smap_get(&nbs->other_config,
"dynamic-routing-bridge-ifname");
- if (bridge_ifname) {
- if (strlen(bridge_ifname) > IFNAMSIZ) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "dynamic-routing-bridge-ifname %s is too long",
- bridge_ifname);
- } else {
- smap_add(external_ids, "dynamic-routing-bridge-ifname",
- bridge_ifname);
- }
+ if (bridge_ifname && check_dynamic_device_name(bridge_ifname)) {
+ smap_add(external_ids, "dynamic-routing-bridge-ifname",
+ bridge_ifname);
}
const char *vxlan_ifname = smap_get(&nbs->other_config,
"dynamic-routing-vxlan-ifname");
- if (vxlan_ifname) {
- if (strlen(vxlan_ifname) > IFNAMSIZ) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "dynamic-routing-vxlan-ifname %s is too long",
- vxlan_ifname);
- } else {
- smap_add(external_ids, "dynamic-routing-vxlan-ifname",
- vxlan_ifname);
- }
+ if (vxlan_ifname && check_dynamic_device_name(vxlan_ifname)) {
+ smap_add(external_ids, "dynamic-routing-vxlan-ifname",
+ vxlan_ifname);
}
const char *adv_ifname = smap_get(&nbs->other_config,
"dynamic-routing-advertise-ifname");
- if (adv_ifname) {
- if (strlen(adv_ifname) > IFNAMSIZ) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl,
- "dynamic-routing-advertise-ifname %s is too long",
- adv_ifname);
- } else {
- smap_add(external_ids, "dynamic-routing-advertise-ifname",
- adv_ifname);
- }
+ if (adv_ifname && check_dynamic_device_name(adv_ifname)) {
+ smap_add(external_ids, "dynamic-routing-advertise-ifname",
+ adv_ifname);
}
const char *redistribute =
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 19ccfc7ba..a1edd8d35 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -804,8 +804,8 @@
</column>
<column name="other_config" key="dynamic-routing-vxlan-ifname">
- Set the interface name for the vxlan device used for EVPN integration.
- The default name is <code>vxlan-$vni</code>.
+ List of interface names used for the vxlan devices used for EVPN
+ integration. The default name is <code>vxlan-$vni</code>.
Only relevant if <ref column="other_config" key="dynamic-routing-vni"
table="Logical_switch"/> is set to valid VNI.
</column>
--
2.52.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev