AT_BANNER([layer3-tunnels])

AT_SETUP([layer3 - ping over VXLAN-GPE])
OVS_TRAFFIC_VSWITCHD_START([set Bridge br0 other-config:hwaddr="00:12:34:56:78:bb"])
OVS_CHECK_VXLAN_GPE()
OVS_CHECK_IPROUTE_ENCAP()

ADD_BR([br-underlay])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], [10.1.1.2/24],
               [options:packet_type=legacy_l3 options:exts=gpe])
AT_CHECK([ip neigh add 10.1.1.1 lladdr 00:12:34:56:78:aa dev br0])
NS_CHECK_EXEC([at_ns0], [ip link add dev at_vxlan1 type vxlan dstport 4789 external gpe])
NS_CHECK_EXEC([at_ns0], [ip addr add dev at_vxlan1 10.1.1.1/24])
NS_CHECK_EXEC([at_ns0], [ip link set dev at_vxlan1 mtu 1450 up])
NS_CHECK_EXEC([at_ns0], [ip route add 10.1.1.2/32 encap ip id 0 dst 172.31.1.100 dev at_vxlan1])

AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

dnl Now add rules for OVS to forward to the tunnel and local port
AT_CHECK([ovs-ofctl add-flow br0 "priority=1 action=drop"])
AT_CHECK([ovs-ofctl add-flow br0 "priority=100 ip,nw_dst=10.1.1.1 action=output:at_vxlan0"])
AT_CHECK([ovs-ofctl add-flow br0 "priority=100 ip,nw_dst=10.1.1.2 action=mod_dl_src:00:12:34:56:78:aa,mod_dl_dst:00:12:34:56:78:bb,local"])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([layer3 - ping over GRE])
OVS_TRAFFIC_VSWITCHD_START([set Bridge br0 other-config:hwaddr="00:12:34:56:78:bb"])
OVS_CHECK_GRE_L3()
OVS_CHECK_IPROUTE_ENCAP()

ADD_BR([br-underlay])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([gre], [br0], [at_gre0], [172.31.1.1], [10.1.1.2/24],
               [options:packet_type=legacy_l3])
AT_CHECK([ip neigh add 10.1.1.1 lladdr 00:12:34:56:78:aa dev br0])
NS_CHECK_EXEC([at_ns0], [ip link add dev at_gre1 type gre remote 172.31.1.100])
NS_CHECK_EXEC([at_ns0], [ip addr add dev at_gre1 10.1.1.1/24])
NS_CHECK_EXEC([at_ns0], [ip link set dev at_gre1 mtu 1450 up])
NS_CHECK_EXEC([at_ns0], [ip route add 10.1.1.2/32 encap ip id 0 dst 172.31.1.100 dev at_gre1])

AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

dnl Now add rules for OVS to forward to the tunnel and local port
AT_CHECK([ovs-ofctl add-flow br0 "priority=1 action=drop"])
AT_CHECK([ovs-ofctl add-flow br0 "priority=100 ip,nw_dst=10.1.1.1 action=output:at_gre0"])
AT_CHECK([ovs-ofctl add-flow br0 "priority=100 ip,nw_dst=10.1.1.2 action=mod_dl_src:00:12:34:56:78:aa,mod_dl_dst:00:12:34:56:78:bb,local"])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([layer3 - use non-local port as tunnel endpoint])

OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1])
AT_CHECK([ovs-vsctl add-port br0 vtep0 -- set int vtep0 type=dummy], [0])
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=gre \
                    options:remote_ip=1.1.2.92 ofport_request=3], [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)
    vtep0 2/2: (dummy)
  int-br:
    int-br 65534/3: (dummy-internal)
    t1 3/4: (gre: remote_ip=1.1.2.92)
])

AT_CHECK([ovs-appctl netdev-dummy/ip4addr vtep0 1.1.2.88/24], [0], [OK
])
AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 vtep0], [0], [OK
])
AT_CHECK([ovs-ofctl add-flow br0 action=normal])
AT_CHECK([ovs-ofctl add-flow int-br action=normal])

