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:
committed by
Ole Trøan
parent
360b523b52
commit
1b81e6ef66
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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]
|
||||
@@ -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:
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
Executable
+2046
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
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user