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

Reply via email to