dnl Use arp request and reply to achieve tunnel next hop mac binding
dnl By default, vtep0's MAC address is aa:55:aa:55:00:03
AT_CHECK([ovs-appctl netdev-dummy/receive vtep0 'recirc_id(0),in_port(2),eth(dst=ff:ff:ff:ff:ff:ff,src=aa:55:aa:55:00:03),eth_type(0x0806),arp(tip=1.1.2.92,sip=1.1.2.88,op=1,sha=aa:55:aa:55:00:03,tha=00:00:00:00:00:00)'])
AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:03),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=aa:55:aa:55:00:03)'])

AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
1.1.2.92                                      f8:bc:12:44:34:b6   br0
])

AT_CHECK([ovs-appctl ovs/route/show | tail -n+2 | sort], [0], [dnl
User: 1.1.2.0/24 dev vtep0 SRC 1.1.2.88
])

dnl Check GRE tunnel pop
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:03),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])

AT_CHECK([tail -1 stdout], [0],
  [Datapath actions: tnl_pop(4)
])

dnl Check GRE tunnel push
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(3),eth(dst=f9:bc:12:44:34:b6,src=af:55:aa:55:00:03),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.92,proto=1,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
  [Datapath actions: clone(tnl_push(tnl_port(4),header(size=38,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:03,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(2)),1)
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([layer3 - ping over MPLS Bareudp])
OVS_CHECK_BAREUDP()
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "36:b1:ee:7c:01:01")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24", "36:b1:ee:7c:01:02")

ADD_OVS_TUNNEL([bareudp], [br0], [at_bareudp0], [8.1.1.3], [8.1.1.2/24],
               [ options:local_ip=8.1.1.2 options:packet_type="legacy_l3" options:payload_type=mpls options:dst_port=6635])

ADD_OVS_TUNNEL([bareudp], [br1], [at_bareudp1], [8.1.1.2], [8.1.1.3/24],
               [options:local_ip=8.1.1.3 options:packet_type="legacy_l3" options:payload_type=mpls options:dst_port=6635])

AT_DATA([flows0.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_mpls_label:3,output:at_bareudp0
table=0,priority=100,dl_type=0x8847 in_port=at_bareudp0 actions=pop_mpls:0x0800,set_field:36:b1:ee:7c:01:01->dl_dst,set_field:36:b1:ee:7c:01:02->dl_src,output:ovs-p0
table=0,priority=10 actions=normal
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_mpls_label:3,output:at_bareudp1
table=0,priority=100,dl_type=0x8847 in_port=at_bareudp1 actions=pop_mpls:0x0800,set_field:36:b1:ee:7c:01:02->dl_dst,set_field:36:b1:ee:7c:01:01->dl_src,output:ovs-p1
table=0,priority=10 actions=normal
])

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0])
AT_CHECK([ovs-vsctl add-port br1 patch1])


AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows0.txt])
AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([layer3 - ping over Bareudp])
OVS_CHECK_BAREUDP()
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "36:b1:ee:7c:01:01")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24", "36:b1:ee:7c:01:02")

ADD_OVS_TUNNEL([bareudp], [br0], [at_bareudp0], [8.1.1.3], [8.1.1.2/24],
               [ options:local_ip=8.1.1.2 options:packet_type="legacy_l3" options:payload_type=ip options:dst_port=6636])

ADD_OVS_TUNNEL([bareudp], [br1], [at_bareudp1], [8.1.1.2], [8.1.1.3/24],
               [options:local_ip=8.1.1.3 options:packet_type="legacy_l3" options:payload_type=ip options:dst_port=6636])

AT_DATA([flows0.txt], [dnl
table=0,priority=100,dl_type=0x0800 in_port=ovs-p0, actions=output:at_bareudp0
table=0,priority=100,dl_type=0x0800 in_port=at_bareudp0 actions=set_field:36:b1:ee:7c:01:01->dl_dst,set_field:36:b1:ee:7c:01:02->dl_src,output:ovs-p0
table=0,priority=10 actions=normal
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,dl_type=0x0800 in_port=ovs-p1 actions=output:at_bareudp1
table=0,priority=100,dl_type=0x0800 in_port=at_bareudp1 actions=set_field:36:b1:ee:7c:01:02->dl_dst,set_field:36:b1:ee:7c:01:01->dl_src,output:ovs-p1
table=0,priority=10 actions=normal
])

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0])
AT_CHECK([ovs-vsctl add-port br1 patch1])


AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows0.txt])
AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
