Native tunnels snoop the outer Ethernet source MAC of every IPv4/IPv6
data packet in terminate_native_tunnel() and call tnl_neigh_set().
That lets BFD recover when the remote VTEP NIC MAC changes, so the
default stays enabled.

The outer source MAC is the last-hop MAC, not necessarily the remote
VTEP MAC. Under ECMP or MLAG, packets from one peer can flap last-hop
MACs. Each mismatch deletes the tnl-neigh entry and seq_change()s
tnl_conf_seq, which revalidates every datapath flow.

Add Interface option neigh_snoop (default true). When false on the
OpenFlow tunnel port that receive matching selects for the packet,
skip the data-packet tnl_neigh_set() path. At terminate time the
packet is still on the physical port, so build receive tunnel metadata
from the outer IP and the encapsulation key (parsed from the native
vport type: vxlan, geneve, or gtpu) and reuse tnl_find() the same way
tnl_port_receive() does. ARP/ND and GARP snooping via tnl_neigh_snoop()
is unchanged.

This option is userspace native tunneling only.

Signed-off-by: Girish Kumar <[email protected]>
---
NEWS | 6 ++
lib/netdev-vport.c | 10 +++
lib/netdev.h | 1 +
lib/tnl-ports.c | 27 +++++++-
lib/tnl-ports.h | 1 +
ofproto/ofproto-dpif-xlate.c | 116 +++++++++++++++++++++++++++++++++-
ofproto/tunnel.c | 36 +++++++++++
ofproto/tunnel.h | 3 +
tests/
https://www.google.com/url?q=http://tunnel-push-pop-ipv6.at&source=gmail&ust=1788189854353000&sa=E
| 48 ++++++++++++++
tests/
https://www.google.com/url?q=http://tunnel-push-pop.at&source=gmail&ust=1788189854353000&sa=E
| 48 ++++++++++++++
vswitchd/vswitch.xml | 13 ++++
11 files changed, 306 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index de1a030..a57914f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,11 @@
Post-v4.0.0
--------------------
+ - Userspace datapath:
+ * Native tunnels accept a per-tunnel Interface 'neigh_snoop' option
+ (default true). Setting 'options:neigh_snoop=false' skips updating
+ the tunnel neighbor cache from the outer source MAC of encapsulated
+ data packets on that Interface. Userspace native tunneling only.
+ ARP/ND snooping is unchanged.


v4.0.0 - 17 Aug 2026
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index d11269d..a28af1c 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -228,6 +228,7 @@ netdev_vport_construct(struct netdev *netdev_)
}

tnl_cfg->dont_fragment = true;
+ tnl_cfg->neigh_snoop = true;
tnl_cfg->ttl = DEFAULT_TTL;

ovsrcu_set(&dev->tnl_cfg, tnl_cfg);
@@ -638,6 +639,7 @@ set_tunnel_config(struct netdev *dev_, const struct
smap *args, char **errp)

needs_dst_port = netdev_vport_needs_dst_port(dev_);
tnl_cfg.dont_fragment = true;
+ tnl_cfg.neigh_snoop = true;

SMAP_FOR_EACH (node, args) {
if (!strcmp(node->key, "remote_ip")) {
@@ -697,6 +699,10 @@ set_tunnel_config(struct netdev *dev_, const struct
smap *args, char **errp)
if (!strcmp(node->value, "false")) {
tnl_cfg.dont_fragment = false;
}
+ } else if (!strcmp(node->key, "neigh_snoop")) {
+ if (!strcmp(node->value, "false")) {
+ tnl_cfg.neigh_snoop = false;
+ }
} else if (!strcmp(node->key, "key") ||
!strcmp(node->key, "in_key") ||
!strcmp(node->key, "out_key") ||
@@ -1045,6 +1051,10 @@ get_tunnel_config(const struct netdev *dev, struct
smap *args)
smap_add(args, "df_default", "false");
}

+ if (!tnl_cfg->neigh_snoop) {
+ smap_add(args, "neigh_snoop", "false");
+ }
+
if (tnl_cfg->set_egress_pkt_mark) {
smap_add_format(args, "egress_pkt_mark",
"%"PRIu32, tnl_cfg->egress_pkt_mark);
diff --git a/lib/netdev.h b/lib/netdev.h
index 5e093b0..42c82bd 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -159,6 +159,7 @@ struct netdev_tunnel_config {

enum netdev_tnl_csum csum;
bool dont_fragment;
+ bool neigh_snoop;
enum netdev_pt_mode pt_mode;

bool set_seq;
diff --git a/lib/tnl-ports.c b/lib/tnl-ports.c
index 56119b3..2e9030d 100644
--- a/lib/tnl-ports.c
+++ b/lib/tnl-ports.c
@@ -53,6 +53,7 @@ struct tnl_port {
struct ovs_refcount ref_cnt;
ovs_be16 tp_port;
uint8_t nw_proto;
+ const char *type;
char dev_name[IFNAMSIZ];
struct ovs_list node;
};
@@ -180,7 +181,8 @@ tnl_type_to_nw_proto(const char type[], uint8_t
nw_protos[2])

static void
tnl_port_map_insert__(odp_port_t port, ovs_be16 tp_port,
- const char dev_name[], uint8_t nw_proto)
+ const char dev_name[], uint8_t nw_proto,
+ const char type[])
{
struct tnl_port *p;
struct ip_device *ip_dev;
@@ -197,6 +199,7 @@ tnl_port_map_insert__(odp_port_t port, ovs_be16 tp_port,
p->port = port;
p->tp_port = tp_port;
p->nw_proto = nw_proto;
+ p->type = type;
ovs_strlcpy(p->dev_name, dev_name, sizeof p->dev_name);
ovs_refcount_init(&p->ref_cnt);
ovs_list_insert(&port_list, &p->node);
@@ -220,7 +223,8 @@ tnl_port_map_insert(odp_port_t port, ovs_be16 tp_port,

for (i = 0; i < 2; i++) {
if (nw_protos[i]) {
- tnl_port_map_insert__(port, tp_port, dev_name, nw_protos[i]);
+ tnl_port_map_insert__(port, tp_port, dev_name, nw_protos[i],
+ type);
}
}
}
@@ -308,6 +312,25 @@ tnl_port_map_lookup(struct flow *flow, struct
flow_wildcards *wc)
return (cr) ? tnl_port_cast(cr)->portno : ODPP_NONE;
}

+/* Returns the native vport type ("vxlan", "geneve", "gtpu", ...) for
+ * 'port', or NULL if 'port' is not in the map. */
+const char *
+tnl_port_map_get_type(odp_port_t port)
+{
+ const char *type = NULL;
+ struct tnl_port *p;
+
+ ovs_mutex_lock(&mutex);
+ LIST_FOR_EACH (p, node, &port_list) {
+ if (p->port == port) {
+ type = p->type;
+ break;
+ }
+ }
+ ovs_mutex_unlock(&mutex);
+ return type;
+}
+
static void
tnl_port_show_v(struct ds *ds)
{
diff --git a/lib/tnl-ports.h b/lib/tnl-ports.h
index 61ca0f8..284b117 100644
--- a/lib/tnl-ports.h
+++ b/lib/tnl-ports.h
@@ -25,6 +25,7 @@
#include "util.h"

odp_port_t tnl_port_map_lookup(struct flow *flow, struct flow_wildcards
*wc);
+const char *tnl_port_map_get_type(odp_port_t);

void tnl_port_map_insert(odp_port_t, ovs_be16 tp_port,
const char dev_name[], const char type[]);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 764dbd6..11de7a3 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4435,6 +4435,119 @@ static bool check_neighbor_reply(struct xlate_ctx
*ctx, struct flow *flow)
return false;
}

+/* Encapsulation key from a native-tunnel packet still on the phy port.
+ * 'type' is the native vport type for tnl_odp_port (vxlan, geneve, gtpu).
+ * Geneve stores the VNI in the same 4 bytes as VXLAN; GTP does not.
+ * GRE uses the optional key. Returns 0 if the type is unknown or the
+ * key is absent. */
+static ovs_be64
+native_tnl_recv_key(const struct dp_packet *packet, const struct flow
*flow,
+ const char *type)
+{
+ const void *l4;
+ size_t l4_size;
+
+ if (!packet) {
+ return 0;
+ }
+
+ l4 = dp_packet_l4(packet);
+ if (!l4) {
+ return 0;
+ }
+ l4_size = dp_packet_l4_size(packet);
+
+ if (flow->nw_proto == IPPROTO_UDP) {
+ if (!type) {
+ return 0;
+ }
+
+ if (!strcmp(type, "vxlan")) {
+ const struct vxlanhdr *vxh;
+
+ if (l4_size < UDP_HEADER_LEN + sizeof *vxh) {
+ return 0;
+ }
+ vxh = ALIGNED_CAST(const struct vxlanhdr *,
+ (const char *) l4 + UDP_HEADER_LEN);
+ return htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ }
+
+ if (!strcmp(type, "geneve")) {
+ const struct genevehdr *gnh;
+
+ if (l4_size < UDP_HEADER_LEN + sizeof *gnh) {
+ return 0;
+ }
+ gnh = ALIGNED_CAST(const struct genevehdr *,
+ (const char *) l4 + UDP_HEADER_LEN);
+ return htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
+ }
+
+ if (!strcmp(type, "gtpu")) {
+ const struct gtpuhdr *gtph;
+
+ if (l4_size < UDP_HEADER_LEN + sizeof *gtph) {
+ return 0;
+ }
+ gtph = ALIGNED_CAST(const struct gtpuhdr *,
+ (const char *) l4 + UDP_HEADER_LEN);
+ return be32_to_be64(get_16aligned_be32(&gtph->teid));
+ }
+
+ return 0;
+ }
+
+ if (flow->nw_proto == IPPROTO_GRE) {
+ const struct gre_base_hdr *greh = l4;
+ const ovs_16aligned_be32 *options;
+ size_t hlen = sizeof *greh;
+
+ if (l4_size < hlen) {
+ return 0;
+ }
+ if (greh->flags & htons(GRE_CSUM)) {
+ hlen += 4;
+ }
+ if (!(greh->flags & htons(GRE_KEY))) {
+ return 0;
+ }
+ hlen += 4;
+ if (l4_size < hlen) {
+ return 0;
+ }
+ options = ALIGNED_CAST(const ovs_16aligned_be32 *,
+ (const char *) greh + hlen - 4);
+ return be32_to_be64(get_16aligned_be32(options));
+ }
+
+ return 0;
+}
+
+/* options:neigh_snoop from the OpenFlow tunnel port that receive matching
+ * would select for this packet. Default on. */
+static bool
+native_tnl_neigh_snoop(const struct xlate_ctx *ctx, const struct flow
*flow,
+ odp_port_t tnl_odp_port)
+{
+ const struct netdev_tunnel_config *cfg;
+ const struct ofport_dpif *ofport;
+ const struct xport *xport;
+ const char *type;
+ ovs_be64 tun_id;
+
+ type = tnl_port_map_get_type(tnl_odp_port);
+ tun_id = native_tnl_recv_key(ctx->xin->packet, flow, type);
+ ofport = tnl_port_receive_native(flow, tnl_odp_port, tun_id);
+ xport = xport_lookup(ctx->xcfg, ofport);
+ if (!xport || !xport->netdev) {
+ return true;
+ }
+
+ cfg = netdev_get_tunnel_config(xport->netdev);
+ return !cfg || cfg->neigh_snoop;
+}
+
static bool
terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport,
struct flow *flow, struct flow_wildcards *wc,
@@ -4460,7 +4573,8 @@ terminate_native_tunnel(struct xlate_ctx *ctx, const
struct xport *xport,
ctx->xin->allow_side_effects);
} else if (*tnl_port != ODPP_NONE &&
ctx->xin->allow_side_effects &&
- dl_type_is_ip_any(flow->dl_type)) {
+ dl_type_is_ip_any(flow->dl_type) &&
+ native_tnl_neigh_snoop(ctx, flow, *tnl_port)) {
struct eth_addr mac = flow->dl_src;
struct in6_addr s_ip6;

diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index d8a2895..6001d50 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -335,6 +335,42 @@ out:
return ofport;
}

+/* Like tnl_port_receive(), but 'flow' still has the outer headers from the
+ * physical port. 'tnl_odp_port' is the shared native vport from
+ * tnl_port_map_lookup() and 'tun_id' is the encapsulation key. */
+const struct ofport_dpif *
+tnl_port_receive_native(const struct flow *flow, odp_port_t tnl_odp_port,
+ ovs_be64 tun_id) OVS_EXCLUDED(rwlock)
+{
+ const struct ofport_dpif *ofport = NULL;
+ struct tnl_port *tnl_port;
+ struct flow recv_flow;
+
+ memset(&recv_flow, 0, sizeof recv_flow);
+ recv_flow.packet_type = flow->packet_type;
+ recv_flow.in_port.odp_port = tnl_odp_port;
+ recv_flow.tunnel.tun_id = tun_id;
+ recv_flow.tunnel.flags = FLOW_TNL_F_KEY;
+
+ if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ recv_flow.tunnel.ip_src = flow->nw_src;
+ recv_flow.tunnel.ip_dst = flow->nw_dst;
+ } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+ recv_flow.tunnel.ipv6_src = flow->ipv6_src;
+ recv_flow.tunnel.ipv6_dst = flow->ipv6_dst;
+ } else {
+ return NULL;
+ }
+
+ fat_rwlock_rdlock(&rwlock);
+ tnl_port = tnl_find(&recv_flow);
+ if (tnl_port) {
+ ofport = tnl_port->ofport;
+ }
+ fat_rwlock_unlock(&rwlock);
+ return ofport;
+}
+
/* Should be called at the beginning of action translation to initialize
* wildcards and perform any actions based on receiving on tunnel port.
*
diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h
index 323f3fa..c70e899 100644
--- a/ofproto/tunnel.h
+++ b/ofproto/tunnel.h
@@ -40,6 +40,9 @@ int tnl_port_add(const struct ofport_dpif *, const struct
netdev *,
void tnl_port_del(const struct ofport_dpif *, odp_port_t);

const struct ofport_dpif *tnl_port_receive(const struct flow *);
+const struct ofport_dpif *tnl_port_receive_native(const struct flow *,
+ odp_port_t tnl_odp_port,
+ ovs_be64 tun_id);
void tnl_wc_init(struct flow *, struct flow_wildcards *);
bool tnl_process_ecn(struct flow *);
odp_port_t tnl_port_send(const struct ofport_dpif *, struct flow *,
diff --git a/tests/
https://www.google.com/url?q=http://tunnel-push-pop-ipv6.at&source=gmail&ust=1788189854354000&sa=E
b/tests/
https://www.google.com/url?q=http://tunnel-push-pop-ipv6.at&source=gmail&ust=1788189854354000&sa=E
index ec757f7..38dd077 100644
--- a/tests/
https://www.google.com/url?q=http://tunnel-push-pop-ipv6.at&source=gmail&ust=1788189854354000&sa=E
+++ b/tests/
https://www.google.com/url?q=http://tunnel-push-pop-ipv6.at&source=gmail&ust=1788189854354000&sa=E
@@ -656,6 +656,54 @@ AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort],
[0], [dnl
2001:cafe::93 f8:bc:12:44:34:b7 br0
])

+dnl Disable data-packet neigh snoop on t2 only. A different outer MAC
+dnl on that Interface must not replace the complete tnl-neigh entry.
+AT_CHECK([ovs-vsctl set Interface t2 options:neigh_snoop=false])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'aa55aa550000f8bc1244cafe86dd60000000003a11402001cafe0000000000000000000000922001cafe000000000000000000000088c85312b5003abc700c00000300007b00ffffffffffff00000000000008004500001c0001000040117cce7f0000017f0000010035003500080172'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
+2001:cafe::92 f8:bc:12:44:34:b6 br0
+2001:cafe::93 f8:bc:12:44:34:b7 br0
+])
+
+dnl t3 stays default-on. A data packet for 2001:cafe::93 must still update.
+dnl Use a different outer MAC so this misses the t2 megaflow and re-xlates.
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'aa55aa550000f8bc1244caff86dd60000000003a11402001cafe0000000000000000000000932001cafe000000000000000000000088c85312b5003abc700c00000300000000ffffffffffff00000000000008004500001c0001000040117cce7f0000017f0000010035003500080172'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
+2001:cafe::92 f8:bc:12:44:34:b6 br0
+2001:cafe::93 f8:bc:12:44:ca:ff br0
+])
+
+dnl ND snooping still updates the cache when neigh_snoop is false.
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'in_port(1),eth(src=f8:bc:12:44:ca:fe,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:ca:fe)'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
+2001:cafe::92 f8:bc:12:44:ca:fe br0
+2001:cafe::93 f8:bc:12:44:ca:ff br0
+])
+
+dnl Restore the complete entries used by later push checks.
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b6)'])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'in_port(1),eth(src=f8:bc:12:44:34:b7,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::93,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::93,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b7)'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
+2001:cafe::92 f8:bc:12:44:34:b6 br0
+2001:cafe::93 f8:bc:12:44:34:b7 br0
+])
+
dnl Disable checksum from VXLAN port.
AT_CHECK([ovs-vsctl set Interface t3 options:csum=false])
AT_CHECK([ovs-ofctl del-flows int-br])
diff --git a/tests/
https://www.google.com/url?q=http://tunnel-push-pop.at&source=gmail&ust=1788189854354000&sa=E
b/tests/
https://www.google.com/url?q=http://tunnel-push-pop.at&source=gmail&ust=1788189854354000&sa=E
index ab393cf..79cec86 100644
--- a/tests/
https://www.google.com/url?q=http://tunnel-push-pop.at&source=gmail&ust=1788189854354000&sa=E
+++ b/tests/
https://www.google.com/url?q=http://tunnel-push-pop.at&source=gmail&ust=1788189854354000&sa=E
@@ -759,6 +759,54 @@ AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 |
sort], [0], [dnl
1.1.2.93 f8:bc:12:44:34:b7 br0
])

+dnl Disable data-packet neigh snoop on t2 only. A different outer MAC
+dnl on that Interface must not replace the complete tnl-neigh entry.
+AT_CHECK([ovs-vsctl set Interface t2 options:neigh_snoop=false])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'aa55aa550000f8bc1244cafe08004500004e00010000401173e90101025c01010258c85312b5003a8cd40c00000300007b00ffffffffffff00000000000008004500001c0001000040117cce7f0000017f0000010035003500080172'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
+1.1.2.92 f8:bc:12:44:34:b6 br0
+1.1.2.93 f8:bc:12:44:34:b7 br0
+])
+
+dnl t3 stays default-on. A data packet for 1.1.2.93 must still update.
+dnl Use a different outer MAC so this misses the t2 megaflow and re-xlates.
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'aa55aa550000f8bc1244caff08004500004e00010000401173e80101025d01010258c85312b5003a00000c00000300000000ffffffffffff00000000000008004500001c0001000040117cce7f0000017f0000010035003500080172'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
+1.1.2.92 f8:bc:12:44:34:b6 br0
+1.1.2.93 f8:bc:12:44:ca:ff br0
+])
+
+dnl ARP snooping still updates the cache when neigh_snoop is false.
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:ca:fe,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:ca:fe,tha=00:00:00:00:00:00)'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
+1.1.2.92 f8:bc:12:44:ca:fe br0
+1.1.2.93 f8:bc:12:44:ca:ff br0
+])
+
+dnl Restore the complete entries used by later push checks.
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)'])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0
'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b7,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.93,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b7,tha=00:00:00:00:00:00)'])
+
+ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
+1.1.2.92 f8:bc:12:44:34:b6 br0
+1.1.2.93 f8:bc:12:44:34:b7 br0
+])
+
ovs-appctl time/warp 10000

AT_CHECK([ovs-vsctl del-port int-br t3 \
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 4eec70f..acd1bd0 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -3102,6 +3102,19 @@
to <code>false</code> to disable.
</column>

+ <column name="options" key="neigh_snoop"
+ type='{"type": "boolean"}'>
+ Optional. Userspace native tunneling only. If enabled (the
+ default), the userspace datapath updates the native-tunnel neighbor
+ cache from the outer Ethernet source MAC of encapsulated IPv4 and
+ IPv6 data packets received on this tunnel Interface. That lets
+ BFD recover after the remote VTEP NIC MAC changes. Set to
+ <code>false</code> to skip that data-packet snooping, which can
+ otherwise flap the neighbor entry when ECMP or MLAG changes the
+ last-hop MAC. ARP, GARP, and Neighbor Discovery snooping is not
+ affected.
+ </column>
+
<column name="options" key="egress_pkt_mark">
Optional. The pkt_mark to be set on the encapsulating packet. This
option sets packet mark for the tunnel endpoint for all tunnel packets
-- 
2.47.3
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to