On 5/30/24 20:17, Ilya Maximets wrote:
> On 5/30/24 01:27, 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>
>> ---
>> v5: fix minor CI failure
>> v4: feedback from Ilya
>> - add route del test case, wrap around test width
>> - not set neighbor cache manually
>> - on br-phy, use /32 on address in steead of /24
>> compare v3 and v4
>> https://github.com/williamtu/ovs/compare/router..router-v4
>> v3: add vxlan test, remove rfc
>> v2: fix CI error
>> ---
> 
> <snip>
> 
>> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
>> index 508737c53ec6..7266f0990570 100644
>> --- a/tests/tunnel-push-pop.at
>> +++ b/tests/tunnel-push-pop.at
>> @@ -196,6 +196,69 @@ 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/32], [0], [OK
>> +])
>> +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 
>> src=1.1.2.89], [0], [OK
>> +])
>> +
>> +AT_CHECK([ovs-appctl ovs/route/show | grep br0 | sort], [0], [dnl
>> +Cached: 1.1.2.88/32 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.89
>> +])
>> +
>> +dnl Check ARP Snoop
>> +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(100),dnl
>> +eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),dnl
>> +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)'])
> 
> This is still not a correct test, we would never receive an ARP
> from an IPv6-only network.  This must be an IPv6 NA packet instead.
> 
> All in all, I'd expect the following test to work without modifications
> (unless I mistyped something):
> 
> ---
> 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-appctl vlog/set dpif_netdev:dbg])
> AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy])
> AT_CHECK([ovs-vsctl add-port int-br t2 \
>           -- set Interface t2 type=geneve \
>                               options:remote_ip=1.1.2.92 \
>                               options:key=123 ofport_request=2])
> 
> dnl Setup IP addresses.
> AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/32], [0], [OK
> ])
> AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/64], [0], [OK
> ])
> dnl Adding a static v4 via v6 route.
> AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/32 br0 2001:cafe::10 
> src=1.1.2.88], [0], [OK
> ])
> 
> dnl Checking that a local route for added IP was successfully installed.
> AT_CHECK([ovs-appctl ovs/route/show | grep br0 | sort], [0], [dnl
> Cached: 1.1.2.88/32 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-ofctl add-flow br0 action=normal])
> AT_CHECK([ovs-ofctl add-flow int-br action=normal])
> 
> AT_CHECK([ovs-vsctl -- set Interface p0 options:tx_pcap=p0.pcap])
> 
> dnl Check that v4-over-v6 route is used in the trace and that a tunnel 
> neighbor
> dnl lookup miss generates ND and not an ARP.
> AT_CHECK([ovs-appctl ofproto/trace int-br in_port=LOCAL \
>                 | grep -E 'tunnel|neighbor|actions'], [0], [dnl
>      -> output to native tunnel
>      -> tunneling to 2001:cafe::10 via br0
>      -> neighbor cache miss for 2001:cafe::10 on bridge br0, sending ND 
> request
> Datapath actions: drop
> ])
> 
> dnl Check that the correct Neighbor Solicitation was sent out via p0.
> m4_define([ND_NS_PACKET], [m4_joinall([,],
>   [eth_src=aa:55:aa:55:00:00,eth_dst=33:33:ff:00:00:10,eth_type=0x86dd],
>   [ipv6_src=2001:cafe::88,ipv6_dst=ff02::1:ff00:10],
>   [nw_proto=58,nw_ttl=255,nw_frag=no],
>   [icmpv6_type=135,icmpv6_code=0],
>   [nd_target=2001:cafe::10,nd_options_type=1,nd_sll=aa:55:aa:55:00:00])])
> 
> OVS_WAIT_UNTIL([test $(ovs-pcap p0.pcap \
>     | grep -c "$(ovs-ofctl compose-packet --bare 'ND_NS_PACKET')") -eq 1])
> 
> dnl Now send a Neighbor Advertisement from p0 which has two effects:
> dnl 1. The neighbor cache will learn that 2001:cafe::10 is at 
> f8:bc:12:44:34:b6.
> dnl 2. The br0 mac learning will learn that f8:bc:12:44:34:b6 is on p0.
> AT_CHECK([ovs-appctl netdev-dummy/receive p0 dnl
>  'recirc_id(0),in_port(1),dnl
>   eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),dnl
>   
> ipv6(src=2001:cafe::10,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),dnl
>   icmpv6(type=136,code=0),dnl
>   nd(target=2001:cafe::10,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b6)'
> ])
> 
> dnl Check that v4-over-v6 route is used in the trace and the tunnel is 
> working.
> AT_CHECK([ovs-appctl ofproto/trace int-br in_port=LOCAL \
>                 | grep -E 'tunnel|neighbor|actions'], [0], [dnl
>      -> output to native tunnel
>      -> tunneling to 2001:cafe::10 via br0
>      -> tunneling from aa:55:aa:55:00:00 1.1.2.88 to f8:bc:12:44:34:b6 
> 2001:cafe::10

Though, I think, we should make this output less confusing, e.g.
    -> tunneling from aa:55:aa:55:00:00 1.1.2.88 to 1.1.2.92 via 
f8:bc:12:44:34:b6 2001:cafe::10
Or something like that.  Otherwise it's lacking the actual destination
IP information and may be hard to understand.

> Datapath actions: tnl_push(tnl_port(6081),header(size=50,type=5,dnl
> eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),dnl
> ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),dnl
> udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),1
> ])
> 
> dnl Now check that the packet is actually encapsulated and delivered.
> packet=50540000000a5054000000091234
> eth=f8bc124434b6aa55aa5500000800
> ip4=450000320000400040113406010102580101025c
> dnl Source port is based on a packet hash, so it may differ depending on the
> dnl compiler flags and CPU type.  Masked with '....'.
> udp=....17c1001e0000
> geneve=0000655800007b00
> encap=${eth}${ip4}${udp}${geneve}
> dnl Output to the tunnel from the int-br internal port.
> dnl Checking that the packet arrived and it was correctly encapsulated.
> AT_CHECK([ovs-appctl netdev-dummy/receive int-br "${packet}"])
> OVS_WAIT_UNTIL([test $(ovs-pcap p0.pcap | grep -c "${encap}${packet}") -eq 1])
> 
> dnl Sending again to exercise the non-miss upcall path.
> AT_CHECK([ovs-appctl netdev-dummy/receive int-br "${packet}"])
> OVS_WAIT_UNTIL([test $(ovs-pcap p0.pcap | grep -c "${encap}${packet}") -eq 2])
> 
> dnl Finally, checking that the datapath flow is also correct.
> AT_CHECK([ovs-appctl dpctl/dump-flows | grep tnl_push \
>             | strip_ufid | strip_used], [0], [dnl
> recirc_id(0),in_port(2),packet_type(ns=0,id=0),dnl
> eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x1234), dnl
> packets:1, bytes:14, used:0.0s, dnl
> actions:tnl_push(tnl_port(6081),header(size=50,type=5,dnl
> eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),dnl
> ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),dnl
> udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),1
> ])
> 
> OVS_VSWITCHD_STOP
> AT_CLEANUP
> ---
> 
> With the current version of a patch it fails on the tunnel neighbor
> lookup because it looks for IPv4 neighbor and there are no IPv4
> neighbors in this setup, all the neighbors are IPv6-only.
> 
> Best regards, Ilya Maximets.

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

Reply via email to