-
Notifications
You must be signed in to change notification settings - Fork 709
VPP How_to_add_a_tunnel_encapsulation
- 1 Introduction
- 2 Each tunnel instance needs an interface
- 3 Encapsulation Path
- 4 Decapsulation Path
- 5 Adjacency and connection setup
The vpp engine currently supports a number of different tunnel encapsulations. They're all slightly different under the covers, which is not a Good Thing. Strategically, the ip6/l2tpv3 tunnel implementation is probably the closest thing in the source base to a "correct" tunnel implementation. This note is an attempt to codify what we should build moving forward.
Each tunnel type needs an encap path, a decap path, and [most likely] a set of L3 adjacencies to do the job.
I resisted this scheme, up to the point where the vpp engine grew an L2 path. At L3, traffic destined for a tunnel needs a FIB entry, and an appropriate adjacency rewrite. At L3, that's sufficient. The L2 path expects to cross-connect or bridge interfaces, which means that we either create an interface or make a complete mess.
The tunnel interface should have something like the following device class and hardware interface class definitions. Aside from the tunnel name formatter, not much doing:
static u8 * format_l2tpv3_name (u8 * s, va_list * args)
{
u32 dev_instance = va_arg (*args, u32);
return format (s, "l2tpv3_tunnel%d", dev_instance);
}
static uword dummy_interface_tx (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
clib_warning ("you shouldn't be here, leaking buffers...");
return frame->n_vectors;
}
VNET_DEVICE_CLASS (l2tpv3_device_class,static) = {
.name = "L2TPv3",
.format_device_name = format_l2tpv3_name,
.tx_function = dummy_interface_tx,
};
static u8 * format_l2tp_header_with_length (u8 * s, va_list * args)
{
u32 dev_instance = va_arg (*args, u32);
s = format (s, "unimplemented dev %u", dev_instance);
return s;
}
static uword dummy_set_rewrite (vnet_main_t * vnm,
u32 sw_if_index,
u32 l3_type,
void * dst_address,
void * rewrite,
uword max_rewrite_bytes)
{
return 0;
}
VNET_HW_INTERFACE_CLASS (l2tpv3_hw_class) = {
.name = "L2TPV3",
.format_header = format_l2tp_header_with_length,
.set_rewrite = dummy_set_rewrite,
};
Presumably, each tunnel has some sort of instance data. Put its pool index into (one or both of) the vnet hardware dev and hw instance(s):
hw_if_index = vnet_register_interface (vnm, l2tpv3_device_class.index, s - lm->sessions,
l2tpv3_hw_class.index, s - lm->sessions);
hi = vnet_get_hw_interface (vnm, hw_if_index);
hi->dev_instance = s - lm->sessions;
hi->hw_instance = s - lm->sessions;
Each tunnel interface needs an interface transmit routine. Set it up:
hi->output_node_index = tunnel_encap_node.index;
Since vnet interfaces are not actually destroyed, construct a free tunnel index vector and add "deleted" tunnel hw_if_indices to it when deleting a tunnel.
Remember to shut down the tunnel interface so that any traffic being sent to it will be discarded:
vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0 /* admin down */);
Retrieve the tunnel instance from hi->dev_instance:
sw_if_index = vnet_buffer(b)->sw_if_index[VLIB_TX];
hi = vnet_get_sup_hw_interface (rt->vnet_main, sw_if_index);
session_index = hi->dev_instance;
Consider using a 1-wide cache. The encap path processes vectors aimed at individual tunnels, so the cache should hit 99% of the time.
Using the session object, add tunnel encap prior to bN->current_data. Techniques: manually paint an (unrouted) ip4/ip6 header, or apply and fix up a vnet_rewrite_t from the session object. Don't forget to deal with checksums.
When using a rewrite, the traditional method involves precomputing the header checksum with the length field set to zero. Then, fix the checksum in the speed path. Example:
sum0 = ip0->checksum;
old_l0 = 0; /* old_l0 always 0, see the rewrite setup... */
new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
length /* changed member */);
ip0->checksum = ip_csum_fold (sum0);
ip0->length = new_l0;
Push newly tunnel-encapsulated, unrouted packets forward in the graph, to ip4-lookup or ip6-lookup - as appropriate.
Register the decap node with the vpp L3 local stack. If tunnel pkts in need of decapsulation arrive in ip forus packets with a specific protocol - the l2tpv3 case - register as follows:
ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_node.index);
If packets arrive as udp-ip4 forus packets, the vxlan case, register this way:
udp_register_dst_port (vm, UDP_DST_PORT_vxlan, vxlan_udp_node.index, 1 /* is_ip4 */);
In the decap node itself, look up the tunnel session object. The decap path MUST NOT decapsulate packets which lack corresponding valid tunnel objects. Drop-and-count.
Remember to actually pop the tunnel header. Something like this:
vlib_buffer_advance(b0, sizeof(popped_encap)).
When cross-connected or bridging at L2, the decap path must set vnet_buffer(b0)->l2.l2_len. We will turn the following incantation into an inline function any second now; here are the details:
vnet_buffer(b)->l2.l2_len = sizeof(ethernet_header_t);
ethertype = clib_net_to_host_u16(eth->type);
if ((ethertype == ETHERNET_TYPE_VLAN) ||
(ethertype == ETHERNET_TYPE_DOT1AD) ||
(ethertype == ETHERNET_TYPE_VLAN_9100) ||
(ethertype == ETHERNET_TYPE_VLAN_9200)) {
ethernet_vlan_header_t * vlan;
vnet_buffer(b)->l2.l2_len += sizeof (vlan);
vlan = (void *) (eth+1);
ethertype = clib_net_to_host_u16 (vlan->type);
if (ethertype == ETHERNET_TYPE_VLAN) {
vnet_buffer(b)->l2.l2_len += sizeof (vlan);
}
If forwarding newly decapsulated traffic at L2, send packet to l2-input. At L3, send to ip4-lookup / ip6-lookup; remember to set vnet_buffer(b0)->sw_if_index[VLIB_TX] to the desired lookup FIB index based on data in the tunnel's session object.
When operating at L3, give the tunnel interface an address via the use the vl_api_sw_interface_add_del API, or via debug CLI:
set int ip address xxx_tunnelN 192.168.1.1/24
At L2, cross-connect or bridge the tunnel interface, via the vl_api_sw_interface_set_l2_xconnect API for cross-connection or the vl_api_sw_interface_set_l2_bridge API for bridging. If bridinging, place tunnel interfaces into a non-default split-horizon group (e.g. 1).
- VPP 2022 Make Test Use Case Poll
- VPP-AArch64
- VPP-ABF
- VPP Alternative Builds
- VPP API Concepts
- VPP API Versioning
- VPP-ApiChangeProcess
- VPP-ArtifactVersioning
- VPP-BIER
- VPP-Bihash
- VPP-BugReports
- VPP Build System Deep Dive
- VPP Build, Install, And Test Images
- VPP-BuildArtifactRetentionPolicy
- VPP-c2cpel
- VPP Code Walkthrough VoD
- VPP Code Walkthrough VoD Topic Index
- VPP Code Walkthrough VoDs
- VPP-CodeStyleConventions
- VPP-CodingTips
- VPP Command Line Arguments
- VPP Command Line Interface CLI Guide
- VPP-CommitMessages
- VPP-Committers-SMEs
- VPP-CommitterTasks-ApiFreeze
- VPP CommitterTasks Compare API Changes
- VPP-CommitterTasks-CutPointRelease
- VPP-CommitterTasks-CutRelease
- VPP-CommitterTasks-FinalReleaseCandidate
- VPP-CommitterTasks-PullThrottleBranch
- VPP-CommitterTasks-ReleasePlan
- VPP Configuration Tool
- VPP Configure An LW46 MAP E Terminator
- VPP Configure VPP As A Router Between Namespaces
- VPP Configure VPP TAP Interfaces For Container Routing
- VPP-CoreFileMismatch
- VPP-cpel
- VPP-cpeldump
- VPP-CurrentData
- VPP-DHCPKit
- VPP-DHCPv6
- VPP-DistributedOwnership
- VPP-Documentation
- VPP DPOs And Feature Arcs
- VPP EC2 Instance With SRIOV
- VPP-elog
- VPP-FAQ
- VPP Feature Arcs
- VPP-Features
- VPP-Features-IPv6
- VPP-FIB
- VPP-g2
- VPP Getting VPP 16.06
- VPP Getting VPP Release Binaries
- VPP-HA
- VPP-HostStack
- VPP-HostStack-BuiltinEchoClientServer
- VPP-HostStack-EchoClientServer
- VPP-HostStack-ExternalEchoClientServer
- VPP HostStack Hs Test
- VPP-HostStack-LDP-iperf
- VPP-HostStack-LDP-nginx
- VPP-HostStack-LDP-sshd
- VPP-HostStack-nginx
- VPP-HostStack-SessionLayerArchitecture
- VPP-HostStack-TestHttpServer
- VPP-HostStack-TestProxy
- VPP-HostStack-TLS
- VPP-HostStack-VCL
- VPP-HostStack-VclEchoClientServer
- VPP-Hotplug
- VPP How To Add A Tunnel Encapsulation
- VPP How To Build The Sample Plugin
- VPP How To Connect A PCI Interface To VPP
- VPP How To Create A VPP Binary Control Plane API
- VPP How To Deploy VPP In EC2 Instance And Use It To Connect Two Different VPCs
- VPP How To Optimize Performance %28System Tuning%29
- VPP How To Use The API Trace Tools
- VPP How To Use The C API
- VPP How To Use The Packet Generator And Packet Tracer
- VPP-Howtos
- VPP-index
- VPP Installing VPP Binaries From Packages
- VPP Interconnecting vRouters With VPP
- VPP Introduction To IP Adjacency
- VPP Introduction To N Tuple Classifiers
- VPP IP Adjacency Introduction
- VPP-IPFIX
- VPP-IPSec
- VPP IPSec And IKEv2
- VPP IPv6 SR VIRL Topology File
- VPP Java API
- VPP Java API Plugin Support
- VPP Jira Workflow
- VPP-Macswapplugin
- VPP-MakeTestFramework
- VPP-Meeting
- VPP-MFIB
- VPP Missing Prefetches
- VPP Modifying The Packet Processing Directed Graph
- VPP MPLS FIB
- VPP-NAT
- VPP Nataas Test
- VPP-OVN
- VPP Per Feature Notes
- VPP Performance Analysis Tools
- VPP-perftop
- VPP Progressive VPP Tutorial
- VPP Project Meeting Minutes
- VPP Pulling, Building, Running, Hacking And Pushing VPP Code
- VPP Pure L3 Between Namespaces With 32s
- VPP Pure L3 Container Networking
- VPP Pushing And Testing A Tag
- VPP Python API
- VPP-PythonVersionPolicy
- VPP-QuickTrexSetup
- VPP Random Hints And Kinks For KVM Usage
- VPP Release Plans Release Plan 16.09
- VPP Release Plans Release Plan 17.01
- VPP Release Plans Release Plan 17.04
- VPP Release Plans Release Plan 17.07
- VPP Release Plans Release Plan 17.10
- VPP Release Plans Release Plan 18.01
- VPP Release Plans Release Plan 18.04
- VPP Release Plans Release Plan 18.07
- VPP Release Plans Release Plan 18.10
- VPP Release Plans Release Plan 19.01
- VPP Release Plans Release Plan 19.04
- VPP Release Plans Release Plan 19.08
- VPP Release Plans Release Plan 20.01
- VPP Release Plans Release Plan 20.05
- VPP Release Plans Release Plan 20.09
- VPP Release Plans Release Plan 21.01
- VPP Release Plans Release Plan 21.06
- VPP Release Plans Release Plan 21.10
- VPP Release Plans Release Plan 22.02
- VPP Release Plans Release Plan 22.06
- VPP Release Plans Release Plan 22.10
- VPP Release Plans Release Plan 23.02
- VPP Release Plans Release Plan 23.06
- VPP Release Plans Release Plan 23.10
- VPP Release Plans Release Plan 24.02
- VPP Release Plans Release Plan 24.06
- VPP Release Plans Release Plan 24.10
- VPP Release Plans Release Plan 25.02
- VPP Release Plans Release Plan 25.06
- VPP Release Plans Release Plan 25.10
- VPP Release Plans Release Plan 26.02
- VPP Release Plans Release Plan 26.06
- VPP-RM
- VPP-SecurityGroups
- VPP Segment Routing For IPv6
- VPP Segment Routing For MPLS
- VPP Setting Up Your Dev Environment
- VPP-SNAT
- VPP Software Architecture
- VPP STN Testing
- VPP The VPP API
- VPP Training Events
- VPP-Troubleshooting
- VPP-Troubleshooting-BuildIssues
- VPP-Troubleshooting-Vagrant
- VPP Tutorial DPDK And MacSwap
- VPP Tutorial Routing And Switching
- VPP-Tutorials
- VPP Use VPP To Chain VMs Using Vhost User Interface
- VPP Use VPP To Connect VMs Using Vhost User Interface
- VPP Using mTCP User Mode TCP Stack With VPP
- VPP Using VPP As A VXLAN Tunnel Terminator
- VPP Using VPP In A Multi Thread Model
- VPP-VOM
- VPP VPP BFD Nexus
- VPP VPP Home Gateway
- VPP VPP WIKI DEPRECATED CONTENT
- VPP-VPPCommunicationsLibrary
- VPP-VPPConfig
- VPP What Is ODP4VPP
- VPP What Is VPP
- VPP Working Environments
- VPP Working With The 16.06 Throttle Branch