Design

Software architecture

FPTUN-eBPF uses the Linux eBPF architecture to drive packets between the fast path and the Linux networking stack.

Path from the fast path to the Linux networking stack

A VLAN virtual interface (fptun0) is created in the current VRF with VLAN id that matches the VRF vrfid and a tc eBPF filter is attached on ingress and egress. This filter is also attached at ingress on all fast path port interfaces. The fast path adds a VLAN header to the packets and sends them to this fptun0 interface via the fpn0 interface. Statistics can be shown with the following commands:

# tc -s filter show dev eth0 ingress
# tc -s filter show dev fptun0 egress

The FPTUN-eBPF metadata (from the fast path) are stored in a trailer at the end of the packet. The eBPF program get them (exception type, targeted interface, etc.) from this trailer. It removes them before injecting the packet into the Linux networking stack.

The bpf_redirect() function is used to redirect packets from fptun0 (ingress) to the targeted interface (at ingress or egress).

Below is a description of the supported exception types.

FPTUN_BASIC_EXCEPT

This exception is used to inject a L2 packet in an interface (a fast path port) at ingress.

Example of a packet flow for a datagram destinated to a local fast path port interface:

eth0 physical in-interface (FPTUN_BASIC_EXCEPT)
  --> fp_process_input (FPTUN_BASIC_EXCEPT)
  --> fp_ether_input (FPTUN_BASIC_EXCEPT)
  --> fp_ip_input (FPTUN_BASIC_EXCEPT)
  --> fp_ip_input_demux (FPTUN_BASIC_EXCEPT)
  --> fp_bulk_exception (FPTUN_BASIC_EXCEPT)
  --> fp_process_basic_exception (FPTUN_BASIC_EXCEPT)
  --> fp_add_fptunebpf_trailer (FPTUN_BASIC_EXCEPT)
  --> eth0/ingress
  --> _tc_fptun_ebpf (FPTUN_BASIC_EXCEPT)
  --> bpf_skb_change_tail (remove fptun-ebpf trailer)
  --> netif_rx_internal (eth0)

FPTUN_ETH_INPUT_EXCEPT

This exception is used to inject a L2 packet in an interface at ingress.

Example of a packet flow for a datagram destinated to a local VLAN interface:

eth0 physical in-interface (FPTUN_BASIC_EXCEPT)
  --> fp_process_input (FPTUN_BASIC_EXCEPT)
  --> fp_ether_input (FPTUN_BASIC_EXCEPT)
  --> fp_vlan_input (FPTUN_BASIC_EXCEPT)
  --> fp_vlan_bulk_process (vlan1, FPTUN_BASIC_EXCEPT => FPTUN_ETH_INPUT_EXCEPT)
  --> fp_ether_input (FPTUN_ETH_INPUT_EXCEPT)
  --> fp_ip_input (FPTUN_ETH_INPUT_EXCEPT)
  --> fp_ip_input_demux (FPTUN_ETH_INPUT_EXCEPT)
  --> fp_bulk_exception (FPTUN_ETH_INPUT_EXCEPT)
  --> fp_send_fptunebpf (FPTUN_ETH_INPUT_EXCEPT)
  --> fptun0/ingress
  --> _tc_fptun_ebpf (FPTUN_ETH_INPUT_EXCEPT)
  --> bpf_skb_change_tail (remove fptun-ebpf trailer)
  --> bpf_redirect (vlan1 / ingress)
  --> dev_forward_skb (vlan1)
  --> netif_rx_internal (vlan1)

FPTUN_IFACE_INPUT_EXCEPT

This exception is used to inject a L3 packet in an interface at ingress.

FPTUN_IPV4_IPSECDONE_INPUT_EXCEPT

This exception is used to inject a deciphered IPv4 packet in an interface at ingress.

FPTUN_IPV6_IPSECDONE_INPUT_EXCEPT

This exception is used to inject a deciphered IPv6 packet in an interface at ingress.

FPTUN_TAP

This exception is used to inject packets in opened AF_PACKET sockets on a specified interface and drop them before they enter the Linux networking stack. An eBPF program is setup at ingress of the tapped interface. This program drops all packets sent through this exception type. An optional trailer can be put (“FASTPATH OFFLOAD” in ascii) at the end of the packet. It helps to indentify if packets are tapped in the fast path or in the kernel.

Example of a packet flow for a datagram tapped on an input interface:

eth0 physical in-interface (FPTUN_BASIC_EXCEPT)
  --> fp_process_input (FPTUN_BASIC_EXCEPT)
  --> fp_tap_bulk (FPTUN_BASIC_EXCEPT)
  --> fp_prepare_tap_exception (m_dup / FPTUN_TAP)
  --> fp_exception (FPTUN_TAP)
  --> fp_send_fptunebpf (FPTUN_TAP)
  --> fptun0/ingress
  --> _tc_fptun_ebpf (FPTUN_TAP)
  --> bpf_skb_store_bytes (set trailer to "FASTPATH OFFLOAD")
  --> bpf_redirect (eth0 / ingress)
  --> dev_forward_skb (eth0)
  --> netif_rx_internal (eth0)
  --> __netif_receive_skb_core (eth0)
  --> deliver_skb (=> AF_PACKET sockets)
  --> sch_handle_ingress
  --> _tc_fptun_ebpf (drop)

Path from the Linux networking stack to the fast path

A tc eBPF filter is attached on egress of all fast path port interfaces. It is used to add a FPTUN-eBPF header to carry metadata like skb->mark. Statistics can be shown with the following command:

# tc -s filter show dev eth0 egress

The FPTUN-eBPF metadata (from the Linux networking stack) are stored in an FPTUN-eBPF header inserted between the L2 headers (Ethernet header and VLAN headers) and the L3 headers (IPv4, IPv6, MPLS, …) of the packet. The fast path removes this header before processing the packet.

A tc eBPF filter can be manually attached on egress to a virtual interface for redirecting packets in fast path via the fptun0 interface of the current VRF. The filter can be attached with the following commands.

For L2 virtual interfaces:

# tc qdisc add dev vlan1 clsact
# tc filter add dev vlan1 egress matchall action bpf obj /usr/share/fast-path/tc_fptun_ebpf_kern.o sec tc_fpout_l2

For L3 virtual interfaces:

# tc qdisc add dev tun1 clsact
# tc filter add dev tun1 egress matchall action bpf obj /usr/share/fast-path/tc_fptun_ebpf_kern.o sec tc_fpout_l3

The filter can be removed with the following commands:

# tc qdisc del dev vlan1 clsact

FPTUN_ETH_SP_OUTPUT_REQ

This exception is used to carry metadata to fast path for packet sent by the Linux networking stack.

Example of a packet flow for a datagram sent by the Linux networking stack to a fast path port interface:

eth0 tuntap out-interface
  --> __dev_queue_xmit
  --> sch_handle_egress
  --> _tc_fptun_mark
  --> bpf_skb_adjust_room (add fptun-ebpf header)
  --> __dev_xmit_skb()
  --> fpn_fpvi_vhost_input
  --> fp_process_soft_input
  --> fp_fptun_ebpf_header_input (remove fptun-ebpf header)
  --> fp_process_soft_output
  --> eth0 physical out-interface

Example of a packet flow for a datagram sent by the Linux networking stack to a L2 virtual interface:

vlan1 out-interface
  --> __dev_queue_xmit
  --> sch_handle_egress
  --> _tc_fpout_l2
  --> bpf_skb_adjust_room (add fptun-ebpf header)
  --> bpf_redirect (fptun0 / egress)
  --> vlan_dev_hard_start_xmit (fptun0)
  --> dev_queue_xmit (fpn0)
  --> fpn_fpvi_vhost_input
  --> fp_process_soft_input
  --> fp_fptun_ebpf_header_input (remove fptun-ebpf header)
  --> fp_vlan_strip (remove vlan header, vlan tag matches vrfid)
  --> fptun_sp_output_req (cmd FPTUN_ETH_SP_OUTPUT_REQ)
  --> fp_vlan_output(vlan1)

FPTUN_IPV4_SP_OUTPUT_REQ

This exception is used to carry metadata to fast path from packet sent by the Linux networking stack via an IPv4 interface.

Example of a packet flow for a packet sent by the Linux networking stack to a L3 virtual interface:

tun1 out-interface
  --> __dev_queue_xmit
  --> sch_handle_egress
  --> _tc_fpout_l3
  --> bpf_skb_change_head (add fake eth header)
  --> bpf_skb_adjust_room (add fptun-ebpf header)
  --> bpf_redirect (fptun0 / egress)
  --> vlan_dev_hard_start_xmit (fptun0)
  --> dev_queue_xmit (fpn0)
  --> fpn_fpvi_vhost_input
  --> fp_process_soft_input
  --> fp_fptun_ebpf_header_input (remove fptun-ebpf header)
  --> fp_vlan_strip (remove vlan header, vlan tag matches vrfid)
  --> m_adj (remove eth header)
  --> fptun_sp_output_req (cmd FPTUN_IPV4_SP_OUTPUT_REQ)
  --> fp_ip_inetif_send(tun1)

FPTUN_IPV6_SP_OUTPUT_REQ

This exception is used to carry metadata to fast path from packet sent by the Linux networking stack via an IPv6 interface.