On 5/14/24 00:11, William Tu wrote:
> Add route-table support for ipv4 dst via ipv6. One use case is BGP
> unnumbered, a mechanism that establishes peering sessions without the
> need to explicitly configure IPv4 addresses on the interfaces involved
> in the peering. Without using IPv4 address assignments, it uses
> link-local IPv6 addresses of the directly connected neighbors for
> peering purposes. For example, BGP might install the following route:
> $ ip route get 100.87.18.3
>     100.87.18.3 via inet6 fe80::920a:84ff:fe9e:9570 \
>     dev br-phy src 100.87.18.6
> 
> Note that the v6 addr fe80::920a:84ff:fe9e:9570 is not being used in
> the packet header, but only used for lookup the out dev br-phy.
> Currently OVS can only support either all-ipv4 or all-ipv6, the patch
> adds support for such use case.
> 
> Reported-at: 
> https://mail.openvswitch.org/pipermail/ovs-discuss/2024-January/052908.html
> Acked-by: Simon Horman <ho...@ovn.org>
> Signed-off-by: William Tu <w...@nvidia.com>
> ---
> v3: add vxlan test, remove rfc
> v2: fix CI error
> ---
>  lib/ovs-router.c         | 34 ++++++++++++++--------------
>  lib/route-table.c        | 21 ++++++++++++++++++
>  tests/ovs-router.at      | 33 +++++++++++++++++++++++++++
>  tests/system-route.at    | 24 ++++++++++++++++++++
>  tests/tunnel-push-pop.at | 48 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 142 insertions(+), 18 deletions(-)
> 
> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
> index 3d84c9a30a8f..3ee927e6f7de 100644
> --- a/lib/ovs-router.c
> +++ b/lib/ovs-router.c
> @@ -415,7 +415,6 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
>      unsigned int plen;
>      ovs_be32 src = 0;
>      ovs_be32 gw = 0;
> -    bool is_ipv6;
>      ovs_be32 ip;
>      int err;
>      int i;
> @@ -423,9 +422,8 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
>      if (scan_ipv4_route(argv[1], &ip, &plen)) {
>          in6_addr_set_mapped_ipv4(&ip6, ip);
>          plen += 96;
> -        is_ipv6 = false;
>      } else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
> -        is_ipv6 = true;
> +        ;
>      } else {
>          unixctl_command_reply_error(conn,
>                                      "Invalid 'ip/plen' parameter");
> @@ -438,21 +436,21 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
>              continue;
>          }
>  
> -        if (is_ipv6) {
> -            if (ovs_scan(argv[i], "src="IPV6_SCAN_FMT, src6_s) &&
> -                ipv6_parse(src6_s, &src6)) {
> -                continue;
> -            }
> -            if (ipv6_parse(argv[i], &gw6)) {
> -                continue;
> -            }
> -        } else {
> -            if (ovs_scan(argv[i], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) {
> -                continue;
> -            }
> -            if (ip_parse(argv[i], &gw)) {
> -                continue;
> -            }
> +        if (ovs_scan(argv[i], "src="IPV6_SCAN_FMT, src6_s) &&
> +            ipv6_parse(src6_s, &src6)) {
> +            continue;
> +        }
> +
> +        if (ipv6_parse(argv[i], &gw6)) {
> +            continue;
> +        }
> +
> +        if (ovs_scan(argv[i], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) {
> +            continue;
> +        }
> +
> +        if (ip_parse(argv[i], &gw)) {
> +            continue;
>          }
>  
>          unixctl_command_reply_error(conn,
> diff --git a/lib/route-table.c b/lib/route-table.c
> index f1fe32714e8d..58412711888f 100644
> --- a/lib/route-table.c
> +++ b/lib/route-table.c
> @@ -232,6 +232,7 @@ route_table_parse(struct ofpbuf *buf, struct 
> route_table_msg *change)
>          [RTA_OIF] = { .type = NL_A_U32, .optional = true },
>          [RTA_GATEWAY] = { .type = NL_A_U32, .optional = true },
>          [RTA_MARK] = { .type = NL_A_U32, .optional = true },
> +        [RTA_VIA] = { .type = NL_A_UNSPEC, .optional = true },
>          [RTA_PREFSRC] = { .type = NL_A_U32, .optional = true },
>          [RTA_TABLE] = { .type = NL_A_U32, .optional = true },
>      };
> @@ -241,6 +242,7 @@ route_table_parse(struct ofpbuf *buf, struct 
> route_table_msg *change)
>          [RTA_OIF] = { .type = NL_A_U32, .optional = true },
>          [RTA_MARK] = { .type = NL_A_U32, .optional = true },
>          [RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true },
> +        [RTA_VIA] = { .type = NL_A_UNSPEC, .optional = true },
>          [RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true },
>          [RTA_TABLE] = { .type = NL_A_U32, .optional = true },
>      };
> @@ -333,6 +335,25 @@ route_table_parse(struct ofpbuf *buf, struct 
> route_table_msg *change)
>                      nl_attr_get_in6_addr(attrs[RTA_PREFSRC]);
>              }
>          }
> +        if (attrs[RTA_VIA]) {
> +            const struct rtvia *via;
> +            ovs_be32 gw;
> +
> +            via = nl_attr_get(attrs[RTA_VIA]);
> +            switch (via->rtvia_family) {
> +            case AF_INET:
> +                gw = *(ALIGNED_CAST(ovs_be32 *, via->rtvia_addr));
> +                in6_addr_set_mapped_ipv4(&change->rd.rta_gw, gw);
> +                break;
> +            case AF_INET6:
> +                change->rd.rta_gw = *(ALIGNED_CAST(struct in6_addr *,
> +                                                    via->rtvia_addr));
> +                break;
> +            default:
> +                VLOG_WARN("Unknown address family %d\n", via->rtvia_family);
> +                return 0;
> +            }
> +        }
>          if (attrs[RTA_GATEWAY]) {
>              if (ipv4) {
>                  ovs_be32 gw;
> diff --git a/tests/ovs-router.at b/tests/ovs-router.at
> index b3314b3dff0d..f34dd3c99f5d 100644
> --- a/tests/ovs-router.at
> +++ b/tests/ovs-router.at
> @@ -109,6 +109,39 @@ User: 2001:db8:beef::14/128 MARK 14 dev br0 GW 
> 2001:db8:cafe::1 SRC 2001:db8:caf
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
>  
> +AT_SETUP([appctl - route/add with ipv4 via ipv6])
> +AT_KEYWORDS([ovs_router])
> +OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy])
> +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.168.9.2/24], [0], [OK
> +])
> +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.168.9.3/24], [0], [OK
> +])
> +
> +# defualt pick the first IP, 192.168.9.2, as src
> +AT_CHECK([ovs-appctl ovs/route/add 192.168.9.10/32 br0 
> fe80::920a:84ff:beef:9510], [0], [OK
> +])
> +AT_CHECK([ovs-appctl ovs/route/add 192.168.9.11/32 br0 
> fe80::920a:84ff:beef:9511 src=192.168.9.2], [0], [OK
> +])
> +AT_CHECK([ovs-appctl ovs/route/add 192.168.9.12/32 br0 
> fe80::920a:84ff:beef:9512 src=192.168.9.3], [0], [OK
> +])
> +AT_CHECK([ovs-appctl ovs/route/add 192.168.9.13/32 br0 
> fe80::920a:84ff:beef:9513 pkt_mark=13 src=192.168.9.3], [0], [OK
> +])
> +
> +AT_CHECK([ovs-appctl ovs/route/show | grep User | grep beef | sort], [0], 
> [dnl
> +User: 192.168.9.10/32 dev br0 GW fe80::920a:84ff:beef:9510 SRC 192.168.9.2
> +User: 192.168.9.11/32 dev br0 GW fe80::920a:84ff:beef:9511 SRC 192.168.9.2
> +User: 192.168.9.12/32 dev br0 GW fe80::920a:84ff:beef:9512 SRC 192.168.9.3
> +User: 192.168.9.13/32 MARK 13 dev br0 GW fe80::920a:84ff:beef:9513 SRC 
> 192.168.9.3
> +])
> +
> +# DST and SRC must be in the same subnet domain
> +AT_CHECK([ovs-appctl ovs/route/add 192.168.10.12/32 br0 
> fe80::920a:84ff:beef:9512 src=192.168.9.3], [2], [], [dnl
> +Error while inserting route.
> +ovs-appctl: ovs-vswitchd: server returned an error
> +])
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
>  AT_SETUP([appctl - route/lookup])
>  AT_KEYWORDS([ovs_router])
>  OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy])
> diff --git a/tests/system-route.at b/tests/system-route.at
> index c0ecad6cfb49..fd698321b401 100644
> --- a/tests/system-route.at
> +++ b/tests/system-route.at
> @@ -65,6 +65,30 @@ Cached: fc00:db8:beef::13/128 dev br0 GW fc00:db8:cafe::1 
> SRC fc00:db8:cafe::2])
>  OVS_TRAFFIC_VSWITCHD_STOP
>  AT_CLEANUP
>  
> +AT_SETUP([ovs-route - add system route ipv4 via ipv6])
> +AT_KEYWORDS([route])
> +OVS_TRAFFIC_VSWITCHD_START()
> +AT_CHECK([ip link set br0 up])
> +
> +AT_CHECK([ip addr add 192.168.9.2/24 dev br0], [0], [stdout])
> +AT_CHECK([ip addr add 192.168.9.3/24 dev br0], [0], [stdout])
> +
> +AT_CHECK([ip -6 addr add fc00:db8:cafe::2/64 dev br0], [0], [stdout])
> +AT_CHECK([ip -6 addr add fc00:db8:cafe::3/64 dev br0], [0], [stdout])
> +
> +AT_CHECK([ip route add 192.168.9.12/32 dev br0 via inet6 
> fe80::920a:84ff:fe9e:9512 src 192.168.9.2], [0], [stdout])
> +AT_CHECK([ip route add 192.168.9.13/32 dev br0 via inet6 
> fe80::920a:84ff:fe9e:9513 src 192.168.9.3], [0], [stdout])
> +
> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep -E 
> '192.168.9.1[[23]]/32' | sort], [dnl
> +Cached: 192.168.9.12/32 dev br0 GW fe80::920a:84ff:fe9e:9512 SRC 192.168.9.2
> +Cached: 192.168.9.13/32 dev br0 GW fe80::920a:84ff:fe9e:9513 SRC 
> 192.168.9.3])
> +
> +AT_CHECK([ovs-appctl ovs/route/add 192.168.9.14/32 br0 
> fe80::920a:84ff:fe9e:9514], [0], [OK
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
>  dnl Checks that OVS doesn't use routes from non-standard tables.
>  AT_SETUP([ovs-route - route tables])
>  AT_KEYWORDS([route])
> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
> index 508737c53ec6..0c8f3862cce9 100644
> --- a/tests/tunnel-push-pop.at
> +++ b/tests/tunnel-push-pop.at
> @@ -196,6 +196,54 @@ OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep 
> 100022eb0000000120000237 | wc -l`
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
>  
> +AT_SETUP([tunnel_push_pop - v4 via v6 route])
> +
> +OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy 
> ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
> +AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], 
> [0])
> +AT_CHECK([ovs-vsctl add-port int-br t1 -- set Interface t1 type=vxlan \
> +                       options:remote_ip=1.1.2.92 options:key=123 
> ofport_request=1\
> +                       ], [0])
> +
> +AT_CHECK([ovs-appctl dpif/show], [0], [dnl
> +dummy@ovs-dummy: hit:0 missed:0
> +  br0:
> +    br0 65534/100: (dummy-internal)
> +    p0 1/1: (dummy)
> +  int-br:
> +    int-br 65534/2: (dummy-internal)
> +    t1 1/4789: (vxlan: key=123, remote_ip=1.1.2.92)
> +])
> +
> +AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> +
> +dnl Setup dummy interface IP addresses.
> +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK

Hmm.  I'm a little confused by this.  The whole point of v4 over v6
routing is that the network we're routing the packets over doesn't
have IPv4 routing, i.e. br0 bridge that is containing an external port
should not be part of IPv4 network, i.e. the address should not be
routable.  Otherwise, why do we even need to use v4 over v6, if there
is a native v4?

Or am I missing something?

In the reporter's case there was an IPv4 address on br-phy, but it
was a /32 address and there was no actual route between tunnel
endpoints, except via v6 gateway.

Best regards, Ilya Maixmets.

> +])
> +AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/64], [0], [OK
> +])
> +dnl Add a static v4 via v6 route
> +AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/32 br0 2001:cafe::10], [0], [OK
> +])
> +
> +AT_CHECK([ovs-appctl ovs/route/show | grep br0 | sort], [0], [dnl
> +Cached: 1.1.2.0/24 dev br0 SRC 1.1.2.88 local
> +Cached: 2001:cafe::/64 dev br0 SRC 2001:cafe::88 local
> +User: 1.1.2.92/32 dev br0 GW 2001:cafe::10 SRC 1.1.2.88
> +])
> +
> +AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.2.92 f8:bc:12:44:34:c8], [0], [OK
> +])
> +
> +dnl Check VXLAN tunnel push
> +AT_CHECK([ovs-ofctl add-flow int-br action=1])
> +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'],
>  [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> +  [Datapath actions: 
> tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:c8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
>  AT_SETUP([tunnel_push_pop - action])
>  
>  OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy 
> ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to