aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/srv6-mobile/extra
diff options
context:
space:
mode:
authorTetsuya Murakami <tetsuya.mrk@gmail.com>2020-01-09 14:22:04 -0800
committerOle Trøan <otroan@employees.org>2020-01-14 18:16:21 +0000
commit57584d99dd8a8524db90c67c88525d58879d9b8e (patch)
tree7e9429d91c753a2f61603bf40cb5f449fe7184f9 /src/plugins/srv6-mobile/extra
parentba4a5bf884516769211e75d11884a1e458323a21 (diff)
srv6-mobile:
Type: feature Add new functions in SRv6 Mobile Plug-in GTP4.DT and GTP6.DT Signed-off-by: Tetsuya Murakami <tetsuya.mrk@gmail.com> Change-Id: I573a0c27bd463dd56a4d11b940941b8a8c826e08 Signed-off-by: Tetsuya Murakami <tetsuya.mrk@gmail.com>
Diffstat (limited to 'src/plugins/srv6-mobile/extra')
-rw-r--r--src/plugins/srv6-mobile/extra/README.md209
-rwxr-xr-xsrc/plugins/srv6-mobile/extra/runner.py477
-rw-r--r--src/plugins/srv6-mobile/extra/runner_doc.md105
-rw-r--r--src/plugins/srv6-mobile/extra/topo-init.pngbin0 -> 121503 bytes
-rw-r--r--src/plugins/srv6-mobile/extra/topo-test_gtp4d.pngbin0 -> 138014 bytes
-rw-r--r--src/plugins/srv6-mobile/extra/topo-test_gtp6.pngbin0 -> 131731 bytes
-rw-r--r--src/plugins/srv6-mobile/extra/topo-test_gtp6d.pngbin0 -> 127820 bytes
-rw-r--r--src/plugins/srv6-mobile/extra/topo-test_gtp6ip6.pngbin0 -> 116633 bytes
8 files changed, 678 insertions, 113 deletions
diff --git a/src/plugins/srv6-mobile/extra/README.md b/src/plugins/srv6-mobile/extra/README.md
index 3b24dea6fd6..ed6bb40f7ff 100644
--- a/src/plugins/srv6-mobile/extra/README.md
+++ b/src/plugins/srv6-mobile/extra/README.md
@@ -1,173 +1,168 @@
-# What's `runner.py` doing?
+Test and Demonstrate SRv6 Mobile User Plane Plugin
+========================
-## Common configurations
-### VPP1
-```
-create host-interface name eth1
-set int ip addr host-eth1 A1::1/120
-set int state host-eth1 up
-ip route add ::/0 via host-eth1 A1::2
-```
+## Getting started
+To play with SRv6 Mobile User Plane on VPP, you need to install following packages:
+ docker
+ python3
+ pip3
-### VPP2
+ Python packages (use pip):
+ docker
+ scapy
+ jinja2
-```
-create host-interface name eth1
-set int ip addr host-eth1 A1::2/120
-create host-interface name eth2
-set int ip addr host-eth2 A2::1/120
-set int state host-eth1 up
-set int state host-eth2 up
-ip route add ::/0 via host-eth2 A2::2
-```
+### Quick-start
-### VPP3
+1. Build up the docker container image as following:
```
-create host-interface name eth1
-set int ip addr host-eth1 A2::2/120
-create host-interface name eth2
-set int ip addr host-eth2 A3::1/120
-set int state host-eth1 up
-set int state host-eth2 up
-ip route add ::/0 via host-eth1 A2::1
-```
+$ git clone https://github.com/filvarga/srv6-mobile.git
+$ cd ./srv6-mobile/src/plugins/srv6-mobile/extra
+$ ./runner.py infra build
-### VPP4
+$ docker images
+REPOSITORY TAG IMAGE ID CREATED SIZE
+srv6m-image latest 577e786b7ec6 2 days ago 8GB
+ubuntu 18.04 4c108a37151f 4 weeks ago 64.2MB
```
-create host-interface name eth1
-set int ip addr host-eth1 A3::2/120
-set int state host-eth1 up
-ip route add ::/0 via host-eth1 A3::1
-```
+The runner script [runner.py](runner.py) has features to automate configurations and procedures for the test.
-## Drop-in for GTP-U over IPv4
+2. Instantiate test Scenario
-What's happened when you run `test tmap`:
+Let's try following command to instantiate a topology:
- $ ./runner.py test tmap
+```
+$ ./runner.py infra start
+```
+This command instantiates 4 VPP containers with following topology:
-Setting up a virtual interface of packet generator:
+![Topology Diagram](topo-init.png)
+
+You can check the instantiated docker instances with "docker ps".
-#### VPP1
```
-create packet-generator interface pg0
-set int mac address pg0 aa:bb:cc:dd:ee:01
-set int ip addr pg0 172.16.0.1/30
-set ip arp pg0 172.16.0.2/30 aa:bb:cc:dd:ee:02
+$ docker ps
+CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+44cb98994500 srv6m-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-4
+6d65fff8aee9 srv6m-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-3
+ad123b516b24 srv6m-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-2
+5efed405b96a srv6m-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-1
+
```
-#### VPP4
+You can login to and configure each instantiated container.
```
-create packet-generator interface pg0
-set int mac address pg0 aa:bb:cc:dd:ee:11
-set int ip addr pg0 1.0.0.2/30
-set ip arp pg0 1.0.0.1 aa:bb:cc:dd:ee:22
+$ ./runner.py cmd vppctl 0
+
+Verified image: None
+connecting to: hck-vpp-1
+ _______ _ _ _____ ___
+ __/ __/ _ \ (_)__ | | / / _ \/ _ \
+ _/ _// // / / / _ \ | |/ / ___/ ___/
+ /_/ /____(_)_/\___/ |___/_/ /_/
+
+vpp#
```
-SRv6 and IP routing settings:
+## Test Scenarios
+### SRv6 Drop-in between GTP-U tunnel
-#### VPP1
+This test scenario introduces SRv6 path between GTP-U tunnel transparently. A GTP-U packet sent out from one end to another is translated to SRv6 and then back to GTP-U. All GTP-U tunnel identifiers are preserved in IPv6 header and SRH.
-```
-sr policy add bsid D1:: next D2:: next D3:: gtp4_removal sr_prefix D4::/32 v6src_prefix C1::/64
-sr steer l3 172.20.0.1/32 via bsid D1::
-```
+#### GTP-U over UDP/IPv4 case
+
+This case uses SRv6 end functions, T.M.GTP4.D and End.M.GTP4.E.
-#### VPP2
+![Topology Diagram](topo-test_gtp4d.png)
+
+VPP1 is configured with "T.M.GTP4.D", and VPP4 is configured with "End.M.GTP4.E". Others are configured with "End". The packet generator sends a GTP-U packet over UDP/IPv4 toward the packet capture. VPP1 translates it to SRv6 toward D4::TEID with SR policy <D2::, D3::> in SRH. VPP4 translates the SRv6 packet to the original GTP-U packet and send out to the packet capture.
+
+To start this case with IPv4 payload over GTP-U, you can run:
```
-sr localsid address D2:: behavior end
-ip route add D3::/128 via host-eth2 A2::2
+$ ./runner.py test gtp4
```
-#### VPP3
+If you want to use IPv6 payload instead of IPv4, you can run:
```
-sr localsid address D3:: behavior end
-ip route add D4::/32 via host-eth2 A3::2
+$ ./runner.py test gtp4_ipv6
```
-#### VPP4
+If you use the latest scapy codes from the master branch, you can test the functions with GTP-U packet in 5G format:
```
-sr localsid prefix D4::/32 behavior end.m.gtp4.e v4src_position 64
-ip route add 172.20.0.1/32 via pg0 1.0.0.1
+$ ./runner.py test gtp4_5g
```
+#### GTP-U over UDP/IPv6 case
-## Packet generator and testing
+This case uses SRv6 end functions, End.M.GTP6.D.Di and End.M.GTP6.E.
- Example how to build custom SRv6 packet in scapy and ipaddress pkgs
+![Topology Diagram](topo-test_gtp6d.png)
- s = '\x11' * 4 + IPv4Address(u"192.168.192.10").packed + '\x11' * 8
- ip6 = IPv6Address(s)
- IPv6(dst=ip6, src=ip6)
+VPP1 is configured with "End.M.GTP6.D.Di", and VPP4 is configured with "End.M.GTP4.E". Others are configured with "End". The packet generator sends a GTP-U packet over UDP/IPv6 toward D:: of the packet capture. VPP1 translates it to SRv6 toward D:: with SR policy <D2::, D3::, D4::TEID> in SRH. VPP4 translates the SRv6 packet to the original GTP-U packet and send out to the packet capture.
+To start this case with IPv4 payload over GTP-U, you can run:
-## end.m.gtp4.e
+```
+$ ./runner.py test gtp6_drop_in
+```
- First set behavior so our localsid node is called with the packet
- matching C1::1 in fib table
- sr localsid address C1::1 behavior end.m.gtp4.ess
+If you want to use IPv6 payload instead of IPv4, you can run:
- show sr localsids behaviors
- show sr localsid
+```
+$ ./runner.py test gtp6_drop_in_ipv6
+```
- We should send a well formated packet to C::1 destination address
- that contains the correct spec as for end.m.gtp4.e with encapsulated
- ipv4 src and dst address and teid with port for the conversion to
- GTPU IPv4 packet
+### GTP-U to SRv6
-## additional commands
+This test scenario demonstrates GTP-U to SRv6 translation. A GTP-U packet sent out from one end to another is translated to SRv6.
- gdb - breakpoint
+#### GTP-U over UDP/IPv6 case
- break sr_policy_rewrite.c:1620
+##### IPv4 payload
- break src/plugins/srv6-end/node.c:84
+This case uses SRv6 end functions, End.M.GTP6.D and End.DT4.
- TMAP
- Linux:
+![Topology Diagram](topo-test_gtp6.png)
- ip link add tmp1 type veth peer name tmp2
- ip link set dev tmp1 up
- ip link set dev tmp2 up
- ip addr add 172.20.0.2/24 dev tmp2
+VPP1 is configured with "End.M.GTP6.D", and VPP4 is configured with "End.DT4". Others are configured with "End". The packet generator sends a GTP-U packet over UDP/IPv6 toward D::2. VPP1 translates it to SRv6 toward the IPv6 destination consists of D4:: and TEID of GTP-U with SR policy <D2::, D3::> in SRH. VPP4 decapsulates the SRv6 packet and lookup the table for the inner IPv4 packet and send out to the packet capture.
- create host-interface name tmp1
- set int mac address host-tmp1 02:fe:98:c6:c8:7b
- set interface ip address host-tmp1 172.20.0.1/24
- set interface state host-tmp1 up
+To start this case, you can run:
- VPP
- set sr encaps source addr C1::
- sr policy add bsid D1::999:2 next D2:: next D3:: gtp4_removal sr-prefix fc34:5678::/64 local-prefix C1::/64
- sr steer l3 172.21.0.0/24 via bsid d1::999:2
+```
+$ ./runner.py test gtp6
+```
- END
- Linux
- create host-interface name tmp1
- set int mac address host-tmp1 02:fe:98:c6:c8:7b
- set interface ip address host-tmp1 A1::1/64
- set interface state host-tmp1 up
+##### IPv6 payload
- VPP
- sr localsid address 1111:1111:c0a8:c00a:1122:1111:1111:1111 behavior end.m.gtp4.e
+This case uses SRv6 end functions, End.M.GTP6.D and End.DT6.
+
+
+![Topology Diagram](topo-test_gtp6ip6.png)
+
+The configurations are same with IPv4 payload case, except D4:: is configured as "End.DT6" in VPP4. VPP4 decapsulates the SRv6 packet and lookup the table for the inner IPv6 packet and send out to the packet capture.
+
+If you want to use IPv6 payload instead of IPv4, you can run:
+
+```
+$ ./runner.py test gtp6_ipv6
+```
- trace add af-packet-input 10
+## More information
- sr localsid address C3:: behavior end.m.gtp4.e
- sr localsid address 2001:200:0:1ce1:3000:757f:0:2 behavior end.m.gtp4.e
+- @subpage runner_doc.md
diff --git a/src/plugins/srv6-mobile/extra/runner.py b/src/plugins/srv6-mobile/extra/runner.py
index 79ec2d007c5..c438fb161b7 100755
--- a/src/plugins/srv6-mobile/extra/runner.py
+++ b/src/plugins/srv6-mobile/extra/runner.py
@@ -135,7 +135,7 @@ class Container(object):
self.vppctl_exec("set int mac address pg0 {}".format(local_mac))
self.vppctl_exec("set int ip addr pg0 {}".format(local_ip))
self.vppctl_exec(
- "set ip6 neighbor pg0 {} {}".format(remote_ip, remote_mac))
+ "set ip neighbor pg0 {} {}".format(remote_ip, remote_mac))
self.vppctl_exec("set int state pg0 up")
def pg_create_interface4(self, local_ip, remote_ip, local_mac, remote_mac):
@@ -145,7 +145,7 @@ class Container(object):
self.vppctl_exec("create packet-generator interface pg0")
self.vppctl_exec("set int mac address pg0 {}".format(local_mac))
self.vppctl_exec("set int ip addr pg0 {}".format(local_ip))
- self.vppctl_exec("set ip arp pg0 {} {}".format(remote_ip, remote_mac))
+ self.vppctl_exec("set ip neighbor pg0 {} {}".format(remote_ip, remote_mac))
self.vppctl_exec("set int state pg0 up")
def pg_create_interface6(self, local_ip, remote_ip, local_mac, remote_mac):
@@ -154,10 +154,30 @@ class Container(object):
time.sleep(2)
self.vppctl_exec("create packet-generator interface pg0")
self.vppctl_exec("set int mac address pg0 {}".format(local_mac))
- self.vppctl_exec("set int ip6 addr pg0 {}".format(local_ip))
- self.vppctl_exec("set ip6 arp pg0 {} {}".format(remote_ip, remote_mac))
+ self.vppctl_exec("set int ip addr pg0 {}".format(local_ip))
+ self.vppctl_exec("set ip neighbor pg0 {} {}".format(remote_ip, remote_mac))
self.vppctl_exec("set int state pg0 up")
+ def pg_create_interface4_name(self, ifname, local_ip, remote_ip, local_mac, remote_mac):
+ # remote_ip can't have subnet mask
+
+ time.sleep(2)
+ self.vppctl_exec("create packet-generator interface {}".format(ifname))
+ self.vppctl_exec("set int mac address {} {}".format(ifname, local_mac))
+ self.vppctl_exec("set int ip addr {} {}".format(ifname, local_ip))
+ self.vppctl_exec("set ip neighbor {} {} {}".format(ifname, remote_ip, remote_mac))
+ self.vppctl_exec("set int state {} up".format(ifname))
+
+ def pg_create_interface6_name(self, ifname, local_ip, remote_ip, local_mac, remote_mac):
+ # remote_ip can't have subnet mask
+
+ time.sleep(2)
+ self.vppctl_exec("create packet-generator interface {}".format(ifname))
+ self.vppctl_exec("set int mac address {} {}".format(ifname, local_mac))
+ self.vppctl_exec("set int ip addr {} {}".format(ifname, local_ip))
+ self.vppctl_exec("set ip neighbor {} {} {}".format(ifname, remote_ip, remote_mac))
+ self.vppctl_exec("set int state {} up".format(ifname))
+
def pg_enable(self):
# start packet generator
self.vppctl_exec("packet-generator enable")
@@ -176,6 +196,13 @@ class Container(object):
"packet-generator capture pg0 pcap {}".format(
self.pg_output_file_in))
+ def pg_start_capture_name(self, ifname):
+ if exists(self.pg_output_file):
+ remove(self.pg_output_file)
+ self.vppctl_exec(
+ "packet-generator capture {} pcap {}".format(
+ ifname, self.pg_output_file_in))
+
def pg_read_packets(self):
return rdpcap(self.pg_output_file)
@@ -184,6 +211,11 @@ class Container(object):
"ip route add {} via host-{} {}".format(
subnet, out_if_name, next_hop_ip))
+ def set_ipv6_route2(self, out_if_name, next_hop_ip, subnet):
+ self.vppctl_exec(
+ "ip route add {} via {} {}".format(
+ subnet, out_if_name, next_hop_ip))
+
def set_ip_pgroute(self, out_if_name, next_hop_ip, subnet):
self.vppctl_exec("ip route add {} via {} {}".format(
subnet, out_if_name, next_hop_ip))
@@ -1089,6 +1121,142 @@ class Program(object):
for p in c4.pg_read_packets():
p.show2()
+ def test_gtp4_reply(self):
+ # TESTS:
+ # trace add af-packet-input 10
+ # pg interface on c1 172.20.0.1
+ # pg interface on c4 B::1/120
+
+ self.start_containers()
+
+ c1 = self.containers.get(self.get_name(self.instance_names[0]))
+ c2 = self.containers.get(self.get_name(self.instance_names[1]))
+ c3 = self.containers.get(self.get_name(self.instance_names[2]))
+ c4 = self.containers.get(self.get_name(self.instance_names[-1]))
+
+ c1.pg_create_interface4(
+ local_ip="172.16.0.1/30",
+ remote_ip="172.16.0.2/30",
+ local_mac="aa:bb:cc:dd:ee:01",
+ remote_mac="aa:bb:cc:dd:ee:02")
+ c4.pg_create_interface4(
+ local_ip="1.0.0.2/30",
+ remote_ip="1.0.0.1",
+ local_mac="aa:bb:cc:dd:ee:11",
+ remote_mac="aa:bb:cc:dd:ee:22")
+
+ c1.vppctl_exec("set sr encaps source addr A1::1")
+ c1.vppctl_exec("sr policy add bsid D4:: next D2:: next D3::")
+ c1.vppctl_exec("sr policy add bsid D5:: behavior t.m.gtp4.d D4::/32 v6src_prefix C1::/64 nhtype ipv4")
+ c1.vppctl_exec("sr steer l3 172.20.0.1/32 via bsid D5::")
+
+ c2.vppctl_exec("sr localsid address D2:: behavior end")
+
+ c3.vppctl_exec("sr localsid address D3:: behavior end")
+
+ c4.vppctl_exec(
+ "sr localsid prefix D4::/32 "
+ "behavior end.m.gtp4.e v4src_position 64")
+
+ c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
+ c2.set_ipv6_route("eth1", "A1::1", "C::/120")
+ c3.set_ipv6_route("eth2", "A3::2", "D4::/32")
+ c3.set_ipv6_route("eth1", "A2::1", "C::/120")
+ c4.set_ip_pgroute("pg0", "1.0.0.1", "172.20.0.1/32")
+
+ p = (Ether(src="aa:bb:cc:dd:ee:02", dst="aa:bb:cc:dd:ee:01") /
+ IP(src="172.20.0.2", dst="172.20.0.1") /
+ UDP(sport=2152, dport=2152) /
+ GTP_U_Header(gtp_type="echo_response", S=1, teid=200, seq=200))
+
+ print("Sending packet on {}:".format(c1.name))
+ p.show2()
+
+ c1.enable_trace(10)
+ c4.enable_trace(10)
+
+ c4.pg_start_capture()
+
+ c1.pg_create_stream(p)
+ c1.pg_enable()
+
+ # timeout (sleep) if needed
+ print("Sleeping")
+ time.sleep(5)
+
+ print("Receiving packet on {}:".format(c4.name))
+ for p in c4.pg_read_packets():
+ p.show2()
+
+ def test_gtp4_error(self):
+ # TESTS:
+ # trace add af-packet-input 10
+ # pg interface on c1 172.20.0.1
+ # pg interface on c4 B::1/120
+
+ self.start_containers()
+
+ c1 = self.containers.get(self.get_name(self.instance_names[0]))
+ c2 = self.containers.get(self.get_name(self.instance_names[1]))
+ c3 = self.containers.get(self.get_name(self.instance_names[2]))
+ c4 = self.containers.get(self.get_name(self.instance_names[-1]))
+
+ c1.pg_create_interface4(
+ local_ip="172.16.0.1/30",
+ remote_ip="172.16.0.2/30",
+ local_mac="aa:bb:cc:dd:ee:01",
+ remote_mac="aa:bb:cc:dd:ee:02")
+ c4.pg_create_interface4(
+ local_ip="1.0.0.2/30",
+ remote_ip="1.0.0.1",
+ local_mac="aa:bb:cc:dd:ee:11",
+ remote_mac="aa:bb:cc:dd:ee:22")
+
+ c1.vppctl_exec("set sr encaps source addr A1::1")
+ c1.vppctl_exec("sr policy add bsid D4:: next D2:: next D3::")
+ c1.vppctl_exec("sr policy add bsid D5:: behavior t.m.gtp4.d D4::/32 v6src_prefix C1::/64 nhtype ipv4")
+ c1.vppctl_exec("sr steer l3 172.20.0.1/32 via bsid D5::")
+
+ c2.vppctl_exec("sr localsid address D2:: behavior end")
+
+ c3.vppctl_exec("sr localsid address D3:: behavior end")
+
+ c4.vppctl_exec(
+ "sr localsid prefix D4::/32 "
+ "behavior end.m.gtp4.e v4src_position 64")
+
+ c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
+ c2.set_ipv6_route("eth1", "A1::1", "C::/120")
+ c3.set_ipv6_route("eth2", "A3::2", "D4::/32")
+ c3.set_ipv6_route("eth1", "A2::1", "C::/120")
+ c4.set_ip_pgroute("pg0", "1.0.0.1", "172.20.0.1/32")
+
+ p = (Ether(src="aa:bb:cc:dd:ee:02", dst="aa:bb:cc:dd:ee:01") /
+ IP(src="172.20.0.2", dst="172.20.0.1") /
+ UDP(sport=2152, dport=2152) /
+ GTP_U_Header(gtp_type="error_indication", S=1, teid=200, seq=200)/
+ IE_TEIDI(TEIDI=65535)/IE_GSNAddress(address="1.1.1.1")/
+ IE_PrivateExtension(extention_value="z"))
+
+ print("Sending packet on {}:".format(c1.name))
+ p.show2()
+
+ c1.enable_trace(10)
+ c4.enable_trace(10)
+
+ c4.pg_start_capture()
+
+ c1.pg_create_stream(p)
+ c1.pg_enable()
+
+ # timeout (sleep) if needed
+ print("Sleeping")
+ time.sleep(5)
+
+ print("Receiving packet on {}:".format(c4.name))
+ for p in c4.pg_read_packets():
+ p.show2()
+
def test_gtp4_ipv6(self):
# TESTS:
# trace add af-packet-input 10
@@ -1452,6 +1620,154 @@ class Program(object):
for p in c4.pg_read_packets():
p.show2()
+ def test_gtp6_drop_in_reply(self):
+ # TESTS:
+ # trace add af-packet-input 10
+ # pg interface on c1 172.20.0.1
+ # pg interface on c4 B::1/120
+
+ self.start_containers()
+
+ print("Deleting the old containers...")
+ time.sleep(30)
+ print("Starting the new containers...")
+
+ c1 = self.containers.get(self.get_name(self.instance_names[0]))
+ c2 = self.containers.get(self.get_name(self.instance_names[1]))
+ c3 = self.containers.get(self.get_name(self.instance_names[2]))
+ c4 = self.containers.get(self.get_name(self.instance_names[-1]))
+
+ c1.pg_create_interface(
+ local_ip="C::1/120",
+ remote_ip="C::2",
+ local_mac="aa:bb:cc:dd:ee:01",
+ remote_mac="aa:bb:cc:dd:ee:02")
+ c4.pg_create_interface(
+ local_ip="B::1/120",
+ remote_ip="B::2",
+ local_mac="aa:bb:cc:dd:ee:11",
+ remote_mac="aa:bb:cc:dd:ee:22")
+
+ c1.vppctl_exec("set sr encaps source addr A1::1")
+ c1.vppctl_exec("sr policy add bsid D4:: next D2:: next D3::")
+
+ c1.vppctl_exec(
+ "sr localsid prefix D::/64 behavior end.m.gtp6.d.di D4::/64")
+
+ c2.vppctl_exec("sr localsid address D2:: behavior end")
+
+ c3.vppctl_exec("sr localsid address D3:: behavior end")
+
+ c4.vppctl_exec("sr localsid prefix D4::/64 behavior end.m.gtp6.e")
+
+ c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
+ c2.set_ipv6_route("eth1", "A1::1", "C::/120")
+ c3.set_ipv6_route("eth2", "A3::2", "D4::/32")
+ c3.set_ipv6_route("eth1", "A2::1", "C::/120")
+ c4.set_ip_pgroute("pg0", "B::2", "D::2/128")
+
+ print("Waiting...")
+ time.sleep(30)
+
+ p = (Ether(src="aa:bb:cc:dd:ee:02", dst="aa:bb:cc:dd:ee:01") /
+ IPv6(src="C::2", dst="D::2") /
+ UDP(sport=2152, dport=2152) /
+ GTP_U_Header(gtp_type="echo_response", S=1, teid=200, seq=300))
+
+ print("Sending packet on {}:".format(c1.name))
+ p.show2()
+
+ c1.enable_trace(10)
+ c4.enable_trace(10)
+
+ c4.pg_start_capture()
+
+ c1.pg_create_stream(p)
+ c1.pg_enable()
+
+ # timeout (sleep) if needed
+ print("Sleeping")
+ time.sleep(5)
+
+ print("Receiving packet on {}:".format(c4.name))
+ for p in c4.pg_read_packets():
+ p.show2()
+
+ def test_gtp6_drop_in_error(self):
+ # TESTS:
+ # trace add af-packet-input 10
+ # pg interface on c1 172.20.0.1
+ # pg interface on c4 B::1/120
+
+ self.start_containers()
+
+ print("Deleting the old containers...")
+ time.sleep(30)
+ print("Starting the new containers...")
+
+ c1 = self.containers.get(self.get_name(self.instance_names[0]))
+ c2 = self.containers.get(self.get_name(self.instance_names[1]))
+ c3 = self.containers.get(self.get_name(self.instance_names[2]))
+ c4 = self.containers.get(self.get_name(self.instance_names[-1]))
+
+ c1.pg_create_interface(
+ local_ip="C::1/120",
+ remote_ip="C::2",
+ local_mac="aa:bb:cc:dd:ee:01",
+ remote_mac="aa:bb:cc:dd:ee:02")
+ c4.pg_create_interface(
+ local_ip="B::1/120",
+ remote_ip="B::2",
+ local_mac="aa:bb:cc:dd:ee:11",
+ remote_mac="aa:bb:cc:dd:ee:22")
+
+ c1.vppctl_exec("set sr encaps source addr A1::1")
+ c1.vppctl_exec("sr policy add bsid D4:: next D2:: next D3::")
+
+ c1.vppctl_exec(
+ "sr localsid prefix D::/64 behavior end.m.gtp6.d.di D4::/64")
+
+ c2.vppctl_exec("sr localsid address D2:: behavior end")
+
+ c3.vppctl_exec("sr localsid address D3:: behavior end")
+
+ c4.vppctl_exec("sr localsid prefix D4::/64 behavior end.m.gtp6.e")
+
+ c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
+ c2.set_ipv6_route("eth1", "A1::1", "C::/120")
+ c3.set_ipv6_route("eth2", "A3::2", "D4::/32")
+ c3.set_ipv6_route("eth1", "A2::1", "C::/120")
+ c4.set_ip_pgroute("pg0", "B::2", "D::2/128")
+
+ print("Waiting...")
+ time.sleep(30)
+
+ p = (Ether(src="aa:bb:cc:dd:ee:02", dst="aa:bb:cc:dd:ee:01") /
+ IPv6(src="C::2", dst="D::2") /
+ UDP(sport=2152, dport=2152) /
+ GTP_U_Header(gtp_type="error_indication", S=1, teid=200, seq=300)/
+ IE_TEIDI(TEIDI=65535)/IE_GSNAddress(address="1.1.1.1")/
+ IE_PrivateExtension(extention_value="z"))
+
+ print("Sending packet on {}:".format(c1.name))
+ p.show2()
+
+ c1.enable_trace(10)
+ c4.enable_trace(10)
+
+ c4.pg_start_capture()
+
+ c1.pg_create_stream(p)
+ c1.pg_enable()
+
+ # timeout (sleep) if needed
+ print("Sleeping")
+ time.sleep(5)
+
+ print("Receiving packet on {}:".format(c4.name))
+ for p in c4.pg_read_packets():
+ p.show2()
+
def test_gtp6_drop_in_ipv6(self):
# TESTS:
# trace add af-packet-input 10
@@ -1641,6 +1957,7 @@ class Program(object):
c3.vppctl_exec("sr localsid address D3:: behavior end")
+ c4.vppctl_exec("set ip neighbor pg0 1.0.0.1 aa:bb:cc:dd:ee:22")
c4.vppctl_exec("sr localsid prefix D4::/64 behavior end.dt4 2")
c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
@@ -1716,6 +2033,7 @@ class Program(object):
c3.vppctl_exec("sr localsid address D3:: behavior end")
+ c4.vppctl_exec("set ip neighbor pg0 1.0.0.1 aa:bb:cc:dd:ee:22")
c4.vppctl_exec("sr localsid prefix D4::/64 behavior end.dt4 2")
c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
@@ -1792,6 +2110,7 @@ class Program(object):
c3.vppctl_exec("sr localsid address D3:: behavior end")
+ c4.vppctl_exec("set ip neighbor pg0 B::2 aa:bb:cc:dd:ee:22")
c4.vppctl_exec("sr localsid prefix D4::/64 behavior end.dt6 2")
c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
@@ -1867,6 +2186,7 @@ class Program(object):
c3.vppctl_exec("sr localsid address D3:: behavior end")
+ c4.vppctl_exec("set ip neighbor pg0 B::2 aa:bb:cc:dd:ee:22")
c4.vppctl_exec("sr localsid prefix D4::/64 behavior end.dt6 2")
c2.set_ipv6_route("eth2", "A2::2", "D3::/128")
@@ -1905,6 +2225,133 @@ class Program(object):
for p in c4.pg_read_packets():
p.show2()
+ def test_gtp6_dt(self):
+ # TESTS:
+ # trace add af-packet-input 10
+ # pg interface on c1 172.20.0.1
+ # pg interface on c4 B::1/120
+
+ self.start_containers()
+
+ print("Deleting the old containers...")
+ time.sleep(30)
+ print("Starting the new containers...")
+
+ c1 = self.containers.get(self.get_name(self.instance_names[0]))
+
+ c1.pg_create_interface6_name(
+ ifname="pg0",
+ local_ip="C::1/120",
+ remote_ip="C::2",
+ local_mac="aa:bb:cc:dd:ee:01",
+ remote_mac="aa:bb:cc:dd:ee:02")
+
+ c1.pg_create_interface4_name(
+ ifname="pg1",
+ local_ip="1.0.0.2/30",
+ remote_ip="1.0.0.1",
+ local_mac="aa:bb:cc:dd:ee:11",
+ remote_mac="aa:bb:cc:dd:ee:22")
+
+ c1.vppctl_exec("set sr encaps source addr A1::1")
+
+ c1.vppctl_exec(
+ "sr localsid prefix D::/64 behavior end.m.gtp6.dt46 fib-table 0 local-fib-table 0")
+
+ c1.vppctl_exec("set ip neighbor pg1 1.0.0.1 aa:bb:cc:dd:ee:22")
+ c1.set_ip_pgroute("pg1", "1.0.0.1", "172.200.0.1/32")
+
+ print("Waiting...")
+ time.sleep(30)
+
+ p = (Ether(src="aa:bb:cc:dd:ee:02", dst="aa:bb:cc:dd:ee:01") /
+ IPv6(src="C::2", dst="D::2") /
+ UDP(sport=2152, dport=2152) /
+ GTP_U_Header(gtp_type="g_pdu", teid=200) /
+ IP(src="172.100.0.1", dst="172.200.0.1") /
+ ICMP())
+
+ print("Sending packet on {}:".format(c1.name))
+ p.show2()
+
+ c1.enable_trace(10)
+
+ c1.pg_start_capture_name(ifname="pg1")
+
+ c1.pg_create_stream(p)
+ c1.pg_enable()
+
+ # timeout (sleep) if needed
+ print("Sleeping")
+ time.sleep(5)
+
+ print("Receiving packet on {}:".format(c1.name))
+ for p in c1.pg_read_packets():
+ p.show2()
+
+ def test_gtp4_dt(self):
+ # TESTS:
+ # trace add af-packet-input 10
+ # pg interface on c1 172.20.0.1
+ # pg interface on c4 B::1/120
+
+ self.start_containers()
+
+ print("Deleting the old containers...")
+ time.sleep(30)
+ print("Starting the new containers...")
+
+ c1 = self.containers.get(self.get_name(self.instance_names[0]))
+
+ c1.pg_create_interface4_name(
+ ifname="pg0",
+ local_ip="172.16.0.1/30",
+ remote_ip="172.16.0.2",
+ local_mac="aa:bb:cc:dd:ee:01",
+ remote_mac="aa:bb:cc:dd:ee:02")
+
+ c1.pg_create_interface4_name(
+ ifname="pg1",
+ local_ip="1.0.0.2/30",
+ remote_ip="1.0.0.1",
+ local_mac="aa:bb:cc:dd:ee:11",
+ remote_mac="aa:bb:cc:dd:ee:22")
+
+ c1.vppctl_exec("set sr encaps source addr A1::1")
+ c1.vppctl_exec("sr policy add bsid D5:: behavior t.m.gtp4.dt4 fib-table 0")
+ c1.vppctl_exec("sr steer l3 172.20.0.1/32 via bsid D5::")
+
+ c1.vppctl_exec("set ip neighbor pg1 1.0.0.1 aa:bb:cc:dd:ee:22")
+ c1.set_ip_pgroute("pg1", "1.0.0.1", "172.200.0.1/32")
+
+ print("Waiting...")
+ time.sleep(30)
+
+ p = (Ether(src="aa:bb:cc:dd:ee:02", dst="aa:bb:cc:dd:ee:01") /
+ IP(src="172.20.0.2", dst="172.20.0.1") /
+ UDP(sport=2152, dport=2152) /
+ GTP_U_Header(gtp_type="g_pdu", teid=200) /
+ IP(src="172.100.0.1", dst="172.200.0.1") /
+ ICMP())
+
+ print("Sending packet on {}:".format(c1.name))
+ p.show2()
+
+ c1.enable_trace(10)
+
+ c1.pg_start_capture_name(ifname="pg1")
+
+ c1.pg_create_stream(p)
+ c1.pg_enable()
+
+ # timeout (sleep) if needed
+ print("Sleeping")
+ time.sleep(5)
+
+ print("Receiving packet on {}:".format(c1.name))
+ for p in c1.pg_read_packets():
+ p.show2()
+
def status_containers(self):
print("Instances:")
@@ -2008,17 +2455,23 @@ def get_args():
"gtp4_usid",
"gtp4_5g",
"gtp4_echo",
+ "gtp4_reply",
+ "gtp4_error",
"gtp4_ipv6",
"gtp4_ipv6_5g",
"gtp6_drop_in",
"gtp6_drop_in_5g",
"gtp6_drop_in_echo",
+ "gtp6_drop_in_reply",
+ "gtp6_drop_in_error",
"gtp6_drop_in_ipv6",
"gtp6_drop_in_ipv6_5g",
"gtp6",
"gtp6_5g",
"gtp6_ipv6",
- "gtp6_ipv6_5g"])
+ "gtp6_ipv6_5g",
+ "gtp6_dt",
+ "gtp4_dt"])
args = parser.parse_args()
if not hasattr(args, "op") or not args.op:
@@ -2038,7 +2491,7 @@ def main(op=None, prefix=None, verbose=None,
image = "srv6m-release-image"
elif image == 'debug':
image = "srv6m-image"
- else
+ else:
image = "srv6m-image"
print("Target image: {}".format(image))
@@ -2080,6 +2533,10 @@ def main(op=None, prefix=None, verbose=None,
program.test_gtp4_5g()
elif op == 'gtp4_echo':
program.test_gtp4_echo()
+ elif op == 'gtp4_reply':
+ program.test_gtp4_reply()
+ elif op == 'gtp4_error':
+ program.test_gtp4_error()
elif op == 'gtp4_ipv6':
program.test_gtp4_ipv6()
elif op == 'gtp4_ipv6_5g':
@@ -2090,6 +2547,10 @@ def main(op=None, prefix=None, verbose=None,
program.test_gtp6_drop_in_5g()
elif op == 'gtp6_drop_in_echo':
program.test_gtp6_drop_in_echo()
+ elif op == 'gtp6_drop_in_reply':
+ program.test_gtp6_drop_in_reply()
+ elif op == 'gtp6_drop_in_error':
+ program.test_gtp6_drop_in_error()
elif op == 'gtp6_drop_in_ipv6':
program.test_gtp6_drop_in_ipv6()
elif op == 'gtp6_drop_in_ipv6_5g':
@@ -2102,6 +2563,10 @@ def main(op=None, prefix=None, verbose=None,
program.test_gtp6_ipv6()
elif op == 'gtp6_ipv6_5g':
program.test_gtp6_ipv6_5g()
+ elif op == 'gtp6_dt':
+ program.test_gtp6_dt()
+ elif op == 'gtp4_dt':
+ program.test_gtp4_dt()
except Exception:
program.logger.exception("")
diff --git a/src/plugins/srv6-mobile/extra/runner_doc.md b/src/plugins/srv6-mobile/extra/runner_doc.md
new file mode 100644
index 00000000000..a6fb0277378
--- /dev/null
+++ b/src/plugins/srv6-mobile/extra/runner_doc.md
@@ -0,0 +1,105 @@
+# What's `runner.py` doing?
+
+## Common configurations
+
+### VPP1
+```
+create host-interface name eth1
+set int ip addr host-eth1 A1::1/120
+set int state host-eth1 up
+ip route add ::/0 via host-eth1 A1::2
+```
+
+
+### VPP2
+
+```
+create host-interface name eth1
+set int ip addr host-eth1 A1::2/120
+create host-interface name eth2
+set int ip addr host-eth2 A2::1/120
+set int state host-eth1 up
+set int state host-eth2 up
+ip route add ::/0 via host-eth2 A2::2
+```
+
+
+### VPP3
+
+```
+create host-interface name eth1
+set int ip addr host-eth1 A2::2/120
+create host-interface name eth2
+set int ip addr host-eth2 A3::1/120
+set int state host-eth1 up
+set int state host-eth2 up
+ip route add ::/0 via host-eth1 A2::1
+```
+
+### VPP4
+
+```
+create host-interface name eth1
+set int ip addr host-eth1 A3::2/120
+set int state host-eth1 up
+ip route add ::/0 via host-eth1 A3::1
+```
+
+
+## Drop-in for GTP-U over IPv4
+
+Drop-in mode is handy to test both GTP-U-to-SRv6 and SRv6-to-GTP-U functions at same time. Let's see what's happened when you run `test gtp4`:
+
+ $ ./runner.py test gtp4
+
+
+Setting up a virtual interface of packet generator:
+
+#### VPP1
+
+```
+create packet-generator interface pg0
+set int mac address pg0 aa:bb:cc:dd:ee:01
+set int ip addr pg0 172.16.0.1/30
+set ip arp pg0 172.16.0.2/30 aa:bb:cc:dd:ee:02
+```
+
+#### VPP4
+
+```
+create packet-generator interface pg0
+set int mac address pg0 aa:bb:cc:dd:ee:11
+set int ip addr pg0 1.0.0.2/30
+set ip arp pg0 1.0.0.1 aa:bb:cc:dd:ee:22
+```
+
+SRv6 and IP routing settings:
+
+#### VPP1
+
+```
+sr policy add bsid D4:: next D2:: next D3::
+sr policy add bsid D5:: behavior t.m.gtp4.d D4::/32 v6src_prefix C1::/64 nhtype ipv4
+sr steer l3 172.20.0.1/32 via bsid D5::
+```
+
+#### VPP2
+
+```
+sr localsid address D2:: behavior end
+ip route add D3::/128 via host-eth2 A2::2
+```
+
+#### VPP3
+
+```
+sr localsid address D3:: behavior end
+ip route add D4::/32 via host-eth2 A3::2
+```
+
+#### VPP4
+
+```
+sr localsid prefix D4::/32 behavior end.m.gtp4.e v4src_position 64
+ip route add 172.20.0.1/32 via pg0 1.0.0.1
+```
diff --git a/src/plugins/srv6-mobile/extra/topo-init.png b/src/plugins/srv6-mobile/extra/topo-init.png
index e69de29bb2d..dc9603ba290 100644
--- a/src/plugins/srv6-mobile/extra/topo-init.png
+++ b/src/plugins/srv6-mobile/extra/topo-init.png
Binary files differ
diff --git a/src/plugins/srv6-mobile/extra/topo-test_gtp4d.png b/src/plugins/srv6-mobile/extra/topo-test_gtp4d.png
index e69de29bb2d..d60beb23093 100644
--- a/src/plugins/srv6-mobile/extra/topo-test_gtp4d.png
+++ b/src/plugins/srv6-mobile/extra/topo-test_gtp4d.png
Binary files differ
diff --git a/src/plugins/srv6-mobile/extra/topo-test_gtp6.png b/src/plugins/srv6-mobile/extra/topo-test_gtp6.png
index e69de29bb2d..2cad260215a 100644
--- a/src/plugins/srv6-mobile/extra/topo-test_gtp6.png
+++ b/src/plugins/srv6-mobile/extra/topo-test_gtp6.png
Binary files differ
diff --git a/src/plugins/srv6-mobile/extra/topo-test_gtp6d.png b/src/plugins/srv6-mobile/extra/topo-test_gtp6d.png
index e69de29bb2d..78b083daa8a 100644
--- a/src/plugins/srv6-mobile/extra/topo-test_gtp6d.png
+++ b/src/plugins/srv6-mobile/extra/topo-test_gtp6d.png
Binary files differ
diff --git a/src/plugins/srv6-mobile/extra/topo-test_gtp6ip6.png b/src/plugins/srv6-mobile/extra/topo-test_gtp6ip6.png
index e69de29bb2d..fe78f673787 100644
--- a/src/plugins/srv6-mobile/extra/topo-test_gtp6ip6.png
+++ b/src/plugins/srv6-mobile/extra/topo-test_gtp6ip6.png
Binary files differ