srv6-mobile

Type: feature

Plug-in for IPv6 Segment Routing Mobile

This funcion was developed by

Signed-off-by: Satoru Matsuchima <satoru.matsushima@gmail.com>
Signed-off-by: Filip Varga <filipvarga89@gmail.com>
Signed-off-by: Tetsuya Murakami <tetsuya.mrk@gmail.com>

Signed-off-by: Tetsuya Murakami <tetsuya.mrk@gmail.com>
Change-Id: Ie995adc73d8f8d444339aab71619c3599e69f12d
Signed-off-by: Tetsuya Murakami <tetsuya.mrk@gmail.com>
This commit is contained in:
Tetsuya Murakami
2019-11-06 11:05:51 -08:00
committed by Ole Trøan
parent 360b523b52
commit 1b81e6ef66
30 changed files with 5340 additions and 32 deletions
+6
View File
@@ -413,6 +413,12 @@ I: srv6-as
M: Francois Clad <fclad@cisco.com>
F: src/plugins/srv6-as/
Plugin - IPv6 Segment Routing Mobile
I: srv6-mobile
M: Tetsuya Murakami <tetsuya.mrk@gmail.com>
M: Satoru Matsushima <satoru.matsushima@gmail.com>
F: src/plugins/srv6-mobile/
Plugin - Link Aggregation Control Protocol
I: lacp
M: Steven Luong <sluong@cisco.com>
+1
View File
@@ -425,6 +425,7 @@ srv6_ad_init (vlib_main_t * vm)
keyword_str,
def_str,
params_str,
128,
&sm->srv6_ad_dpo_type,
format_srv6_ad_localsid,
unformat_srv6_ad_localsid,
+8 -5
View File
@@ -1,4 +1,6 @@
/*
* node.c
*
* Copyright (c) 2015 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -12,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vppinfra/error.h>
@@ -705,9 +708,9 @@ VLIB_REGISTER_NODE (srv6_ad6_rewrite_node) = {
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+1
View File
@@ -212,6 +212,7 @@ srv6_am_init (vlib_main_t * vm)
keyword_str,
def_str,
params_str,
128,
&sm->srv6_am_dpo_type,
format_srv6_am_localsid,
unformat_srv6_am_localsid,
+1
View File
@@ -535,6 +535,7 @@ srv6_as_init (vlib_main_t * vm)
keyword_str,
def_str,
params_str,
128,
&sm->srv6_as_dpo_type,
format_srv6_as_localsid,
unformat_srv6_as_localsid,
+24
View File
@@ -0,0 +1,24 @@
# Copyright (c) 2019 Arrcus Inc and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
add_vpp_plugin(srv6mobile
SOURCES
gtp4_e.c
gtp6_e.c
gtp6_d.c
gtp6_d_di.c
node.c
INSTALL_HEADERS
mobile.h
)
+12
View File
@@ -0,0 +1,12 @@
name: SRv6 Mobuile
maintainer: Tetsuya Murakami <tetsuya.mrk@gmail.com>
features:
- GTP4.D
- GTP4.E
- GTP6.D
- GTP6.D.Di
- GTP6.E
description: "SRv6 Mobile End Functions. GTP4.D, GTP4.E,
GTP6.D, GTP6.D.Di and GTP6.E are supported."
state: production
properties: [API, CLI, MULTITHREAD]
+178
View File
@@ -0,0 +1,178 @@
SRv6 Mobile User Plane Plugin for VPP
========================
## Introduction
This plugin module can provide the stateless mobile user plane protocols translation between GTP-U and SRv6.
The functions of the translation take advantage of SRv6 network programmability.
[SRv6 Mobile User Plane](https://tools.ietf.org/html/draft-ietf-dmm-srv6-mobile-uplane) defines the user plane protocol using SRv6
including following stateless translation functions:
- **T.M.GTP4.D:**
GTP-U over UDP/IPv4 -> SRv6
- **End.M.GTP4.E:**
SRv6 -> GTP-U over UDP/IPv4
- **End.M.GTP6.D:**
GTP-U over UDP/IPv6 -> SRv6
- **End.M.GTP6.E:**
SRv6 -> GTP-U over UDP/IPv6
These functions benefit user plane(overlay) to be able to utilize data plane(underlay) networks properly. And also it benefits
data plane to be able to handle user plane in routing paradigm.
## Getting started
To play with SRv6 Mobile User Plane on VPP, you need to install following packages:
docker
python3
pip3
Python packages (use pip):
docker
scapy
jinja2
### Quick-start
1. Build up the docker container image as following:
```
$ git clone https://github.com/filvarga/srv6-mobile.git
$ cd ./srv6-mobile/extras/ietf105
$ ./runner.py infra build
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ietf105-image latest 577e786b7ec6 2 days ago 5.57GB
ubuntu 18.04 4c108a37151f 4 weeks ago 64.2MB
```
The runner script [runner.py](test/runner.py) has features to automate configurations and procedures for the test.
2. Instantiate test Scenario
Let's try following command to instantiate a topology:
```
$ ./runner.py infra start
```
This command instantiates 4 VPP containers with following topology:
![Topology Diagram](test/topo-init.png)
You can check the instantiated docker instances with "docker ps".
```
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44cb98994500 ietf105-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-4
6d65fff8aee9 ietf105-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-3
ad123b516b24 ietf105-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-2
5efed405b96a ietf105-image "/bin/sh -c 'vpp -c …" About a minute ago Up About a minute hck-vpp-1
```
You can login to and configure each instantiated container.
```
$ ./runner.py cmd vppctl 0
Verified image: None
connecting to: hck-vpp-1
_______ _ _ _____ ___
__/ __/ _ \ (_)__ | | / / _ \/ _ \
_/ _// // / / / _ \ | |/ / ___/ ___/
/_/ /____(_)_/\___/ |___/_/ /_/
vpp#
```
## Test Scenarios
### SRv6 Drop-in between GTP-U tunnel
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.
#### GTP-U over UDP/IPv4 case
This case uses SRv6 end functions, T.M.GTP4.D and End.M.GTP4.E.
![Topology Diagram](test/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:
```
$ ./runner.py test tmap
```
If you want to use IPv6 payload instead of IPv4, you can run:
```
$ ./runner.py test tmap_ipv6
```
#### GTP-U over UDP/IPv6 case
This case uses SRv6 end functions, End.M.GTP6.D.Di and End.M.GTP6.E.
![Topology Diagram](test/topo-test_gtp6d.png)
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:
```
$ ./runner.py test gtp6_drop_in
```
If you want to use IPv6 payload instead of IPv4, you can run:
```
$ ./runner.py test gtp6_drop_in_ipv6
```
### GTP-U to SRv6
This test scenario demonstrates GTP-U to SRv6 translation. A GTP-U packet sent out from one end to another is translated to SRv6.
#### GTP-U over UDP/IPv6 case
##### IPv4 payload
This case uses SRv6 end functions, End.M.GTP6.D and End.DT4.
![Topology Diagram](test/topo-test_gtp6.png)
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.
To start this case, you can run:
```
$ ./runner.py test gtp6
```
##### IPv6 payload
This case uses SRv6 end functions, End.M.GTP6.D and End.DT6.
![Topology Diagram](test/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
```
## More information
TBD
@@ -0,0 +1,48 @@
FROM ubuntu:18.04
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
inetutils-traceroute \
ca-certificates \
build-essential \
git gdb sudo \
iputils-ping \
net-tools \
iproute2 \
tcpdump \
python3-cffi \
asciidoc \
xmlto \
netcat; \
rm -rf /var/lib/apt/lists/*; \
mv /usr/sbin/tcpdump /usr/bin/tcpdump
RUN set -eux; \
mkdir -p {{vpp_path}}
COPY . / {{vpp_path}}/
WORKDIR {{vpp_path}}
RUN set -eux; \
make wipe; \
export UNATTENDED=y; \
echo "y" | make install-dep; \
rm -rf /var/lib/apt/lists/* ; \
make build; \
make pkg-deb; \
rm -rf .ccache; \
find . -type f -name '*.o' -delete ; \
cd {{vpp_path}}/build-root; \
rm vpp-api-python_*.deb; \
tar czf vpp-package.tgz *.deb; \
mv vpp-package.tgz {{vpp_path}}/; \
dpkg -i *.deb ; \
cp {{vpp_path}}/startup.conf /etc/startup.conf
WORKDIR /
CMD vpp -c /etc/startup.conf
@@ -0,0 +1,37 @@
FROM ubuntu:18.04
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
inetutils-traceroute \
ca-certificates \
libmbedcrypto1 \
libmbedtls10 \
libmbedx509-0 \
libnuma1 \
sudo \
iputils-ping \
net-tools \
iproute2 \
tcpdump \
python3-cffi \
netcat; \
rm -rf /var/lib/apt/lists/*; \
mv /usr/sbin/tcpdump /usr/bin/tcpdump
WORKDIR /tmp
COPY startup.conf /etc/startup.conf
COPY vpp-package.tgz /tmp
RUN set -eux; \
tar xzf vpp-package.tgz; \
dpkg -i *.deb ; \
rm -rf *.deb
WORKDIR /
CMD vpp -c /etc/startup.conf
+173
View File
@@ -0,0 +1,173 @@
# 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
What's happened when you run `test tmap`:
$ ./runner.py test tmap
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 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::
```
#### 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
```
## Packet generator and testing
Example how to build custom SRv6 packet in scapy and ipaddress pkgs
s = '\x11' * 4 + IPv4Address(u"192.168.192.10").packed + '\x11' * 8
ip6 = IPv6Address(s)
IPv6(dst=ip6, src=ip6)
## end.m.gtp4.e
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
show sr localsids behaviors
show sr localsid
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
## additional commands
gdb - breakpoint
break sr_policy_rewrite.c:1620
break src/plugins/srv6-end/node.c:84
TMAP
Linux:
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
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
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
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
VPP
sr localsid address 1111:1111:c0a8:c00a:1122:1111:1111:1111 behavior end.m.gtp4.e
trace add af-packet-input 10
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
@@ -0,0 +1,3 @@
docker
jinja2
scapy
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,14 @@
unix {
nodaemon
cli-no-pager
cli-listen 0.0.0.0:5002
}
plugins {
plugin dpdk_plugin.so {
disable
}
}
cpu {
workers 2
}
+188
View File
@@ -0,0 +1,188 @@
/*
* srv6_end_m_gtp4_e.c
*
* Copyright (c) 2019 Arrcus Inc and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/vnet.h>
#include <vnet/adj/adj.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <srv6-mobile/mobile.h>
srv6_end_main_v4_t srv6_end_main_v4;
static void
clb_dpo_lock_srv6_end_m_gtp4_e (dpo_id_t * dpo)
{
}
static void
clb_dpo_unlock_srv6_end_m_gtp4_e (dpo_id_t * dpo)
{
}
static u8 *
clb_dpo_format_srv6_end_m_gtp4_e (u8 * s, va_list * args)
{
index_t index = va_arg (*args, index_t);
CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
return (format (s, "SR: dynamic_proxy_index:[%u]", index));
}
const static dpo_vft_t dpo_vft = {
.dv_lock = clb_dpo_lock_srv6_end_m_gtp4_e,
.dv_unlock = clb_dpo_unlock_srv6_end_m_gtp4_e,
.dv_format = clb_dpo_format_srv6_end_m_gtp4_e,
};
const static char *const srv6_end_m_gtp4_e_nodes[] = {
"srv6-end-m-gtp4-e",
NULL,
};
const static char *const *const dpo_nodes[DPO_PROTO_NUM] = {
[DPO_PROTO_IP6] = srv6_end_m_gtp4_e_nodes,
};
static u8 fn_name[] = "SRv6-End.M.GTP4.E-plugin";
static u8 keyword_str[] = "end.m.gtp4.e";
static u8 def_str[] =
"Endpoint function with encapsulation for IPv4/GTP tunnel";
static u8 param_str[] = "";
static u8 *
clb_format_srv6_end_m_gtp4_e (u8 * s, va_list * args)
{
srv6_end_gtp4_param_t *ls_mem = va_arg (*args, void *);
s = format (s, "SRv6 End gtp4.e\n\t");
s = format (s, "IPv4 address position: %d\n", ls_mem->v4src_position);
return s;
}
static uword
clb_unformat_srv6_end_m_gtp4_e (unformat_input_t * input, va_list * args)
{
void **plugin_mem_p = va_arg (*args, void **);
srv6_end_gtp4_param_t *ls_mem;
u32 v4src_position;
if (!unformat (input, "end.m.gtp4.e v4src_position %d", &v4src_position))
return 0;
ls_mem = clib_mem_alloc_aligned_at_offset (sizeof *ls_mem, 0, 0, 1);
clib_memset (ls_mem, 0, sizeof *ls_mem);
*plugin_mem_p = ls_mem;
ls_mem->v4src_position = v4src_position;
return 1;
}
static int
clb_creation_srv6_end_m_gtp4_e (ip6_sr_localsid_t * localsid)
{
return 0;
}
static int
clb_removal_srv6_end_m_gtp4_e (ip6_sr_localsid_t * localsid)
{
srv6_end_gtp4_param_t *ls_mem;
ls_mem = localsid->plugin_mem;
clib_mem_free (ls_mem);
return 0;
}
static clib_error_t *
srv6_end_m_gtp4_e_init (vlib_main_t * vm)
{
srv6_end_main_v4_t *sm = &srv6_end_main_v4;
ip4_header_t *ip4 = &sm->cache_hdr.ip4;
udp_header_t *udp = &sm->cache_hdr.udp;
gtpu_header_t *gtpu = &sm->cache_hdr.gtpu;
dpo_type_t dpo_type;
vlib_node_t *node;
u32 rc;
sm->vlib_main = vm;
sm->vnet_main = vnet_get_main ();
node = vlib_get_node_by_name (vm, (u8 *) "srv6-end-m-gtp4-e");
sm->end_m_gtp4_e_node_index = node->index;
node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
sm->error_node_index = node->index;
sm->dst_p_len = 32;
sm->src_p_len = 64;
// clear the pre cached packet
clib_memset_u8 (ip4, 0, sizeof (ip4_gtpu_header_t));
// set defaults
ip4->ip_version_and_header_length = 0x45;
ip4->protocol = IP_PROTOCOL_UDP;
ip4->ttl = 64;
udp->dst_port = clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT);
gtpu->ver_flags = GTPU_V1_VER | GTPU_PT_GTP;
gtpu->type = GTPU_TYPE_GTPU;
//
dpo_type = dpo_register_new_type (&dpo_vft, dpo_nodes);
rc = sr_localsid_register_function (vm, fn_name, keyword_str, def_str, param_str, 32, //prefix len
&dpo_type,
clb_format_srv6_end_m_gtp4_e,
clb_unformat_srv6_end_m_gtp4_e,
clb_creation_srv6_end_m_gtp4_e,
clb_removal_srv6_end_m_gtp4_e);
if (rc < 0)
clib_error_return (0, "SRv6 Endpoint GTP4.E LocalSID function"
"couldn't be registered");
return 0;
}
/* *INDENT-OFF* */
VNET_FEATURE_INIT (srv6_end_m_gtp4_e, static) =
{
.arc_name = "ip6-unicast",
.node_name = "srv6-end-m-gtp4-e",
.runs_before = 0,
};
VLIB_INIT_FUNCTION (srv6_end_m_gtp4_e_init);
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "SRv6 GTP Endpoint Functions",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+216
View File
@@ -0,0 +1,216 @@
/*
* srv6_end_m_gtp6_d.c
*
* Copyright (c) 2019 Arrcus Inc and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/vnet.h>
#include <vnet/adj/adj.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <srv6-mobile/mobile.h>
srv6_end_main_v6_decap_t srv6_end_main_v6_decap;
static void
clb_dpo_lock_srv6_end_m_gtp6_d (dpo_id_t * dpo)
{
}
static void
clb_dpo_unlock_srv6_end_m_gtp6_d (dpo_id_t * dpo)
{
}
static u8 *
clb_dpo_format_srv6_end_m_gtp6_d (u8 * s, va_list * args)
{
index_t index = va_arg (*args, index_t);
CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
return (format (s, "SR: dynamic_proxy_index:[%u]", index));
}
const static dpo_vft_t dpo_vft = {
.dv_lock = clb_dpo_lock_srv6_end_m_gtp6_d,
.dv_unlock = clb_dpo_unlock_srv6_end_m_gtp6_d,
.dv_format = clb_dpo_format_srv6_end_m_gtp6_d,
};
const static char *const srv6_end_m_gtp6_d_nodes[] = {
"srv6-end-m-gtp6-d",
NULL,
};
const static char *const *const dpo_nodes[DPO_PROTO_NUM] = {
[DPO_PROTO_IP6] = srv6_end_m_gtp6_d_nodes,
};
static u8 fn_name[] = "SRv6-End.M.GTP6.D-plugin";
static u8 keyword_str[] = "end.m.gtp6.d";
static u8 def_str[] =
"Endpoint function with dencapsulation for IPv6/GTP tunnel";
static u8 param_str[] = "<sr-prefix>/<sr-prefixlen> [nhtype <nhtype>]";
static u8 *
clb_format_srv6_end_m_gtp6_d (u8 * s, va_list * args)
{
srv6_end_gtp6_param_t *ls_mem = va_arg (*args, void *);
s = format (s, "SRv6 End gtp6.d\n\t");
s =
format (s, "SR Prefix: %U/%d", format_ip6_address, &ls_mem->sr_prefix,
ls_mem->sr_prefixlen);
if (ls_mem->nhtype != SRV6_NHTYPE_NONE)
{
if (ls_mem->nhtype == SRV6_NHTYPE_IPV4)
s = format (s, ", NHType IPv4\n");
else if (ls_mem->nhtype == SRV6_NHTYPE_IPV6)
s = format (s, ", NHType IPv6\n");
else if (ls_mem->nhtype == SRV6_NHTYPE_NON_IP)
s = format (s, ", NHType Non-IP\n");
else
s = format (s, ", NHType Unknow(%d)\n", ls_mem->nhtype);
}
else
s = format (s, "\n");
return s;
}
static uword
clb_unformat_srv6_end_m_gtp6_d (unformat_input_t * input, va_list * args)
{
void **plugin_mem_p = va_arg (*args, void **);
srv6_end_gtp6_param_t *ls_mem;
ip6_address_t sr_prefix;
u32 sr_prefixlen;
u8 nhtype;
if (unformat (input, "end.m.gtp6.d %U/%d nh-type ipv4",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_IPV4;
}
else if (unformat (input, "end.m.gtp6.d %U/%d nh-type ipv6",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_IPV6;
}
else if (unformat (input, "end.m.gtp6.d %U/%d nh-type none",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_NON_IP;
}
else if (unformat (input, "end.m.gtp6.d %U/%d",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_NONE;
}
else
{
return 0;
}
ls_mem = clib_mem_alloc_aligned_at_offset (sizeof *ls_mem, 0, 0, 1);
clib_memset (ls_mem, 0, sizeof *ls_mem);
*plugin_mem_p = ls_mem;
ls_mem->sr_prefix = sr_prefix;
ls_mem->sr_prefixlen = sr_prefixlen;
ls_mem->nhtype = nhtype;
return 1;
}
static int
clb_creation_srv6_end_m_gtp6_d (ip6_sr_localsid_t * localsid)
{
return 0;
}
static int
clb_removal_srv6_end_m_gtp6_d (ip6_sr_localsid_t * localsid)
{
srv6_end_gtp6_param_t *ls_mem;
ls_mem = localsid->plugin_mem;
clib_mem_free (ls_mem);
return 0;
}
static clib_error_t *
srv6_end_m_gtp6_d_init (vlib_main_t * vm)
{
srv6_end_main_v6_decap_t *sm = &srv6_end_main_v6_decap;
ip6_header_t *ip6;
dpo_type_t dpo_type;
vlib_node_t *node;
u32 rc;
sm->vlib_main = vm;
sm->vnet_main = vnet_get_main ();
node = vlib_get_node_by_name (vm, (u8 *) "srv6-end-m-gtp6-d");
sm->end_m_gtp6_d_node_index = node->index;
node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
sm->error_node_index = node->index;
ip6 = &sm->cache_hdr;
clib_memset_u8 (ip6, 0, sizeof (ip6_header_t));
// IPv6 header (default)
ip6->ip_version_traffic_class_and_flow_label = 0x60;
ip6->hop_limit = 64;
ip6->protocol = IP_PROTOCOL_IPV6;
dpo_type = dpo_register_new_type (&dpo_vft, dpo_nodes);
rc = sr_localsid_register_function (vm, fn_name, keyword_str, def_str, param_str, 128, //prefix len
&dpo_type,
clb_format_srv6_end_m_gtp6_d,
clb_unformat_srv6_end_m_gtp6_d,
clb_creation_srv6_end_m_gtp6_d,
clb_removal_srv6_end_m_gtp6_d);
if (rc < 0)
clib_error_return (0, "SRv6 Endpoint GTP6.D LocalSID function"
"couldn't be registered");
return 0;
}
/* *INDENT-OFF* */
VNET_FEATURE_INIT (srv6_end_m_gtp6_d, static) =
{
.arc_name = "ip6-unicast",
.node_name = "srv6-end-m-gtp6-d",
.runs_before = 0,
};
VLIB_INIT_FUNCTION (srv6_end_m_gtp6_d_init);
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+218
View File
@@ -0,0 +1,218 @@
/*
* srv6_end_m_gtp6_d_di_di.c
*
* Copyright (c) 2019 Arrcus Inc and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/vnet.h>
#include <vnet/adj/adj.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <srv6-mobile/mobile.h>
srv6_end_main_v6_decap_di_t srv6_end_main_v6_decap_di;
static void
clb_dpo_lock_srv6_end_m_gtp6_d_di (dpo_id_t * dpo)
{
}
static void
clb_dpo_unlock_srv6_end_m_gtp6_d_di (dpo_id_t * dpo)
{
}
static u8 *
clb_dpo_format_srv6_end_m_gtp6_d_di (u8 * s, va_list * args)
{
index_t index = va_arg (*args, index_t);
CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
return (format (s, "SR: dynamic_proxy_index:[%u]", index));
}
const static dpo_vft_t dpo_vft = {
.dv_lock = clb_dpo_lock_srv6_end_m_gtp6_d_di,
.dv_unlock = clb_dpo_unlock_srv6_end_m_gtp6_d_di,
.dv_format = clb_dpo_format_srv6_end_m_gtp6_d_di,
};
const static char *const srv6_end_m_gtp6_d_di_nodes[] = {
"srv6-end-m-gtp6-d-di",
NULL,
};
const static char *const *const dpo_nodes[DPO_PROTO_NUM] = {
[DPO_PROTO_IP6] = srv6_end_m_gtp6_d_di_nodes,
};
static u8 fn_name[] = "SRv6-End.M.GTP6.D.DI-plugin";
static u8 keyword_str[] = "end.m.gtp6.d.di";
static u8 def_str[] =
"Endpoint function with drop-in dencapsulation for IPv6/GTP tunnel";
static u8 param_str[] = "<sr-prefix>/<sr-prefixlen> [nhtype <nhtype>]";
static u8 *
clb_format_srv6_end_m_gtp6_d_di (u8 * s, va_list * args)
{
srv6_end_gtp6_param_t *ls_mem = va_arg (*args, void *);
s = format (s, "SRv6 End gtp6.d Drop-in\n\t");
s =
format (s, "SR Prefix: %U/%d", format_ip6_address, &ls_mem->sr_prefix,
ls_mem->sr_prefixlen);
if (ls_mem->nhtype != SRV6_NHTYPE_NONE)
{
if (ls_mem->nhtype == SRV6_NHTYPE_IPV4)
s = format (s, ", NHType IPv4\n");
else if (ls_mem->nhtype == SRV6_NHTYPE_IPV6)
s = format (s, ", NHType IPv6\n");
else if (ls_mem->nhtype == SRV6_NHTYPE_NON_IP)
s = format (s, ", NHType Non-IP\n");
else
s = format (s, ", NHType Unknow(%d)\n", ls_mem->nhtype);
}
else
s = format (s, "\n");
return s;
}
static uword
clb_unformat_srv6_end_m_gtp6_d_di (unformat_input_t * input, va_list * args)
{
void **plugin_mem_p = va_arg (*args, void **);
srv6_end_gtp6_param_t *ls_mem;
ip6_address_t sr_prefix;
u32 sr_prefixlen = 0;
u8 nhtype;
if (unformat (input, "end.m.gtp6.d.di %U/%d nhtype ipv4",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_IPV4;
}
else if (unformat (input, "end.m.gtp6.d.di %U/%d nhtype ipv6",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_IPV6;
}
else if (unformat (input, "end.m.gtp6.d.di %U/%d nhtype non-ip",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_NON_IP;
}
else if (unformat (input, "end.m.gtp6.d.di %U/%d",
unformat_ip6_address, &sr_prefix, &sr_prefixlen))
{
nhtype = SRV6_NHTYPE_NONE;
}
else
{
return 0;
}
ls_mem = clib_mem_alloc_aligned_at_offset (sizeof *ls_mem, 0, 0, 1);
clib_memset (ls_mem, 0, sizeof *ls_mem);
*plugin_mem_p = ls_mem;
ls_mem->sr_prefix = sr_prefix;
ls_mem->sr_prefixlen = sr_prefixlen;
ls_mem->nhtype = nhtype;
return 1;
}
static int
clb_creation_srv6_end_m_gtp6_d_di (ip6_sr_localsid_t * localsid)
{
return 0;
}
static int
clb_removal_srv6_end_m_gtp6_d_di (ip6_sr_localsid_t * localsid)
{
srv6_end_gtp6_param_t *ls_mem;
ls_mem = localsid->plugin_mem;
clib_mem_free (ls_mem);
return 0;
}
static clib_error_t *
srv6_end_m_gtp6_d_di_init (vlib_main_t * vm)
{
srv6_end_main_v6_decap_di_t *sm = &srv6_end_main_v6_decap_di;
ip6srv_combo_header_t *ip6;
dpo_type_t dpo_type;
vlib_node_t *node;
u32 rc;
sm->vlib_main = vm;
sm->vnet_main = vnet_get_main ();
node = vlib_get_node_by_name (vm, (u8 *) "srv6-end-m-gtp6-d-di");
sm->end_m_gtp6_d_di_node_index = node->index;
node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
sm->error_node_index = node->index;
ip6 = &sm->cache_hdr;
clib_memset_u8 (ip6, 0, sizeof (ip6srv_combo_header_t));
// IPv6 header (default)
ip6->ip.ip_version_traffic_class_and_flow_label = 0x60;
ip6->ip.hop_limit = 64;
ip6->ip.protocol = IPPROTO_IPV6_ROUTE;
// SR header (default)
ip6->sr.type = 4;
dpo_type = dpo_register_new_type (&dpo_vft, dpo_nodes);
rc = sr_localsid_register_function (vm, fn_name, keyword_str, def_str, param_str, 128, //prefix len
&dpo_type,
clb_format_srv6_end_m_gtp6_d_di,
clb_unformat_srv6_end_m_gtp6_d_di,
clb_creation_srv6_end_m_gtp6_d_di,
clb_removal_srv6_end_m_gtp6_d_di);
if (rc < 0)
clib_error_return (0, "SRv6 Endpoint GTP6.D.DI LocalSID function"
"couldn't be registered");
return 0;
}
/* *INDENT-OFF* */
VNET_FEATURE_INIT (srv6_end_m_gtp6_d_di, static) =
{
.arc_name = "ip6-unicast",
.node_name = "srv6-end-m-gtp6-d-di",
.runs_before = 0,
};
VLIB_INIT_FUNCTION (srv6_end_m_gtp6_d_di_init);
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+157
View File
@@ -0,0 +1,157 @@
/*
* srv6_end_m_gtp6_e.c
*
* Copyright (c) 2019 Arrcus Inc and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/vnet.h>
#include <vnet/adj/adj.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <srv6-mobile/mobile.h>
srv6_end_main_v6_t srv6_end_main_v6;
static void
clb_dpo_lock_srv6_end_m_gtp6_e (dpo_id_t * dpo)
{
}
static void
clb_dpo_unlock_srv6_end_m_gtp6_e (dpo_id_t * dpo)
{
}
static u8 *
clb_dpo_format_srv6_end_m_gtp6_e (u8 * s, va_list * args)
{
index_t index = va_arg (*args, index_t);
CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
return (format (s, "SR: dynamic_proxy_index:[%u]", index));
}
const static dpo_vft_t dpo_vft = {
.dv_lock = clb_dpo_lock_srv6_end_m_gtp6_e,
.dv_unlock = clb_dpo_unlock_srv6_end_m_gtp6_e,
.dv_format = clb_dpo_format_srv6_end_m_gtp6_e,
};
const static char *const srv6_end_m_gtp6_e_nodes[] = {
"srv6-end-m-gtp6-e",
NULL,
};
const static char *const *const dpo_nodes[DPO_PROTO_NUM] = {
[DPO_PROTO_IP6] = srv6_end_m_gtp6_e_nodes,
};
static u8 fn_name[] = "SRv6-End.M.GTP6.E-plugin";
static u8 keyword_str[] = "end.m.gtp6.e";
static u8 def_str[] =
"Endpoint function with encapsulation for IPv6/GTP tunnel";
static u8 param_str[] = "";
static u8 *
clb_format_srv6_end_m_gtp6_e (u8 * s, va_list * args)
{
s = format (s, "SRv6 End format function unsupported.");
return s;
}
static uword
clb_unformat_srv6_end_m_gtp6_e (unformat_input_t * input, va_list * args)
{
if (!unformat (input, "end.m.gtp6.e"))
return 0;
return 1;
}
static int
clb_creation_srv6_end_m_gtp6_e (ip6_sr_localsid_t * localsid)
{
return 0;
}
static int
clb_removal_srv6_end_m_gtp6_e (ip6_sr_localsid_t * localsid)
{
return 0;
}
static clib_error_t *
srv6_end_m_gtp6_e_init (vlib_main_t * vm)
{
srv6_end_main_v6_t *sm = &srv6_end_main_v6;
ip6_header_t *ip6 = &sm->cache_hdr.ip6;
udp_header_t *udp = &sm->cache_hdr.udp;
gtpu_header_t *gtpu = &sm->cache_hdr.gtpu;
dpo_type_t dpo_type;
vlib_node_t *node;
u32 rc;
sm->vlib_main = vm;
sm->vnet_main = vnet_get_main ();
node = vlib_get_node_by_name (vm, (u8 *) "srv6-end-m-gtp6-e");
sm->end_m_gtp6_e_node_index = node->index;
node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
sm->error_node_index = node->index;
// clear the pre cached packet
clib_memset_u8 (ip6, 0, sizeof (ip6_gtpu_header_t));
// set defaults
ip6->ip_version_traffic_class_and_flow_label = 0x60;
ip6->protocol = IP_PROTOCOL_UDP;
ip6->hop_limit = 64;
udp->dst_port = clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT);
gtpu->ver_flags = GTPU_V1_VER | GTPU_PT_GTP;
gtpu->type = GTPU_TYPE_GTPU;
dpo_type = dpo_register_new_type (&dpo_vft, dpo_nodes);
rc = sr_localsid_register_function (vm, fn_name, keyword_str, def_str, param_str, 128, //prefix len
&dpo_type,
clb_format_srv6_end_m_gtp6_e,
clb_unformat_srv6_end_m_gtp6_e,
clb_creation_srv6_end_m_gtp6_e,
clb_removal_srv6_end_m_gtp6_e);
if (rc < 0)
clib_error_return (0, "SRv6 Endpoint GTP6.E LocalSID function"
"couldn't be registered");
return 0;
}
/* *INDENT-OFF* */
VNET_FEATURE_INIT (srv6_end_m_gtp6_e, static) =
{
.arc_name = "ip6-unicast",
.node_name = "srv6-end-m-gtp6-e",
.runs_before = 0,
};
VLIB_INIT_FUNCTION (srv6_end_m_gtp6_e_init);
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+243
View File
@@ -0,0 +1,243 @@
/*
* srv6_end.h
*
* Copyright (c) 2019 Arrcus Inc and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __included_srv6_end_h__
#define __included_srv6_end_h__
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/srv6/sr.h>
#include <vnet/srv6/sr_packet.h>
#include <vppinfra/error.h>
#include <vppinfra/elog.h>
#define SRV6_GTP_UDP_DST_PORT 2152
#define SRV6_NHTYPE_NONE 0
#define SRV6_NHTYPE_IPV4 1
#define SRV6_NHTYPE_IPV6 2
#define SRV6_NHTYPE_NON_IP 3
#ifndef IP_PROTOCOL_NONE
#define IP_PROTOCOL_NONE 59
#endif
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define BITALIGN2(A,B) A; B
#define BITALIGN3(A,B,C) A; B; C
#else
#define BITALIGN2(A,B) B; A
#define BITALIGN3(A,B,C) C; B; A
#endif
#define GTPU_EXTHDR_FLAG 0x04
#define GTPU_EXTHDR_PDU_SESSION 0x85
#define SRH_TAG_ECHO_REPLY 0x0008
#define SRH_TAG_ECHO_REQUEST 0x0004
#define SRH_TAG_ERROR_INDICATION 0x0002
#define SRH_TAG_END_MARKER 0x0001
/* *INDENT-OFF* */
typedef struct
{
u16 seq;
u8 npdu_num;
u8 nextexthdr;
} __attribute__ ((packed)) gtpu_exthdr_t;
/* *INDENT-ON* */
/* *INDENT-OFF* */
typedef struct
{
u8 ver_flags;
u8 type;
u16 length; /* length in octets of the payload */
u32 teid;
gtpu_exthdr_t ext[0];
} __attribute__ ((packed)) gtpu_header_t;
/* *INDENT-ON* */
#define GTPU_TYPE_ECHO_REQUEST 1
#define GTPU_TYPE_ECHO_REPLY 2
#define GTPU_TYPE_ERROR_INDICATION 26
#define GTPU_TYPE_END_MARKER 254
#define GTPU_TYPE_GTPU 255
/* *INDENT-OFF* */
typedef struct
{
BITALIGN2 (u8 ppi:3,
u8 spare:5);
u8 padding[3];
} __attribute__ ((packed)) gtpu_paging_policy_t;
/* *INDENT-ON* */
/* *INDENT-OFF* */
typedef struct
{
u8 exthdrlen;
BITALIGN2(u8 type:4,
u8 spare:4);
union {
struct gtpu_qfi_bits {BITALIGN3(u8 p:1,
u8 r:1,
u8 qfi:6);
} bits;
u8 val;
} u;
gtpu_paging_policy_t paging[0];
u8 nextexthdr;
} __attribute__ ((packed)) gtpu_pdu_session_t;
/* *INDENT-ON* */
#define GTPU_PDU_SESSION_P_BIT_MASK 0x80
#define GTPU_PDU_SESSION_R_BIT_MASK 0x40
#define GTPU_PDU_SESSION_QFI_MASK 0x3f
#define SRV6_PDU_SESSION_U_BIT_MASK 0x01
#define SRV6_PDU_SESSION_R_BIT_MASK 0x02
#define SRV6_PDU_SESSION_QFI_MASK 0xfC
/* *INDENT-OFF* */
typedef struct
{
ip4_header_t ip4; /* 20 bytes */
udp_header_t udp; /* 8 bytes */
gtpu_header_t gtpu; /* 8 bytes */
} __attribute__ ((packed)) ip4_gtpu_header_t;
/* *INDENT-ON* */
/* *INDENT-OFF* */
typedef struct
{
ip6_header_t ip6; /* 40 bytes */
udp_header_t udp; /* 8 bytes */
gtpu_header_t gtpu; /* 8 bytes */
} __attribute__ ((packed)) ip6_gtpu_header_t;
/* *INDENT-ON* */
#define GTPU_V1_VER (1<<5)
#define GTPU_PT_GTP (1<<4)
typedef struct srv6_end_gtp6_param_s
{
u8 nhtype;
ip6_address_t sr_prefix;
u32 sr_prefixlen;
} srv6_end_gtp6_param_t;
typedef struct srv6_end_gtp4_param_s
{
u8 nhtype;
ip6_address_t sr_prefix;
u32 sr_prefixlen;
ip6_address_t v6src_prefix;
u32 v6src_prefixlen;
u32 v4src_position;
} srv6_end_gtp4_param_t;
typedef struct srv6_end_main_v4_s
{
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
u32 end_m_gtp4_e_node_index;
u32 error_node_index;
u32 dst_p_len; // dst prefix len
u32 src_p_len; // src prefix len
ip4_gtpu_header_t cache_hdr;
} srv6_end_main_v4_t;
typedef struct srv6_end_main_v4_decap_s
{
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
u32 end_m_gtp4_d_node_index;
u32 error_node_index;
ip6_header_t cache_hdr;
} srv6_end_main_v4_decap_t;
extern srv6_end_main_v4_t srv6_end_main_v4;
extern srv6_end_main_v4_decap_t srv6_end_main_v4_decap;
extern vlib_node_registration_t srv6_end_m_gtp4_e;
typedef struct srv6_end_main_v6_s
{
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
u32 end_m_gtp6_e_node_index;
u32 error_node_index;
ip6_gtpu_header_t cache_hdr;
} srv6_end_main_v6_t;
extern srv6_end_main_v6_t srv6_end_main_v6;
extern vlib_node_registration_t srv6_end_m_gtp6_e;
typedef struct srv6_end_main_v6_decap_s
{
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
u32 end_m_gtp6_d_node_index;
u32 error_node_index;
ip6_header_t cache_hdr;
} srv6_end_main_v6_decap_t;
extern srv6_end_main_v6_decap_t srv6_end_main_v6_decap;
extern vlib_node_registration_t srv6_end_m_gtp6_d;
typedef struct srv6_end_main_v6_decap_di_s
{
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
u32 end_m_gtp6_d_di_node_index;
u32 error_node_index;
ip6srv_combo_header_t cache_hdr;
} srv6_end_main_v6_decap_di_t;
extern srv6_end_main_v6_decap_di_t srv6_end_main_v6_decap_di;
extern vlib_node_registration_t srv6_end_m_gtp6_d_di;
#endif /* __included_srv6_end_h__ */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,161 @@
#!/usr/bin/env python
from framework import VppTestCase
from ipaddress import IPv4Address
from ipaddress import IPv6Address
from scapy.contrib.gtp import *
from scapy.all import *
class TestSRv6EndMGTP4E(VppTestCase):
""" SRv6 End.M.GTP4.E (SRv6 -> GTP-U) """
@classmethod
def setUpClass(cls):
super(TestSRv6EndMGTP4E, cls).setUpClass()
try:
cls.create_pg_interfaces(range(2))
cls.pg_if_i = cls.pg_interfaces[0]
cls.pg_if_o = cls.pg_interfaces[1]
cls.pg_if_i.config_ip6()
cls.pg_if_o.config_ip4()
cls.ip4_dst = cls.pg_if_o.remote_ip4
# cls.ip4_src = cls.pg_if_o.local_ip4
cls.ip4_src = "192.168.192.10"
for pg_if in cls.pg_interfaces:
pg_if.admin_up()
pg_if.resolve_arp()
except Exception:
super(TestSRv6EndMGTP4E, cls).tearDownClass()
raise
def create_packets(self, inner):
ip4_dst = IPv4Address(str(self.ip4_dst))
# 32bit prefix + 32bit IPv4 DA + 8bit + 32bit TEID + 24bit
dst = b'\xaa' * 4 + ip4_dst.packed + \
b'\x11' + b'\xbb' * 4 + b'\x11' * 3
ip6_dst = IPv6Address(dst)
ip4_src = IPv4Address(str(self.ip4_src))
# 64bit prefix + 32bit IPv4 SA + 16 bit port + 16bit
src = b'\xcc' * 8 + ip4_src.packed + \
b'\xdd' * 2 + b'\x11' * 2
ip6_src = IPv6Address(src)
self.logger.info("ip4 dst: {}".format(ip4_dst))
self.logger.info("ip4 src: {}".format(ip4_src))
self.logger.info("ip6 dst (remote srgw): {}".format(ip6_dst))
self.logger.info("ip6 src (local srgw): {}".format(ip6_src))
pkts = list()
for d, s in inner:
pkt = (Ether() /
IPv6(dst=str(ip6_dst), src=str(ip6_src)) /
IPv6ExtHdrSegmentRouting() /
IPv6(dst=d, src=s) /
UDP(sport=1000, dport=23))
self.logger.info(pkt.show2())
pkts.append(pkt)
return pkts
def test_srv6_end(self):
""" test_srv6_end """
pkts = self.create_packets([("A::1", "B::1"), ("C::1", "D::1")])
self.vapi.cli(
"sr localsid address {} behavior end.m.gtp4.e v4src_position 64"
.format(pkts[0]['IPv6'].dst))
self.logger.info(self.vapi.cli("show sr localsids"))
self.vapi.cli("clear errors")
self.pg0.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
self.logger.info(self.vapi.cli("show errors"))
self.logger.info(self.vapi.cli("show int address"))
capture = self.pg1.get_capture(len(pkts))
for pkt in capture:
self.logger.info(pkt.show2())
self.assertEqual(pkt[IP].dst, self.ip4_dst)
self.assertEqual(pkt[IP].src, self.ip4_src)
self.assertEqual(pkt[GTP_U_Header].teid, 0xbbbbbbbb)
class TestSRv6TMTmap(VppTestCase):
""" SRv6 T.M.Tmap (GTP-U -> SRv6) """
@classmethod
def setUpClass(cls):
super(TestSRv6TMTmap, cls).setUpClass()
try:
cls.create_pg_interfaces(range(2))
cls.pg_if_i = cls.pg_interfaces[0]
cls.pg_if_o = cls.pg_interfaces[1]
cls.pg_if_i.config_ip4()
cls.pg_if_o.config_ip6()
for pg_if in cls.pg_interfaces:
pg_if.admin_up()
pg_if.resolve_arp()
except Exception:
super(TestSRv6TMTmap, cls).tearDownClass()
raise
class TestSRv6EndMGTP6E(VppTestCase):
""" SRv6 End.M.GTP6.E """
@classmethod
def setUpClass(cls):
super(TestSRv6EndMGTP6E, cls).setUpClass()
try:
cls.create_pg_interfaces(range(2))
cls.pg_if_i = cls.pg_interfaces[0]
cls.pg_if_o = cls.pg_interfaces[1]
cls.pg_if_i.config_ip4()
cls.pg_if_o.config_ip6()
for pg_if in cls.pg_interfaces:
pg_if.admin_up()
pg_if.resolve_arp()
except Exception:
super(TestSRv6EndMGTP6E, cls).tearDownClass()
raise
class TestSRv6EndMGTP6D(VppTestCase):
""" SRv6 End.M.GTP6.D """
@classmethod
def setUpClass(cls):
super(TestSRv6EndMGTP6D, cls).setUpClass()
try:
cls.create_pg_interfaces(range(2))
cls.pg_if_i = cls.pg_interfaces[0]
cls.pg_if_o = cls.pg_interfaces[1]
cls.pg_if_i.config_ip4()
cls.pg_if_o.config_ip6()
for pg_if in cls.pg_interfaces:
pg_if.admin_up()
pg_if.resolve_arp()
except Exception:
super(TestSRv6EndMGTP6D, cls).tearDownClass()
raise
+1
View File
@@ -9796,6 +9796,7 @@ api_sr_localsid_add_del (vat_main_t * vam)
M (SR_LOCALSID_ADD_DEL, mp);
clib_memcpy (mp->localsid.addr, &localsid, sizeof (mp->localsid));
if (nexthop_set)
{
clib_memcpy (mp->nh_addr6, &nh_addr6, sizeof (mp->nh_addr6));
+18 -6
View File
@@ -54,6 +54,14 @@
#define SR_SEGMENT_LIST_WEIGHT_DEFAULT 1
/* *INDENT-OFF* */
typedef struct
{
ip6_header_t ip;
ip6_sr_header_t sr;
} __attribute__ ((packed)) ip6srv_combo_header_t;
/* *INDENT-ON* */
/**
* @brief SR Segment List (SID list)
*/
@@ -103,6 +111,8 @@ typedef struct
{
ip6_address_t localsid; /**< LocalSID IPv6 address */
u16 localsid_len;
char end_psp; /**< Combined with End.PSP? */
u16 behavior; /**< Behavior associated to this localsid */
@@ -141,6 +151,8 @@ typedef struct
u8 *params_str; /**< Behavior parameters (i.e. <oif> <IP46next_hop>) */
u8 prefix_length;
dpo_type_t dpo; /**< DPO type registration */
format_function_t *ls_format; /**< LocalSID format function */
@@ -250,7 +262,8 @@ extern void sr_dpo_unlock (dpo_id_t * dpo);
extern int
sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
u8 * keyword_str, u8 * def_str,
u8 * params_str, dpo_type_t * dpo,
u8 * params_str, u8 prefix_length,
dpo_type_t * dpo,
format_function_t * ls_format,
unformat_function_t * ls_unformat,
sr_plugin_callback_t * creation_fn,
@@ -259,14 +272,13 @@ sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
extern int
sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
u32 weight, u8 behavior, u32 fib_table, u8 is_encap);
extern int
sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
u8 operation, ip6_address_t * segments, u32 sl_index,
u32 weight);
extern int sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
u8 operation, ip6_address_t * segments,
u32 sl_index, u32 weight);
extern int sr_policy_del (ip6_address_t * bsid, u32 index);
extern int
sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, u16 prefixlen,
char end_psp, u8 behavior, u32 sw_if_index,
u32 vlan_index, u32 fib_table, ip46_address_t * nh_addr,
void *ls_plugin_mem);
+1 -1
View File
@@ -80,7 +80,7 @@ static void vl_api_sr_localsid_add_del_t_handler
memcpy (&prefix.ip6, mp->nh_addr6, sizeof (prefix.ip6));
rv = sr_cli_localsid (mp->is_del,
(ip6_address_t *) & mp->localsid,
(ip6_address_t *) & mp->localsid, 0,
mp->end_psp,
mp->behavior,
ntohl (mp->sw_if_index),
+52 -20
View File
@@ -63,13 +63,15 @@ static dpo_type_t sr_localsid_d_dpo_type;
* @return 0 on success, error otherwise.
*/
int
sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, u16 prefixlen,
char end_psp, u8 behavior, u32 sw_if_index, u32 vlan_index,
u32 fib_table, ip46_address_t * nh_addr, void *ls_plugin_mem)
{
ip6_sr_main_t *sm = &sr_main;
uword *p;
int rv;
u8 pref_length = 128;
sr_localsid_fn_registration_t *plugin = 0;
ip6_sr_localsid_t *ls = 0;
@@ -84,18 +86,30 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
{
/* Retrieve localsid */
ls = pool_elt_at_index (sm->localsids, p[0]);
if (ls->behavior >= SR_BEHAVIOR_LAST)
{
plugin = pool_elt_at_index (sm->plugin_functions,
ls->behavior - SR_BEHAVIOR_LAST);
pref_length = plugin->prefix_length;
}
if (prefixlen != 0)
{
pref_length = prefixlen;
}
/* Delete FIB entry */
fib_prefix_t pfx = {
.fp_proto = FIB_PROTOCOL_IP6,
.fp_len = 128,
.fp_len = pref_length,
.fp_addr = {
.ip6 = *localsid_addr,
}
};
fib_table_entry_delete (fib_table_find (FIB_PROTOCOL_IP6,
fib_table),
&pfx, FIB_SOURCE_SR);
fib_table_entry_delete (fib_table_find
(FIB_PROTOCOL_IP6, fib_table), &pfx,
FIB_SOURCE_SR);
/* In case it is a Xconnect iface remove the (OIF, NHOP) adj */
if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX6
@@ -104,10 +118,6 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
if (ls->behavior >= SR_BEHAVIOR_LAST)
{
sr_localsid_fn_registration_t *plugin = 0;
plugin = pool_elt_at_index (sm->plugin_functions,
ls->behavior - SR_BEHAVIOR_LAST);
/* Callback plugin removal function */
rv = plugin->removal (ls);
}
@@ -125,15 +135,28 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
if (is_del)
return -2;
if (behavior >= SR_BEHAVIOR_LAST)
{
sr_localsid_fn_registration_t *plugin = 0;
plugin =
pool_elt_at_index (sm->plugin_functions, behavior - SR_BEHAVIOR_LAST);
pref_length = plugin->prefix_length;
}
/* Check whether there exists a FIB entry with such address */
fib_prefix_t pfx = {
.fp_proto = FIB_PROTOCOL_IP6,
.fp_len = 128,
.fp_len = pref_length,
};
pfx.fp_addr.as_u64[0] = localsid_addr->as_u64[0];
pfx.fp_addr.as_u64[1] = localsid_addr->as_u64[1];
if (prefixlen != 0)
{
pfx.fp_len = prefixlen;
}
/* Lookup the FIB index associated to the table id provided */
u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, fib_table);
if (fib_index == ~0)
@@ -153,6 +176,7 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
ls->behavior = behavior;
ls->nh_adj = (u32) ~ 0;
ls->fib_table = fib_table;
ls->localsid_len = pfx.fp_len;
switch (behavior)
{
case SR_BEHAVIOR_END:
@@ -267,6 +291,7 @@ sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
vnet_main_t *vnm = vnet_get_main ();
ip6_sr_main_t *sm = &sr_main;
u32 sw_if_index = (u32) ~ 0, vlan_index = (u32) ~ 0, fib_index = 0;
u16 prefix_len = 0;
int is_del = 0;
int end_psp = 0;
ip6_address_t resulting_address;
@@ -288,6 +313,10 @@ sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
&& unformat (input, "address %U", unformat_ip6_address,
&resulting_address))
address_set = 1;
else if (!address_set
&& unformat (input, "prefix %U/%d", unformat_ip6_address,
&resulting_address, &prefix_len))
address_set = 1;
else if (!address_set
&& unformat (input, "addr %U", unformat_ip6_address,
&resulting_address))
@@ -325,12 +354,12 @@ sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
sr_localsid_fn_registration_t **plugin_it = 0;
/* Create a vector out of the plugin pool as recommended */
/* *INDENT-OFF* */
pool_foreach (plugin, sm->plugin_functions,
{
vec_add1 (vec_plugins, plugin);
});
/* *INDENT-ON* */
/* *INDENT-OFF* */
pool_foreach (plugin, sm->plugin_functions,
{
vec_add1 (vec_plugins, plugin);
});
/* *INDENT-ON* */
vec_foreach (plugin_it, vec_plugins)
{
@@ -373,9 +402,10 @@ sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
return clib_error_return (0,
"Error: SRv6 PSP only compatible with End and End.X");
rv = sr_cli_localsid (is_del, &resulting_address, end_psp, behavior,
sw_if_index, vlan_index, fib_index, &next_hop,
ls_plugin_mem);
rv =
sr_cli_localsid (is_del, &resulting_address, prefix_len, end_psp,
behavior, sw_if_index, vlan_index, fib_index, &next_hop,
ls_plugin_mem);
switch (rv)
{
@@ -1533,7 +1563,8 @@ const static char *const *const sr_loc_d_nodes[DPO_PROTO_NUM] = {
int
sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
u8 * keyword_str, u8 * def_str,
u8 * params_str, dpo_type_t * dpo,
u8 * params_str, u8 prefix_length,
dpo_type_t * dpo,
format_function_t * ls_format,
unformat_function_t * ls_unformat,
sr_plugin_callback_t * creation_fn,
@@ -1562,6 +1593,7 @@ sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
plugin->sr_localsid_function_number = (plugin - sm->plugin_functions);
plugin->sr_localsid_function_number += SR_BEHAVIOR_LAST;
plugin->prefix_length = prefix_length;
plugin->ls_format = ls_format;
plugin->ls_unformat = ls_unformat;
plugin->creation = creation_fn;