On 12/16/25 4:32 PM, Lorenzo Bianconi wrote:
> Introduce the capability to specify multiple ips for ovn-evpn-local-ip
> option in order to enable dual-stack for EVPN vxlan tunnels.
> The IPs used for vxlan tunnel can be specified using the following
> syntax in the external_ids column of Open_vSwitch table:
>
> external_ids:ovn-evpn-local-ip=10:1.1.1.1,20:[2::2],30:3.3.3.3,40:[4::4],30:[3::3]
>
> Reported-at: https://issues.redhat.com/browse/FDP-2768
> Signed-off-by: Lorenzo Bianconi <[email protected]>
> ---
Hi Lorenzo,
Thanks for the patch!
> controller/physical.c | 155 +++++++++---
> tests/system-ovn.at | 534 ++++++++++++++++++++++++++++++++++++++++++
We also need a NEWS item for this new feature.
We should also update the documentation about ovn-evpn-local-ip in
ovn-controller.8.xml and also update the TODO.rst file removing the item
we had for this feature.
> 2 files changed, 651 insertions(+), 38 deletions(-)
>
> diff --git a/controller/physical.c b/controller/physical.c
> index b9c60c8ab..8f66f1774 100644
> --- a/controller/physical.c
> +++ b/controller/physical.c
> @@ -3178,13 +3178,87 @@ physical_eval_remote_chassis_flows(const struct
> physical_ctx *ctx,
> ofpbuf_uninit(&ingress_ofpacts);
> }
>
> +#define DEFAULT_VNI (1 << 24) /* VNI used for the default local IP. */
> +struct vni_local_ip {
> + struct in6_addr ip;
> + uint32_t vni;
> +};
> +
> +static struct in6_addr *
> +evpn_local_ip_lookup_by_vni(const struct vector *map,
> + uint32_t vni, bool ipv4)
> +{
> + struct vni_local_ip *e, *def_e = NULL;
> + VECTOR_FOR_EACH_PTR (map, e) {
> + if (e->vni == vni && IN6_IS_ADDR_V4MAPPED(&e->ip) == ipv4) {
> + return &e->ip;
> + }
> + if (e->vni == DEFAULT_VNI) {
> + def_e = e;
> + }
> + }
> +
> + return def_e ? &def_e->ip : NULL;
At this point, def_e->ip's family might not match the requested family
(argument "ipv4"). I guess we need to check that too.
> +}
> +
> +static void
> +evpn_vni_local_ip_map_parse(struct vector *map, const char *local_ip_str)
> +{
> + char *tokstr = xstrdup(local_ip_str);
> + char *token, *ptr0 = NULL;
> +
> + for (token = strtok_r(tokstr, ",", &ptr0); token;
> + token = strtok_r(NULL, ",", &ptr0)) {
> + char *ptr1 = NULL, *vni_str = strtok_r(token, ":", &ptr1);
> + char *ip_str = strtok_r(NULL, "", &ptr1);
> + char *ip_address = NULL;
> + struct vni_local_ip e = {
> + .vni = DEFAULT_VNI,
> + };
> + int addr_family;
> + uint16_t port;
> +
> + if (!ip_str) {
> + /* Default local IP. */
> + ip_str = vni_str;
> + vni_str = NULL;
> + }
> +
> + if (!ip_address_and_port_from_lb_key(ip_str, &ip_address, &e.ip,
> &port,
> + &addr_family)) {
It's odd to use ip_address_and_port_from_lb_key(). That's a LB specific
function that also allows TCP/UDP ports to be listed after the IP
address. Let's add a new helper in ovn-util.[ch] that uses
inet_parse_active() and ss_format_address_nobracks() and errors out if
port is specified.
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> + VLOG_WARN_RL(&rl, "EVPN enabled, but required 'evpn-local-ip' is
> "
> + "missing or invalid %s ", local_ip_str);
> + continue;
> + }
> + free(ip_address);
> +
> + if (vni_str) {
> + if (!ovs_scan(vni_str, "%u", &e.vni) ||
> !ovn_is_valid_vni(e.vni)) {
> + continue;
> + }
> + }
> + vector_push(map, &e);
> + }
> + free(tokstr);
> +}
> +
> static void
> physical_consider_evpn_binding(const struct evpn_binding *binding,
> - const struct in6_addr *local_ip,
> + const struct vector *vni_ip_map,
> struct ofpbuf *ofpacts, struct match *match,
> - struct ovn_desired_flow_table *flow_table,
> - bool ipv4)
> + struct ovn_desired_flow_table *flow_table)
> {
> + bool ipv4 = IN6_IS_ADDR_V4MAPPED(&binding->remote_ip);
> + const struct in6_addr *local_ip = evpn_local_ip_lookup_by_vni(vni_ip_map,
> +
> binding->vni,
> + ipv4);
> + if (!local_ip) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> + VLOG_WARN_RL(&rl, "failed to get local tunnel ip");
> + return;
> + }
> +
> /* Ingress flows. */
> ofpbuf_clear(ofpacts);
> match_init_catchall(match);
> @@ -3308,29 +3382,40 @@ physical_consider_evpn_binding(const struct
> evpn_binding *binding,
>
> static void
> physical_consider_evpn_multicast(const struct evpn_multicast_group *mc_group,
> - const struct in6_addr *local_ip,
> + const struct vector *vni_ip_map,
> struct ofpbuf *ofpacts, struct match *match,
> - struct ovn_desired_flow_table *flow_table,
> - bool ipv4)
> + struct ovn_desired_flow_table *flow_table)
> {
> const struct evpn_binding *binding = NULL;
> + const struct in6_addr *local_ip = NULL;
>
> ofpbuf_clear(ofpacts);
> uint32_t multicast_tunnel_keys[] = {OVN_MCAST_FLOOD_TUNNEL_KEY,
> OVN_MCAST_UNKNOWN_TUNNEL_KEY,
> OVN_MCAST_FLOOD_L2_TUNNEL_KEY};
> - if (ipv4) {
> - ovs_be32 ip4 = in6_addr_get_mapped_ipv4(local_ip);
> - put_load_bytes(&ip4, sizeof ip4, MFF_TUN_SRC, 0, 32, ofpacts);
> - } else {
> - put_load_bytes(local_ip, sizeof *local_ip, MFF_TUN_IPV6_SRC,
> - 0, 128, ofpacts);
> - }
> - put_load(mc_group->vni, MFF_TUN_ID, 0, 24, ofpacts);
> -
> const struct hmapx_node *node;
> HMAPX_FOR_EACH (node, &mc_group->bindings) {
If I'm not wrong the mc_group can contain a mix of IPv4 and IPv6
bindings here, that's fine.
> binding = node->data;
> + bool ipv4 = IN6_IS_ADDR_V4MAPPED(&binding->remote_ip);
> + if (!local_ip) {
> + local_ip = evpn_local_ip_lookup_by_vni(vni_ip_map, binding->vni,
> + ipv4);
But now we only use the first binding to determine the address family
and therefore always set the TUN_SRC to either the local IPv4 or local
IPv6 address. Even if the remote binding family is different.
> + if (!local_ip) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,
> 1);
> + VLOG_WARN_RL(&rl, "failed to get local tunnel ip");
> + return;
> + }
> +
> + if (ipv4) {
> + ovs_be32 ip4 = in6_addr_get_mapped_ipv4(local_ip);
> + put_load_bytes(&ip4, sizeof ip4, MFF_TUN_SRC, 0, 32,
> ofpacts);
> + } else {
> + put_load_bytes(local_ip, sizeof *local_ip, MFF_TUN_IPV6_SRC,
> + 0, 128, ofpacts);
> + }
> + put_load(mc_group->vni, MFF_TUN_ID, 0, 24, ofpacts);
> + }
> +
> if (ipv4) {
> ovs_be32 ip4 = in6_addr_get_mapped_ipv4(&binding->remote_ip);
> put_load_bytes(&ip4, sizeof ip4, MFF_TUN_DST, 0, 32, ofpacts);
That means that at this point we might end up with inconsistent actions,
e.g.:
MFF_TUN_IPV6_SRC=<ipv6-address>,MFF_TUN_DST=<ipv4-address>,output:x,MFF_TUN_IPV6_DST=<ipv6-address>,output:y
> @@ -3420,28 +3505,24 @@ physical_eval_evpn_flows(const struct physical_ctx
> *ctx,
>
> const char *local_ip_str = smap_get_def(&ctx->chassis->other_config,
> "ovn-evpn-local-ip", "");
> - struct in6_addr local_ip;
> - if (!ip46_parse(local_ip_str, &local_ip)) {
> - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> - VLOG_WARN_RL(&rl, "EVPN enabled, but required 'evpn-local-ip' is "
> - "missing or invalid %s ", local_ip_str);
> - return;
> - }
> + struct vector vni_ip_map =
> + VECTOR_EMPTY_INITIALIZER(const struct vni_local_ip);
> + evpn_vni_local_ip_map_parse(&vni_ip_map, local_ip_str);
>
> struct match match = MATCH_CATCHALL_INITIALIZER;
> - bool ipv4 = IN6_IS_ADDR_V4MAPPED(&local_ip);
> -
> const struct evpn_binding *binding;
> +
> HMAP_FOR_EACH (binding, hmap_node, ctx->evpn_bindings) {
> - physical_consider_evpn_binding(binding, &local_ip, ofpacts,
> - &match, flow_table, ipv4);
> + physical_consider_evpn_binding(binding, &vni_ip_map, ofpacts,
> + &match, flow_table);
> }
>
> const struct evpn_multicast_group *mc_group;
> HMAP_FOR_EACH (mc_group, hmap_node, ctx->evpn_multicast_groups) {
> - physical_consider_evpn_multicast(mc_group, &local_ip, ofpacts,
> - &match, flow_table, ipv4);
> + physical_consider_evpn_multicast(mc_group, &vni_ip_map, ofpacts,
> + &match, flow_table);
> }
> + vector_destroy(&vni_ip_map);
>
> const struct evpn_fdb *fdb;
> HMAP_FOR_EACH (fdb, hmap_node, ctx->evpn_fdbs) {
> @@ -3571,32 +3652,30 @@ physical_handle_evpn_binding_changes(
> {
> const char *local_ip_str = smap_get_def(&ctx->chassis->other_config,
> "ovn-evpn-local-ip", "");
> - struct in6_addr local_ip;
> - if (!ip46_parse(local_ip_str, &local_ip)) {
> - return;
> - }
> + struct vector vni_ip_map =
> + VECTOR_EMPTY_INITIALIZER(const struct vni_local_ip);
> + evpn_vni_local_ip_map_parse(&vni_ip_map, local_ip_str);
>
> struct ofpbuf ofpacts;
> ofpbuf_init(&ofpacts, 0);
> struct match match = MATCH_CATCHALL_INITIALIZER;
> - bool ipv4 = IN6_IS_ADDR_V4MAPPED(&local_ip);
>
> const struct hmapx_node *node;
> HMAPX_FOR_EACH (node, updated_bindings) {
> const struct evpn_binding *binding = node->data;
> -
> ofctrl_remove_flows(flow_table, &binding->flow_uuid);
> - physical_consider_evpn_binding(binding, &local_ip, &ofpacts,
> - &match, flow_table, ipv4);
> + physical_consider_evpn_binding(binding, &vni_ip_map, &ofpacts,
> + &match, flow_table);
> }
>
> HMAPX_FOR_EACH (node, updated_multicast_groups) {
> const struct evpn_multicast_group *mc_group = node->data;
>
> ofctrl_remove_flows(flow_table, &mc_group->flow_uuid);
> - physical_consider_evpn_multicast(mc_group, &local_ip, &ofpacts,
> - &match, flow_table, ipv4);
> + physical_consider_evpn_multicast(mc_group, &vni_ip_map, &ofpacts,
> + &match, flow_table);
> }
> + vector_destroy(&vni_ip_map);
>
> ofpbuf_uninit(&ofpacts);
>
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 1b4b30743..9980927ba 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -18160,6 +18160,540 @@ AT_CLEANUP
> EVPN_SWITCH_TESTS([default])
> EVPN_SWITCH_TESTS([custom])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([dynamic-routing - EVPN - IPv6])
We can move this test above, inside the EVPN_SWITCH_TESTS define and
parametrize the EVPN host interface names like we do for the current
EVPN tests.
That will make it such the test is run with both default and custom
interface names.
> +AT_KEYWORDS([dynamic-routing])
> +
> +CHECK_VRF()
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +
> +vni=10
> +VRF_RESERVE([$vni])
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +ADD_BR([br-ext], [set Bridge br-ext fail-mode=standalone])
> +
> +# Set external-ids in br-int needed for ovn-controller.
> +check ovs-vsctl \
> + -- set Open_vSwitch . external-ids:system-id=hv1 \
> + -- set Open_vSwitch .
> external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> + -- set Open_vSwitch . external-ids:ovn-encap-ip=169::1 \
> + -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext \
> + -- set Open_vSwitch .
> external-ids:ovn-evpn-local-ip=10:169.0.0.1,10:[169::1] \
This configures a "dual stack" local IP for EVPN VTEPs.
> + -- set Open_vSwitch . external-ids:ovn-evpn-vxlan-ports=4789 \
> + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller.
> +start_daemon ovn-controller
> +
> +OVS_WAIT_WHILE([ip link | grep -q ovnvrf$vni:.*UP])
> +
> +check ovn-nbctl
> \
> + -- ls-add ls-evpn
> \
> + -- lsp-add ls-evpn workload1
> \
> + -- lsp-set-addresses workload1 "f0:00:0f:16:01:10 172.16.1.10
> 172:16::10" \
> + -- lsp-add ls-evpn workload2
> \
> + -- lsp-set-addresses workload2 "f0:00:0f:16:01:20 172.16.1.20
> 172:16::20" \
> + -- lsp-add-localnet-port ls-evpn ln_port phynet
> +
> +ADD_NAMESPACES(workload1)
> +ADD_VETH(workload1, workload1, br-int, "172:16::10/64", "f0:00:0f:16:01:10",
> \
> + "172:16::1", "nodad", "172.16.1.10/24", "172.16.1.1")
> +
> +ADD_NAMESPACES(workload2)
> +ADD_VETH(workload2, workload2, br-int, "172:16::20/64", "f0:00:0f:16:01:20",
> \
> + "172:16::1", "nodad", "172.16.1.20/24", "172.16.1.1")
> +
> +OVN_POPULATE_ARP
> +check ovn-nbctl --wait=hv sync
> +wait_for_ports_up
> +
> +# Setup a VRF for the VNI.
> +check ip link add vrf-$vni type vrf table $vni
> +on_exit "ip link del vrf-$vni"
> +check ip link set vrf-$vni up
> +
> +# Add VNI bridge.
> +check ip link add br-$vni type bridge
> +on_exit "ip link del br-$vni"
> +check ip link set br-$vni master vrf-$vni addrgenmode none
> +check ip link set dev br-$vni up
> +
> +# Add VXLAN VTEP for the VNI (linked to the OVS vxlan_sys_<port> interface).
> +# Use a dstport different than the one used by OVS.
> +# This is fine because we don't actually want traffic to pass through
> +# the $vxlan interface. FRR should read the dstport from the linked
> +# vxlan_sys_${vxlan_port} device.
> +dstport=$((60000 + $vni))
> +check ip link add vxlan-$vni type vxlan \
> + id $vni dstport $dstport local 169::1 nolearning
But here we create a single VXLAN interface, only for IPv6. We should
also add one for IPv4.
But raises the point that even with commit
https://github.com/ovn-org/ovn/commit/3673730 we still can't monitor the
two vxlan interfaces (the one for IPv4 and the one for IPv6).
We need a follow up of that patch to replace
"dynamic-routing-vxlan-ifname" with "dynamic-routing-vxlan-v4-ifname"
and "dynamic-routing-vxlan-v6-ifname".
> +on_exit "ip link del vxlan-$vni"
> +check ip link set dev vxlan-$vni up
> +check ip link set vxlan-$vni master br-$vni
> +
> +# Add a dummy loopback to the VNI bridge to be used for advertising local
> +# MACs.
> +check ip link add name lo-$vni type dummy
> +on_exit "ip link del lo-$vni"
> +check ip link set lo-$vni master br-$vni
> +check ip link set lo-$vni up
> +
> +AS_BOX([L2 EVPN VTEP and FDB learning])
> +
> +check ovn-nbctl --wait=hv set logical_switch ls-evpn
> other_config:dynamic-routing-vni=$vni
> +ofport=$(ovs-vsctl --bare --columns ofport find Interface
> name="ovn-evpn-4789")
> +dp_key=$(fetch_column Datapath tunnel_key external_ids:name=ls-evpn)
> +
> +AT_CHECK([ovn-appctl evpn/remote-vtep-list], [0], [dnl
> +])
> +
> +AT_CHECK([ovn-appctl evpn/vtep-binding-list], [0], [dnl
> +])
> +
> +AT_CHECK([ovn-appctl evpn/vtep-multicast-group-list], [0], [dnl
> +])
> +
> +# Simulate remote VTEP.
> +check bridge fdb append 00:00:00:00:00:00 dev vxlan-$vni dst 169::a static
> permanent
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/remote-vtep-list], [0], [dnl
> +IP: 169::a, port: 4789, vni: $vni
> +])
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-binding-list | cut -d','
> -f2-], [0], [dnl
> + Remote IP: 169::a, vni: $vni, binding_key: 0x80000001, tunnel_ofport:
> $ofport, dp_key: $dp_key
> +])
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-multicast-group-list |
> cut -d',' -f2-], [0], [dnl
> + Remote IPs: 169::a, vni: $vni
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_PHY_TO_LOG |
> grep priority=1050 | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=1050,tun_id=0xa,tun_ipv6_src=169::a,tun_ipv6_dst=169::1,in_port=$ofport
>
> actions=load:0x$dp_key->OXM_OF_METADATA[[0..31]],load:0x80000001->NXM_NX_REG14[[]],resubmit(,OFTABLE_LEARN_REMOTE_FDB),resubmit(,OFTABLE_LOG_INGRESS_PIPELINE)
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int
> table=OFTABLE_REMOTE_VTEP_OUTPUT | grep output | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=50,reg15=0x8000,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],output:$ofport,resubmit(,OFTABLE_LOCAL_OUTPUT)
> +priority=50,reg15=0x80000001,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],output:$ofport
> +priority=50,reg15=0x8001,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],output:$ofport,resubmit(,OFTABLE_LOCAL_OUTPUT)
> +priority=50,reg15=0x8004,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],output:$ofport,resubmit(,OFTABLE_LOCAL_OUTPUT)
> +priority=55,reg10=0x1/0x1,reg15=0x80000001,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xffff->NXM_OF_IN_PORT[[]],output:$ofport
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int
> table=OFTABLE_LEARN_REMOTE_FDB | grep priority | \
> + awk '{print $7, $8}' | strip_cookie | sort], [0], [dnl
> +priority=100,reg14=0x80000001,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +])
> +
> +# Simulate more remote VTEPs.
> +check bridge fdb append 00:00:00:00:00:00 dev vxlan-$vni dst 169::14 static
> permanent
> +check bridge fdb append 00:00:00:00:00:01 dev vxlan-$vni dst 169::1e
> extern_learn
We should also add IPv4 remote VTEPs to check that the dual-stack
implementation works fine.
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/remote-vtep-list | sort], [0],
> [dnl
> +IP: 169::14, port: 4789, vni: $vni
> +IP: 169::1e, port: 4789, vni: $vni
> +IP: 169::a, port: 4789, vni: $vni
> +])
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-binding-list | cut -d','
> -f2- | sort], [0], [dnl
> + Remote IP: 169::14, vni: $vni, binding_key: 0x80000002, tunnel_ofport:
> $ofport, dp_key: $dp_key
> + Remote IP: 169::1e, vni: $vni, binding_key: 0x80000003, tunnel_ofport:
> $ofport, dp_key: $dp_key
> + Remote IP: 169::a, vni: $vni, binding_key: 0x80000001, tunnel_ofport:
> $ofport, dp_key: $dp_key
> +])
> +
> +# We cannot check the output directly because the order might change.
> +OVS_WAIT_UNTIL([ovn-appctl evpn/vtep-multicast-group-list | grep -q
> "169::a"])
> +OVS_WAIT_UNTIL([ovn-appctl evpn/vtep-multicast-group-list | grep -q
> "169::14"])
> +OVS_WAIT_UNTIL([ovn-appctl evpn/vtep-multicast-group-list | grep -q
> "169::1e"])
> +AT_CHECK([ovn-appctl evpn/vtep-multicast-group-list | wc -l], [0], [1
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_PHY_TO_LOG |
> grep priority=1050 | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=1050,tun_id=0xa,tun_ipv6_src=169::14,tun_ipv6_dst=169::1,in_port=$ofport
>
> actions=load:0x$dp_key->OXM_OF_METADATA[[0..31]],load:0x80000002->NXM_NX_REG14[[]],resubmit(,OFTABLE_LEARN_REMOTE_FDB),resubmit(,OFTABLE_LOG_INGRESS_PIPELINE)
> +priority=1050,tun_id=0xa,tun_ipv6_src=169::1e,tun_ipv6_dst=169::1,in_port=$ofport
>
> actions=load:0x$dp_key->OXM_OF_METADATA[[0..31]],load:0x80000003->NXM_NX_REG14[[]],resubmit(,OFTABLE_LEARN_REMOTE_FDB),resubmit(,OFTABLE_LOG_INGRESS_PIPELINE)
> +priority=1050,tun_id=0xa,tun_ipv6_src=169::a,tun_ipv6_dst=169::1,in_port=$ofport
>
> actions=load:0x$dp_key->OXM_OF_METADATA[[0..31]],load:0x80000001->NXM_NX_REG14[[]],resubmit(,OFTABLE_LEARN_REMOTE_FDB),resubmit(,OFTABLE_LOG_INGRESS_PIPELINE)
> +])
> +
> +ovs-ofctl dump-flows br-int table=OFTABLE_REMOTE_VTEP_OUTPUT >
> oftable_remote_vtep_output
> +AT_CHECK_UNQUOTED([grep "output" oftable_remote_vtep_output | grep -v
> resubmit | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=50,reg15=0x80000001,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],output:$ofport
> +priority=50,reg15=0x80000002,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0x14->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],output:$ofport
> +priority=50,reg15=0x80000003,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0x1e->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],output:$ofport
> +priority=55,reg10=0x1/0x1,reg15=0x80000001,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0xa->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xffff->NXM_OF_IN_PORT[[]],output:$ofport
> +priority=55,reg10=0x1/0x1,reg15=0x80000002,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0x14->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xffff->NXM_OF_IN_PORT[[]],output:$ofport
> +priority=55,reg10=0x1/0x1,reg15=0x80000003,metadata=0x$dp_key
> actions=load:0x1->NXM_NX_TUN_IPV6_SRC[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_SRC[[64..127]],load:0x1e->NXM_NX_TUN_IPV6_DST[[0..63]],load:0x169000000000000->NXM_NX_TUN_IPV6_DST[[64..127]],load:0xa->NXM_NX_TUN_ID[[0..23]],load:0xffff->NXM_OF_IN_PORT[[]],output:$ofport
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int
> table=OFTABLE_LEARN_REMOTE_FDB | grep priority | \
> + awk '{print $7, $8}' | strip_cookie | sort], [0], [dnl
> +priority=100,reg14=0x80000001,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000002,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000003,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=150,reg14=0x80000003,metadata=0x1,dl_src=00:00:00:00:00:01
> actions=drop
> +])
> +
> +AT_CHECK([grep "resubmit" oftable_remote_vtep_output | grep
> "load:0xa->NXM_NX_TUN_IPV6_DST" | grep -c
> "load:0x169000000000000->NXM_NX_TUN_IPV6_DST"], [0], [3
> +])
> +AT_CHECK([grep "resubmit" oftable_remote_vtep_output | grep
> "load:0x14->NXM_NX_TUN_IPV6_DST" | grep -c
> "load:0x169000000000000->NXM_NX_TUN_IPV6_DST"], [0], [3
> +])
> +AT_CHECK([grep "resubmit" oftable_remote_vtep_output | grep
> "load:0x1e->NXM_NX_TUN_IPV6_DST" | grep -c
> "load:0x169000000000000->NXM_NX_TUN_IPV6_DST"], [0], [3
> +])
> +
> +# Simulate remote workload.
> +check bridge fdb add f0:00:0f:16:10:50 dev vxlan-$vni dst 169::a static
> extern_learn
> +check bridge fdb add f0:00:0f:16:10:60 dev vxlan-$vni dst 169::14 static
> extern_learn
> +check bridge fdb add f0:00:0f:16:10:70 dev vxlan-$vni dst 169::1e static
> extern_learn
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-fdb-list | cut -d',' -f2-
> | sort], [0], [dnl
> + MAC: 00:00:00:00:00:01, vni: $vni, binding_key: 0x80000003, dp_key: $dp_key
> + MAC: f0:00:0f:16:10:50, vni: $vni, binding_key: 0x80000001, dp_key: $dp_key
> + MAC: f0:00:0f:16:10:60, vni: $vni, binding_key: 0x80000002, dp_key: $dp_key
> + MAC: f0:00:0f:16:10:70, vni: $vni, binding_key: 0x80000003, dp_key: $dp_key
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_GET_REMOTE_FDB
> | grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=0 actions=load:0->NXM_NX_REG1[[]]
> +priority=150,metadata=0x$dp_key,dl_dst=00:00:00:00:00:01
> actions=load:0x80000003->NXM_NX_REG1[[]]
> +priority=150,metadata=0x$dp_key,dl_dst=f0:00:0f:16:10:50
> actions=load:0x80000001->NXM_NX_REG1[[]]
> +priority=150,metadata=0x$dp_key,dl_dst=f0:00:0f:16:10:60
> actions=load:0x80000002->NXM_NX_REG1[[]]
> +priority=150,metadata=0x$dp_key,dl_dst=f0:00:0f:16:10:70
> actions=load:0x80000003->NXM_NX_REG1[[]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int
> table=OFTABLE_LEARN_REMOTE_FDB | grep priority | \
> + awk '{print $7, $8}' | strip_cookie | sort], [0], [dnl
> +priority=100,reg14=0x80000001,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000002,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000003,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=150,reg14=0x80000001,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:50
> actions=drop
> +priority=150,reg14=0x80000002,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:60
> actions=drop
> +priority=150,reg14=0x80000003,metadata=0x$dp_key,dl_src=00:00:00:00:00:01
> actions=drop
> +priority=150,reg14=0x80000003,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:70
> actions=drop
> +])
> +
> +# Check that the recompute won't change the UUIDs and tunnel keys.
> +ovn-appctl evpn/vtep-binding-list > bindings_before
> +ovn-appctl evpn/vtep-multicast-group-list > mc_groups_before
> +ovn-appctl evpn/vtep-fdb-list > fdb_before
> +
> +check ovn-appctl inc-engine/recompute
> +check ovn-nbctl --wait=hv sync
> +
> +ovn-appctl evpn/vtep-binding-list > bindings_after
> +ovn-appctl evpn/vtep-multicast-group-list > mc_groups_after
> +ovn-appctl evpn/vtep-fdb-list > fdb_after
> +
> +check diff -q bindings_before bindings_after
> +check diff -q mc_groups_before mc_groups_after
> +check diff -q fdb_before fdb_after
> +
> +AS_BOX([L2 EVPN FDB advertising])
> +
> +check ovn-nbctl --wait=hv set logical_switch ls-evpn
> other_config:dynamic-routing-redistribute=fdb
> +OVS_WAIT_FOR_OUTPUT([bridge fdb show | grep "lo-10" | grep "f0:00:0f:16:01"
> | sort], [0], [dnl
> +f0:00:0f:16:01:10 dev lo-10 master br-10 static
> +f0:00:0f:16:01:10 dev lo-10 vlan 1 master br-10 static
> +f0:00:0f:16:01:20 dev lo-10 master br-10 static
> +f0:00:0f:16:01:20 dev lo-10 vlan 1 master br-10 static
> +])
> +
> +check ovn-nbctl --wait=hv lsp-del workload2
> +OVS_WAIT_FOR_OUTPUT([bridge fdb show | grep "lo-10" | grep "f0:00:0f:16:01"
> | sort], [0], [dnl
> +f0:00:0f:16:01:10 dev lo-10 master br-10 static
> +f0:00:0f:16:01:10 dev lo-10 vlan 1 master br-10 static
> +])
> +
> +check ovn-nbctl --wait=hv remove logical_switch ls-evpn other_config
> dynamic-routing-redistribute
> +OVS_WAIT_FOR_OUTPUT([bridge fdb show | grep "lo-10" | grep "f0:00:0f:16:01"
> | sort], [0], [dnl
> +])
> +
> +check ovn-nbctl --wait=hv set logical_switch ls-evpn
> other_config:fdb_age_threshold=300
> +ovs-ofctl dump-flows br-int table=OFTABLE_LEARN_REMOTE_FDB
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int
> table=OFTABLE_LEARN_REMOTE_FDB | grep priority | \
> + awk '{print $7, $8}' | strip_cookie | sort], [0], [dnl
> +priority=100,reg14=0x80000001,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,hard_timeout=300,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000002,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,hard_timeout=300,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000003,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,hard_timeout=300,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=150,reg14=0x80000001,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:50
> actions=drop
> +priority=150,reg14=0x80000002,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:60
> actions=drop
> +priority=150,reg14=0x80000003,metadata=0x$dp_key,dl_src=00:00:00:00:00:01
> actions=drop
> +priority=150,reg14=0x80000003,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:70
> actions=drop
> +])
> +
> +check ovn-nbctl --wait=hv remove logical_switch ls-evpn other_config
> fdb_age_threshold
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int
> table=OFTABLE_LEARN_REMOTE_FDB | grep priority | \
> + awk '{print $7, $8}' | strip_cookie | sort], [0], [dnl
> +priority=100,reg14=0x80000001,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000002,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=100,reg14=0x80000003,metadata=0x$dp_key
> actions=learn(table=OFTABLE_GET_REMOTE_FDB,priority=150,delete_learned,OXM_OF_METADATA[[]],NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],load:NXM_NX_REG14[[]]->NXM_NX_REG1[[]])
> +priority=150,reg14=0x80000001,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:50
> actions=drop
> +priority=150,reg14=0x80000002,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:60
> actions=drop
> +priority=150,reg14=0x80000003,metadata=0x$dp_key,dl_src=00:00:00:00:00:01
> actions=drop
> +priority=150,reg14=0x80000003,metadata=0x$dp_key,dl_src=f0:00:0f:16:10:70
> actions=drop
> +])
> +
> +AS_BOX([L2 EVPN ARP learning])
> +# Add a router connected to the EVPN logical switch.
> +check ovn-nbctl --wait=hv \
> + -- lr-add lr \
> + -- lrp-add lr lr-ls-evpn f0:00:0f:16:01:01 172.16.1.1/24 172:16::1/64 \
> + -- lsp-add-router-port ls-evpn ls-evpn-lr lr-ls-evpn
> +
> +rtr_dp_key=$(fetch_column Datapath tunnel_key external_ids:name=lr)
> +rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=lr-ls-evpn)
> +
> +# Simulate remote workload ARPs (type-2 MAC+IP EVPN route).
> +# ovn-controller needs to add OF rules for ARP lookup but no rules for
> +# MAC_CACHE use. These entries do not age out automatically, their lifetime
> +# is controlled by the BGP-EVPN control plane.
> +check ip neigh add dev br-10 172.16.1.50 lladdr f0:00:0f:16:10:50 nud noarp
> extern_learn
> +check ip neigh add dev br-10 172.16.1.60 lladdr f0:00:0f:16:10:60 nud noarp
> extern_learn
> +check ip neigh add dev br-10 172.16.1.70 lladdr f0:00:0f:16:10:70 nud noarp
> extern_learn
> +
> +check ip -6 neigh add dev br-10 172:16::50 lladdr f0:00:0f:16:10:50 nud
> noarp extern_learn
> +check ip -6 neigh add dev br-10 172:16::60 lladdr f0:00:0f:16:10:60 nud
> noarp extern_learn
> +check ip -6 neigh add dev br-10 172:16::70 lladdr f0:00:0f:16:10:70 nud
> noarp extern_learn
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-arp-list | cut -d',' -f2-
> | sort], [0], [dnl
> + VNI: 10, MAC: f0:00:0f:16:10:50, IP: 172.16.1.50, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:50, IP: 172:16::50, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:60, IP: 172.16.1.60, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:60, IP: 172:16::60, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172.16.1.70, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172:16::70, dp_key: $dp_key
> +])
> +
> +AS_BOX([Check dynamic-routing-arp-prefer-local=true])
> +check ovn-nbctl --wait=hv set Logical_Switch ls-evpn
> other_config:dynamic-routing-arp-prefer-local=true
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> +priority=20,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=20,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=20,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=20,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=20,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=20,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
> actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
> actions=drop
> +])
> +
> +AS_BOX([Check dynamic-routing-arp-prefer-local=false])
> +check ovn-nbctl --wait=hv set Logical_Switch ls-evpn
> other_config:dynamic-routing-arp-prefer-local=false
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
> actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
> actions=drop
> +])
> +
> +# Check that the recompute won't change the UUIDs and flows.
> +ovn-appctl evpn/vtep-arp-list > arp_before
> +
> +check ovn-appctl inc-engine/recompute
> +check ovn-nbctl --wait=hv sync
> +
> +ovn-appctl evpn/vtep-arp-list > arp_after
> +
> +check diff -q arp_before arp_after
> +
> +# Remove remote workload ARP entries and check ovn-controller's state.
> +check ip neigh del dev br-10 172.16.1.50
> +check ip neigh del dev br-10 172.16.1.60
> +check ip neigh del dev br-10 172.16.1.70
> +
> +check ip -6 neigh del dev br-10 172:16::50
> +check ip -6 neigh del dev br-10 172:16::60
> +check ip -6 neigh del dev br-10 172:16::70
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-arp-list | cut -d',' -f2-
> | sort], [0], [dnl
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
> actions=load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
> actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
> actions=drop
> +])
> +
> +# Re-add the remote workload ARPs, remove the router, check that flows are
> +# removed (vtep-arp-list should still list the ARPs as they're learned on
> +# the logical switch that still exists).
> +check ip neigh add dev br-10 172.16.1.50 lladdr f0:00:0f:16:10:50 nud noarp
> extern_learn
> +check ip neigh add dev br-10 172.16.1.60 lladdr f0:00:0f:16:10:60 nud noarp
> extern_learn
> +check ip neigh add dev br-10 172.16.1.70 lladdr f0:00:0f:16:10:70 nud noarp
> extern_learn
> +
> +check ip -6 neigh add dev br-10 172:16::50 lladdr f0:00:0f:16:10:50 nud
> noarp extern_learn
> +check ip -6 neigh add dev br-10 172:16::60 lladdr f0:00:0f:16:10:60 nud
> noarp extern_learn
> +check ip -6 neigh add dev br-10 172:16::70 lladdr f0:00:0f:16:10:70 nud
> noarp extern_learn
> +
> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-arp-list | cut -d',' -f2-
> | sort], [0], [dnl
> + VNI: 10, MAC: f0:00:0f:16:10:50, IP: 172.16.1.50, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:50, IP: 172:16::50, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:60, IP: 172.16.1.60, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:60, IP: 172:16::60, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172.16.1.70, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172:16::70, dp_key: $dp_key
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
> actions=load:0x1->NXM_NX_REG10[[6]]
> +])
> +
> +check ovn-nbctl --wait=hv lr-del lr
> +AT_CHECK_UNQUOTED([ovn-appctl evpn/vtep-arp-list | cut -d',' -f2- | sort],
> [0], [dnl
> + VNI: 10, MAC: f0:00:0f:16:10:50, IP: 172.16.1.50, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:50, IP: 172:16::50, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:60, IP: 172.16.1.60, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:60, IP: 172:16::60, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172.16.1.70, dp_key: $dp_key
> + VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172:16::70, dp_key: $dp_key
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +])
> +
> +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP |
> grep priority | \
> + awk '{print $7, $8}' | sort], [0], [dnl
> +])
> +
> +AS_BOX([L2 EVPN ARP advertising])
> +# Add a router connected to the EVPN logical switch.
> +check ovn-nbctl --wait=hv \
> + -- lr-add lr \
> + -- set Logical_Router lr options:chassis=hv1 \
> + -- lrp-add lr lr-ls-evpn f0:00:0f:16:01:01 172.16.1.1/24 172:16::1/64
> +
> +ls_evpn_uuid=$(fetch_column Datapath_Binding _uuid external_ids:name=ls-evpn)
> +check ovn-nbctl --wait=hv set logical_switch ls-evpn
> other_config:dynamic-routing-redistribute=fdb,ip
> +check_row_count Advertised_MAC_Binding 1 ip='172.16.1.10'
> mac='f0\:00\:0f\:16\:01\:10' datapath=$ls_evpn_uuid
> +check_row_count Advertised_MAC_Binding 1 ip='172.16.1.1'
> mac='f0\:00\:0f\:16\:01\:01' datapath=$ls_evpn_uuid
> +check_row_count Advertised_MAC_Binding 1 ip='172\:16\:\:10'
> mac='f0\:00\:0f\:16\:01\:10' datapath=$ls_evpn_uuid
> +check_row_count Advertised_MAC_Binding 1 ip='172\:16\:\:1'
> mac='f0\:00\:0f\:16\:01\:01' datapath=$ls_evpn_uuid
> +check_row_count Advertised_MAC_Binding 4
> +
> +AT_CHECK([ip neigh show dev br-10 nud noarp | grep -q '172.16.1.10 lladdr
> f0:00:0f:16:01:10 NOARP'])
> +AT_CHECK([ip neigh show dev br-10 nud noarp | grep -q '172.16.1.1 lladdr
> f0:00:0f:16:01:01 NOARP'])
> +AT_CHECK([ip -6 neigh show dev br-10 nud noarp | grep -q '172:16::10 lladdr
> f0:00:0f:16:01:10 NOARP'])
> +AT_CHECK([ip -6 neigh show dev br-10 nud noarp | grep -q '172:16::1 lladdr
> f0:00:0f:16:01:01 NOARP'])
> +
> +OVS_WAIT_FOR_OUTPUT([bridge fdb show | grep "lo-10" | grep "f0:00:0f:16:01"
> | sort], [0], [dnl
> +f0:00:0f:16:01:01 dev lo-10 master br-10 static
> +f0:00:0f:16:01:01 dev lo-10 vlan 1 master br-10 static
> +f0:00:0f:16:01:10 dev lo-10 master br-10 static
> +f0:00:0f:16:01:10 dev lo-10 vlan 1 master br-10 static
> +])
> +
> +check ovn-nbctl --wait=hv lsp-add ls-evpn workload2 \
> + -- lsp-set-addresses workload2 "f0:00:0f:16:01:20 172.16.1.20 172:16::20"
> +
> +check_row_count Advertised_MAC_Binding 1 ip='172.16.1.20'
> mac='f0\:00\:0f\:16\:01\:20' datapath=$ls_evpn_uuid
> +AT_CHECK([ip neigh show dev br-10 nud noarp | grep -q '172.16.1.20 lladdr
> f0:00:0f:16:01:20 NOARP'])
> +
> +check_row_count Advertised_MAC_Binding 1 ip='172\:16\:\:20'
> mac='f0\:00\:0f\:16\:01\:20' datapath=$ls_evpn_uuid
> +AT_CHECK([ip -6 neigh show dev br-10 nud noarp | grep -q '172:16::20 lladdr
> f0:00:0f:16:01:20 NOARP'])
> +
> +check ovn-nbctl --wait=hv lsp-del workload2
> +AT_CHECK([ip neigh show dev br-10 nud noarp | grep -q '172.16.1.20 lladdr
> f0:00:0f:16:01:20 NOARP'], [1])
> +AT_CHECK([ip -6 neigh show dev br-10 nud noarp | grep -q '172:16::20 lladdr
> f0:00:0f:16:01:20 NOARP'], [1])
> +
> +check ovn-nbctl --wait=hv lsp-del workload1
> +check_row_count Advertised_MAC_Binding 2
> +AT_CHECK([ip neigh show dev br-10 nud noarp | grep -q '172.16.1.10 lladdr
> f0:00:0f:16:01:10 NOARP'], [1])
> +AT_CHECK([ip -6 neigh show dev br-10 nud noarp | grep -q '172:16::10 lladdr
> f0:00:0f:16:01:10 NOARP'], [1])
> +
> +check ovn-nbctl --wait=hv lrp-del lr-ls-evpn
> +check_row_count Advertised_MAC_Binding 0
> +AT_CHECK([ip neigh show dev br-10 nud noarp | grep -q '172.16.1.1 lladdr
> f0:00:0f:16:01:01 NOARP'], [1])
> +AT_CHECK([ip -6 neigh show dev br-10 nud noarp | grep -q '172:16::1 lladdr
> f0:00:0f:16:01:01 NOARP'], [1])
> +
> +check ovn-nbctl --wait=hv ls-del ls-evpn
> +check ovn-nbctl --wait=hv lr-del lr
> +
> +OVN_CLEANUP_CONTROLLER([hv1])
> +
> +OVN_CLEANUP_NORTHD
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/Failed to acquire.*/d
> +/connection dropped.*/d"])
> +AT_CLEANUP
> +])
> +
> OVN_FOR_EACH_NORTHD([
> AT_SETUP([Router reroute policies - output port])
> AT_SKIP_IF([test $HAVE_NC = no])
Regards,
Dumitru
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev