On Mon, Mar 17, 2025 at 10:18 PM Lorenzo Bianconi <
[email protected]> wrote:
> Fix the active mac-binding refresh support for IPv6. In particular, remove
> wrong flows for IPv6 NA in OFTABLE_MAC_CACHE_USE table (79) since they are
> already managed by the more general IPv6 open-flow rules reported below.
>
> table=79, n_packets=2, n_bytes=172, idle_age=4,
> priority=100,ipv6,reg14=0x2,metadata=0x1,dl_src=f0:00:00:01:02:04,ipv6_src=fd12::2
> actions=drop
>
> Add IPv6 unit/system-tests.
>
> Fixes: 1e4d4409f391 ("controller: Send ARP/ND for stale mac_bindings
> entries.")
> Fixes: 9fc291c889bb ("controller: Update OFTABLE_MAC_CACHE_USE for ARP
> reply generated by the tracked device.")
> Signed-off-by: Lorenzo Bianconi <[email protected]>
> ---
>
Hi Lorenzo,
thank you for the fix, I have a few comments down below.
controller/lflow.c | 13 +++--
> controller/mac-cache.c | 2 +-
> tests/ovn.at | 105 ++++++++++++++++++++++++++++++++++++++---
> tests/system-ovn.at | 37 +++++++++++++--
> 4 files changed, 139 insertions(+), 18 deletions(-)
>
> diff --git a/controller/lflow.c b/controller/lflow.c
> index 860869f55..cb44f0b7a 100644
> --- a/controller/lflow.c
> +++ b/controller/lflow.c
> @@ -1398,15 +1398,11 @@ consider_neighbor_flow(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> match_set_dl_type(&lookup_arp_match, htons(ETH_TYPE_IPV6));
> match_set_nw_proto(&lookup_arp_match, 58);
> match_set_icmp_code(&lookup_arp_match, 0);
> - lookup_arp_for_stats_match = lookup_arp_match;
>
> match_set_xxreg(&lookup_arp_match, 0, ntoh128(value));
>
> match_set_dl_type(&mb_cache_use_match, htons(ETH_TYPE_IPV6));
> match_set_ipv6_src(&mb_cache_use_match, &ip6);
> -
> - match_set_icmp_type(&lookup_arp_for_stats_match, 136);
> - match_set_nd_target(&lookup_arp_for_stats_match, &ip6);
> }
>
> match_set_metadata(&get_arp_match, htonll(pb->datapath->tunnel_key));
> @@ -1438,9 +1434,12 @@ consider_neighbor_flow(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
>
> if (b) {
> ofpbuf_clear(&ofpacts);
> - ofctrl_add_flow(flow_table, OFTABLE_MAC_CACHE_USE, priority,
> - b->header_.uuid.parts[0],
> &lookup_arp_for_stats_match,
> - &ofpacts, &b->header_.uuid);
> + if (strchr(ip, '.')) {
> + ofctrl_add_flow(flow_table, OFTABLE_MAC_CACHE_USE, priority,
> + b->header_.uuid.parts[0],
> + &lookup_arp_for_stats_match,
> + &ofpacts, &b->header_.uuid);
> + }
> ofctrl_add_flow(flow_table, OFTABLE_MAC_CACHE_USE, priority,
> b->header_.uuid.parts[0], &mb_cache_use_match,
> &ofpacts, &b->header_.uuid);
> diff --git a/controller/mac-cache.c b/controller/mac-cache.c
> index 0aebb09a4..a67578c48 100644
> --- a/controller/mac-cache.c
> +++ b/controller/mac-cache.c
> @@ -943,7 +943,7 @@ mac_binding_probe_stats_run(
> }
>
> if (laddr.n_ipv4_addrs || laddr.n_ipv6_addrs) {
> - struct in6_addr local = laddr.n_ipv4_addrs
> + struct in6_addr local = IN6_IS_ADDR_V4MAPPED(&mb->data.ip)
> ? in6_addr_mapped_ipv4(laddr.ipv4_addrs[0].addr)
> : laddr.ipv6_addrs[0].addr;
>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 714286596..afde2576f 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -36240,6 +36240,22 @@ send_udp() {
> as $hv ovs-appctl netdev-dummy/receive $dev $packet
> }
>
> +send_udp6() {
> + local hv=$1 dev=$2 hdst=$3 hsrc=$4 idst=$5 isrc=$6
> + local packet=$(fmt_pkt "Ether(dst='${hdst}', src='${hsrc}')/ \
> + IPv6(dst='${idst}', src='${isrc}')/UDP()")
> + as $hv ovs-appctl netdev-dummy/receive $dev $packet
> +}
>
This function is identical to send_udp, can we just use that?
+
> +send_na() {
> + local hv=$1 dev=$2 hdst=$3 hsrc=$4 idst=$5 isrc=$6
> + local packet=$(fmt_pkt "Ether(dst='${hdst}', src='${hsrc}')/ \
> + IPv6(dst='${idst}', src='${isrc}')/ \
> + ICMPv6ND_NA(tgt='${isrc}')/ \
> + ICMPv6NDOptDstLLAddr(lladdr='${hsrc}')")
> + as $hv ovs-appctl netdev-dummy/receive $dev $packet
> +}
> +
> dump_arp() {
> local op=$1 eth_src=$2 eth_dst=$3 spa=$4 tpa=$5 hwdst=$6
>
> @@ -36249,6 +36265,15 @@ dump_arp() {
> echo $packet
> }
>
> +dump_ns() {
> + local hdst=$1 hsrc=$2 idst=$3 isrc=$4 tgt=$5
> + local packet=$(fmt_pkt "Ether(dst='${hdst}', src='${hsrc}')/ \
> + IPv6(dst='${idst}', src='${isrc}')/ \
> + ICMPv6ND_NS(tgt='${tgt}')/
> + ICMPv6NDOptSrcLLAddr(lladdr='${hsrc}')")
> + echo $packet
> +}
> +
> aging_th=10
> net_add n1
> sim_add hv1
> @@ -36262,8 +36287,8 @@ check ovn-nbctl
> \
> -- ls-add ls2
> \
> -- lr-add lr
> \
> -- set logical_router lr options:mac_binding_age_threshold=$aging_th
> \
> - -- lrp-add lr lr-ls1 00:00:00:00:10:00 192.168.10.1/24
> \
> - -- lrp-add lr lr-ls2 00:00:00:00:20:00 192.168.20.1/24
> \
> + -- lrp-add lr lr-ls1 00:00:00:00:10:00 192.168.10.1/24 fd11::1/64
> \
> + -- lrp-add lr lr-ls2 00:00:00:00:20:00 192.168.20.1/24 fd12::1/64
> \
> -- lsp-add ls1 ls1-lr
> \
> -- lsp-set-type ls1-lr router
> \
> -- lsp-set-addresses ls1-lr router
> \
> @@ -36342,6 +36367,32 @@ send_udp hv1 vif2 00:00:00:00:20:00
> 00:00:00:00:10:2b 192.168.10.100 192.168.20.
> OVN_CHECK_PACKETS_CONTAIN([hv1/vif2-tx.pcap], [expected1])
> OVN_CHECK_PACKETS_CONTAIN([hv1/vif1-tx.pcap], [expected2])
>
> +wait_row_count mac_binding 0
> +# Send UDP6 traffic.
> +send_udp6 hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:2a fd12::64 fd11::64
> +send_udp6 hv1 vif2 00:00:00:00:20:00 00:00:00:00:10:2b fd11::64 fd12::64
> +# Send NA to resolve L2 addresses.
> +send_na hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:1a fd11::1 fd11::64
> +send_na hv1 vif2 00:00:00:00:20:00 00:00:00:00:10:1b fd12::1 fd12::64
> +
> +check_row_count mac_binding 1 mac=\"00:00:00:00:10:1a\" ip=\"fd11::64\"
> +check_row_count mac_binding 1 mac=\"00:00:00:00:10:1b\" ip=\"fd12::64\"
> +
> +ts0=$(fetch_column Mac_Binding timestamp mac=\"00:00:00:00:10:1a\"
> ip=\"fd11::64\")
> +uuid=$(fetch_column Mac_Binding _uuid mac=\"00:00:00:00:10:1a\"
> ip=\"fd11::64\")
> +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_CACHE_USE | \
> + awk '/ipv6_src=fd11::64/{print substr($6,10,1)}')
> -ge $((aging_th/2))])
> +send_udp6 hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:2a fd12::64 fd11::64
> +send_udp6 hv1 vif2 00:00:00:00:20:00 00:00:00:00:10:2b fd11::64 fd12::64
> +
> +dump_ns 33:33:ff:00:00:64 00:00:00:00:10:00 ff02::1:ff00:64 fd11::1
> fd11::64 > expected2
> +dump_ns 33:33:ff:00:00:64 00:00:00:00:10:00 ff02::1:ff00:64 fd11::1
> fd11::64 >> expected2
> +OVN_CHECK_PACKETS_CONTAIN([hv1/vif1-tx.pcap], [expected2])
> +
> +send_na hv1 vif1 00:00:00:00:10:00 00:00:00:00:10:1a fd11::1 fd11::64
> +OVS_WAIT_UNTIL([test $(fetch_column Mac_Binding timestamp
> mac=\"00:00:00:00:10:1a\" ip=\"fd11::64\") -gt $ts0])
> +AT_CHECK([test "$(fetch_column Mac_Binding _uuid
> mac=\"00:00:00:00:10:1a\" ip=\"fd11::64\")" = "$uuid"])
> +
> OVN_CLEANUP([hv1])
> AT_CLEANUP
> ])
> @@ -36358,6 +36409,22 @@ send_imcp_echo_req() {
> as $hv ovs-appctl netdev-dummy/receive $dev $packet
> }
>
> +send_icmp6_echo_req() {
> + local hv=$1 dev=$2 hdst=$3 hsrc=$4 idst=$5 isrc=$6
> + local packet=$(fmt_pkt "Ether(dst='${hdst}', src='${hsrc}')/ \
> + IPv6(dst='${idst}',
> src='${isrc}')/ICMPv6EchoRequest()")
> + as $hv ovs-appctl netdev-dummy/receive $dev $packet
> +}
> +
> +send_na() {
> + local hv=$1 dev=$2 hdst=$3 hsrc=$4 idst=$5 isrc=$6
> + local packet=$(fmt_pkt "Ether(dst='${hdst}', src='${hsrc}')/ \
> + IPv6(dst='${idst}', src='${isrc}')/ \
> + ICMPv6ND_NA(tgt='${isrc}')/ \
> + ICMPv6NDOptDstLLAddr(lladdr='${hsrc}')")
> + as $hv ovs-appctl netdev-dummy/receive $dev $packet
> +}
> +
> dump_icmp() {
> local hdst=$1 hsrc=$2 idst=$3 isrc=$4 ttl=$5 type=$6 chksum=$7
> local packet=$(fmt_pkt "Ether(dst='${hdst}', src='${hsrc}')/ \
> @@ -36383,8 +36450,8 @@ check ovn-nbctl
> \
> -- set Logical_Router gw options:chassis="hv1"
> \
> -- set logical_router gw options:mac_binding_age_threshold=$aging_th
> \
> -- set logical_router gw options:dynamic_neigh_routers=true
> \
> - -- lrp-add gw gw-public 00:00:00:00:10:00 192.168.10.1/24
> \
> - -- lrp-add gw gw-join 00:00:00:00:20:00 192.168.20.1/24
> \
> + -- lrp-add gw gw-public 00:00:00:00:10:00 192.168.10.1/24
> fd11::1/64 \
> + -- lrp-add gw gw-join 00:00:00:00:20:00 192.168.20.1/24 fd12::1/64
> \
> -- lsp-add public public-gw
> \
> -- lsp-set-type public-gw router
> \
> -- lsp-set-addresses public-gw router
> \
> @@ -36395,12 +36462,13 @@ check ovn-nbctl
> \
> -- lsp-set-type join-gw router
> \
> -- lsp-set-addresses join-gw router
> \
> -- lsp-set-options join-gw router-port=gw-join
> \
> - -- lrp-add lr lr-join 00:00:00:00:30:00 192.168.20.2/24
> \
> + -- lrp-add lr lr-join 00:00:00:00:30:00 192.168.20.2/24 fd12::2/64
> \
> -- lsp-add join join-lr
> \
> -- lsp-set-type join-lr router
> \
> -- lsp-set-addresses join-lr router
> \
> -- lsp-set-options join-lr router-port=lr-join
> \
> - -- lr-route-add lr 0.0.0.0/0 192.168.20.1
> + -- lr-route-add lr 0.0.0.0/0 192.168.20.1
> \
> + -- lr-route-add lr ::/0 fd12::1
>
> check ovs-vsctl
> \
> -- add-port br-int public
> \
> @@ -36433,10 +36501,10 @@ OVS_WAIT_UNTIL([$(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_BINDING | \
> sed
> 's/reg15=0x.,metadata=0x./reg15=<cleared>,metadata=<cleared>/g' | \
> grep -q
> "reg0=0xc0a81402,reg15=<cleared>,metadata=<cleared>
> actions=mod_dl_dst:00:00:00:00:30:00")])
>
> +n_arp=$(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |awk
> '/arp_spa=192.168.20.2/{print <http://192.168.20.2/%7Bprint>
> substr($4,11,1)}')
> # Check GW router does not send any ARP requests in this case.
> OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_CACHE_USE | \
> awk '/nw_src=192.168.10.100/{print
> <http://192.168.10.100/%7Bprint> substr($6,10,1)}') -ge $((aging_th/2))])
> -n_arp=$(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |awk
> '/arp_spa=192.168.20.2/{print <http://192.168.20.2/%7Bprint>
> substr($4,11,1)}')
> AT_CHECK([test $(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE
> |awk '/arp_spa=192.168.20.2/{print <http://192.168.20.2/%7Bprint>
> substr($4,11,1)}') -eq $n_arp])
>
> send_imcp_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:10:1a
> 192.168.20.2 192.168.10.100
> @@ -36449,6 +36517,29 @@ OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows
> br-int table=OFTABLE_MAC_CACHE_USE |
> send_imcp_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:10:1a
> 192.168.20.2 192.168.10.100
> OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_CACHE_USE |awk '/arp_spa=192.168.20.2/{print
> <http://192.168.20.2/%7Bprint> substr($4,11,1)}') -ge $((n_arp+1))])
>
> +check ovn-nbctl --wait=hv acl-del join
> +wait_row_count mac_binding 0
> +
> +send_icmp6_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:50:01
> fd12::2 fd11::64
> +send_na hv1 vif1 00:00:00:00:10:00 00:00:00:00:50:01 fd11::1 fd11::64
> +check_row_count mac_binding 1 mac=\"00:00:00:00:30:00\" ip=\"fd12::2\"
> +
> +n_ipv6=$(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |awk
> '/ipv6_src=fd12::2/{print substr($4,11,1)}')
> +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_CACHE_USE | \
> + awk '/ipv6_src=fd12::2/{print substr($6,10,1)}')
> -ge $((aging_th/2))])
> +# Check GW router does not send any NS requests in this case.
> +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE
> |awk '/ipv6_src=fd12::2/{print substr($4,11,1)}') -eq $n_ipv6])
> +send_icmp6_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:50:01
> fd12::2 fd11::64
> +
> +# Now drop ICMPv6 echo reply in order to force OVN to send NS for the lr
> mac binding entry.
> +check ovn-nbctl --wait=hv acl-add join from-lport 1010 'inport ==
> "join-lr" && ip6 && icmp6.type == 0x87' allow
> +check ovn-nbctl --wait=hv acl-add join from-lport 1000 'inport ==
> "join-lr" && icmp' drop
> +n_ipv6=$(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |awk
> '/ipv6_src=fd12::2/{print substr($4,11,1)}')
> +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_CACHE_USE | \
> + awk '/ipv6_src=fd12::2/{print substr($6,10,1)}')
> -ge $((aging_th/2))])
> +send_icmp6_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:50:01
> fd12::2 fd11::64
> +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> table=OFTABLE_MAC_CACHE_USE |awk '/ipv6_src=fd12::2/{print
> substr($4,11,1)}') -ge $((n_ipv6+1))])
> +
> OVN_CLEANUP([hv1])
> AT_CLEANUP
> ])
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 55d71248b..8d140954a 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -17277,8 +17277,8 @@ check ovn-nbctl set logical_router lr
> options:mac_binding_age_threshold=5
> check ovn-nbctl ls-add sw
> check ovn-nbctl ls-add public
>
> -check ovn-nbctl lrp-add lr rp-sw 00:00:01:01:02:03 192.168.1.1/24
> -check <http://192.168.1.1/24-check> ovn-nbctl lrp-add lr rp-public
> 00:00:02:01:02:03 172.16.1.1/24
> +check ovn-nbctl lrp-add lr rp-sw 00:00:01:01:02:03 192.168.1.1/24
> fd11::1/64
> +check ovn-nbctl lrp-add lr rp-public 00:00:02:01:02:03 172.16.1.1/24
> fd12::1/64
>
> check ovn-nbctl lsp-add sw sw-rp -- set Logical_Switch_Port sw-rp \
> type=router options:router-port=rp-sw \
> @@ -17290,7 +17290,9 @@ check ovn-nbctl lsp-add public public-rp -- set
> Logical_Switch_Port public-rp \
>
> ADD_NAMESPACES(alice)
> ADD_VETH(alice, alice, br-int, "192.168.1.2/24", "f0:00:00:01:02:03",
> "192.168.1.1")
> -check ovn-nbctl lsp-add sw alice -- lsp-set-addresses alice
> "f0:00:00:01:02:03 192.168.1.2"
> +NS_CHECK_EXEC([alice], [ip a a fd11::2/64 dev alice nodad])
>
nit: ADD_VETH can be used to setup both IPv4 and IPv6
+NS_CHECK_EXEC([alice], [ip -6 route add default via fd11::1])
> +check ovn-nbctl lsp-add sw alice -- lsp-set-addresses alice
> "f0:00:00:01:02:03 192.168.1.2 fd11::2"
>
> check ovs-vsctl set Open_vSwitch .
> external-ids:ovn-bridge-mappings=phynet:br-ext
> check ovn-nbctl lsp-add public public \
> @@ -17300,16 +17302,25 @@ check ovn-nbctl lsp-add public public \
>
> ADD_NAMESPACES(gw)
> ADD_VETH(gw0, gw, br-ext, "172.16.1.2/24", "f0:00:00:01:02:04",
> "172.16.1.1")
> +NS_CHECK_EXEC([gw], [ip a a fd12::2/64 dev gw0 nodad])
> +NS_CHECK_EXEC([gw], [ip -6 route add default via fd12::1])
> ADD_VETH(gw1, gw, br-gw, "172.16.2.2/24", "f0:00:00:01:03:04")
> +NS_CHECK_EXEC([gw], [ip a a fd13::2/64 dev gw1 nodad])
>
> NS_CHECK_EXEC([gw], [sysctl -w net.ipv4.conf.all.forwarding=1],[0], [dnl
> net.ipv4.conf.all.forwarding = 1
> ])
> +NS_CHECK_EXEC([gw], [sysctl -w net.ipv6.conf.all.forwarding=1],[0], [dnl
> +net.ipv6.conf.all.forwarding = 1
> +])
>
> ADD_NAMESPACES(bob)
> ADD_VETH(bob, bob, br-gw, "172.16.2.10/24", "f0:00:00:01:02:06",
> "172.16.2.2")
> +NS_CHECK_EXEC([bob], [ip a a fd13::a/64 dev bob nodad])
> +NS_CHECK_EXEC([bob], [ip -6 route add default via fd13::2])
>
> check ovn-nbctl lr-route-add lr 0.0.0.0/0 172.16.1.2
> +check ovn-nbctl lr-route-add lr ::/0 fd12::2
> check ovn-nbctl --wait=hv sync
>
> NS_CHECK_EXEC([alice], [ping -q -c 3 -i 0.3 -w 2 172.16.2.10 |
> FORMAT_PING], \
> @@ -17337,6 +17348,26 @@ OVS_WAIT_UNTIL([
> # Wait for the mac binding entry to expire.
> wait_row_count MAC_Binding 0
>
> +NS_CHECK_EXEC([alice], [ping -6 -q -c 3 -i 0.3 -w 2 fd13::a |
> FORMAT_PING], \
> +[0], [dnl
> +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> +])
> +
> +check_row_count mac_binding 1 mac=\"f0:00:00:01:02:04\" ip=\"fd12::2\"
> +mac_binding_uuid=$(fetch_column mac_binding _uuid
> mac=\"f0:00:00:01:02:04\" ip=\"fd12::2\")
> +NETNS_START_TCPDUMP([gw], [-n -c 2 -i gw0 icmp6 and ip6[[40]] == 0x87],
> [gw6])
> +
> +NS_CHECK_EXEC([alice], [ping -6 -q -c 30 -i 0.5 fd13::a | FORMAT_PING], \
> +[0], [dnl
> +30 packets transmitted, 30 received, 0% packet loss, time 0ms
> +])
> +
> +AT_CHECK([test "$(fetch_column mac_binding _uuid
> mac=\"f0:00:00:01:02:04\" ip=\"fd12::2\")" = "$mac_binding_uuid"])
> +OVS_WAIT_UNTIL([
> + n_ns=$(cat gw6.tcpdump | wc -l)
> + test ${n_ns} -ge 2
> +])
> +
> OVN_CLEANUP_CONTROLLER([hv1])
>
> as ovn-sb
> --
> 2.48.1
>
>
Other than that it looks good, thanks.
Acked-by: Ales Musil <[email protected]>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev