summaryrefslogtreecommitdiffstats
path: root/src/plugins/linux-cp/lcp_node.c
diff options
context:
space:
mode:
authorAdrian Pistol <vifino@posteo.net>2023-06-07 15:28:17 +0200
committerMatthew Smith <mgsmith@netgate.com>2023-07-11 17:09:25 +0000
commit44b3abe86ab49a35403ba8d3938955549e392d22 (patch)
treef8dda9648b065b20c8226a557dd2745861d2c095 /src/plugins/linux-cp/lcp_node.c
parentff27c9f8ecb08ff0f5b98332975733e8bab125f1 (diff)
linux-cp: Basic MPLS support.
1) Imports ENCAP_MPLS labels from IPv4/IPv6 routes. Note that this requires libnl 3.6.0 or newer. In previous patches, the fib_path_ext_t had a path ID of -1. After a long investigation, it turned out to be caused by route weight being set to 0. There is a comment explaining more details. 2) Handles MPLS routes. MPLS routes were wrongly added as IPv4 routes before. POP and SWAP are now both supported. All the routes are installed as NON-EOS and EOS routes, as the Linux kernel does not differentiate. EOS POP used in PHP uses the next-hop address family to determine the resulting address family. This patch is sufficient for P setups. PE setups with implicit null should also function okay, as long as a seperate label gets programmed per address family. PE setups with explicit null will also forward packets, but punting is a bit odd and needs MPLS input enabled on the LCP host device. 3) Propagate MPLS input state to LCP Pair and Linux. Since the Linux kernel uses the MPLS routes itself, the LCP pair tap needs MPLS enabled to allow host originated packets. This also syncs the Linux `net.mpls.conf.<host_if>.input` sysctl to allow punted packets to have MPLS labels, mostly explicit nulls. In addition, a special feature is enabled to cross connect MPLS packets coming from Linux directly to interface-output untouched. Make sure to enable MPLS/add a table in VPP first and load the MPLS kernel modules!! Type: feature Change-Id: Ie4184bb4cc96905bf8b483a27e7ca6d251697374 Signed-off-by: Adrian Pistol <vifino@posteo.net> Signed-off-by: Pim van Pelt <pim@ipng.nl>
Diffstat (limited to 'src/plugins/linux-cp/lcp_node.c')
-rw-r--r--src/plugins/linux-cp/lcp_node.c100
1 files changed, 99 insertions, 1 deletions
diff --git a/src/plugins/linux-cp/lcp_node.c b/src/plugins/linux-cp/lcp_node.c
index b00049884ea..241cc5e4bff 100644
--- a/src/plugins/linux-cp/lcp_node.c
+++ b/src/plugins/linux-cp/lcp_node.c
@@ -31,6 +31,7 @@
#include <vnet/ip/ip4.h>
#include <vnet/ip/ip6.h>
#include <vnet/l2/l2_input.h>
+#include <vnet/mpls/mpls.h>
#define foreach_lip_punt \
_ (IO, "punt to host") \
@@ -438,6 +439,103 @@ VNET_FEATURE_INIT (lcp_xc_ip6_mcast_node, static) = {
typedef enum
{
+ LCP_XC_MPLS_NEXT_DROP,
+ LCP_XC_MPLS_NEXT_IO,
+ LCP_XC_MPLS_N_NEXT,
+} lcp_xc_mpls_next_t;
+
+static_always_inline uword
+lcp_xc_mpls_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
+{
+ u32 n_left_from, *from, *to_next, n_left_to_next;
+ lcp_xc_next_t next_index;
+
+ next_index = 0;
+ n_left_from = frame->n_vectors;
+ from = vlib_frame_vector_args (frame);
+
+ while (n_left_from > 0)
+ {
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ const ethernet_header_t *eth;
+ const lcp_itf_pair_t *lip;
+ u32 next0, bi0, lipi, ai;
+ vlib_buffer_t *b0;
+ // const ip_adjacency_t *adj;
+
+ bi0 = to_next[0] = from[0];
+
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+
+ lipi =
+ lcp_itf_pair_find_by_host (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
+ lip = lcp_itf_pair_get (lipi);
+
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip->lip_phy_sw_if_index;
+ vlib_buffer_advance (b0, -lip->lip_rewrite_len);
+ eth = vlib_buffer_get_current (b0);
+
+ ai = ADJ_INDEX_INVALID;
+ next0 = LCP_XC_MPLS_NEXT_DROP;
+ if (!ethernet_address_cast (eth->dst_address))
+ ai = lcp_adj_lkup ((u8 *) eth, lip->lip_rewrite_len,
+ vnet_buffer (b0)->sw_if_index[VLIB_TX]);
+ if (ai != ADJ_INDEX_INVALID)
+ {
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
+ next0 = LCP_XC_MPLS_NEXT_IO;
+ }
+
+ if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ lcp_xc_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->phy_sw_if_index = lip->lip_phy_sw_if_index;
+ t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+VLIB_NODE_FN (lcp_xc_mpls)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return (lcp_xc_mpls_inline (vm, node, frame));
+}
+
+VLIB_REGISTER_NODE (
+ lcp_xc_mpls) = { .name = "linux-cp-xc-mpls",
+ .vector_size = sizeof (u32),
+ .format_trace = format_lcp_xc_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_next_nodes = LCP_XC_MPLS_N_NEXT,
+ .next_nodes = {
+ [LCP_XC_MPLS_NEXT_DROP] = "error-drop",
+ [LCP_XC_MPLS_NEXT_IO] = "interface-output",
+ } };
+
+VNET_FEATURE_INIT (lcp_xc_mpls_node, static) = {
+ .arc_name = "mpls-input",
+ .node_name = "linux-cp-xc-mpls",
+};
+
+typedef enum
+{
LCP_XC_L3_NEXT_XC,
LCP_XC_L3_NEXT_LOOKUP,
LCP_XC_L3_N_NEXT,
@@ -446,7 +544,7 @@ typedef enum
/**
* X-connect all packets from the HOST to the PHY on L3 interfaces
*
- * There's only one adjacency that can be used on thises links.
+ * There's only one adjacency that can be used on these links.
*/
static_always_inline u32
lcp_xc_l3_inline (vlib_main_t *vm, vlib_node_runtime_t *node,