Add admin-up flag to L2TP tunnels and start tunnels set to down 01/1701/3
authorPierre Pfister <ppfister@cisco.com>
Wed, 22 Jun 2016 11:54:48 +0000 (12:54 +0100)
committerChris Luke <chris_luke@comcast.com>
Fri, 24 Jun 2016 12:55:22 +0000 (12:55 +0000)
L2TP tunnels use virtual interfaces but directly send
packets to l2-input node (not ethernet-input).
This node requires a bridge-domain to be associated with
the interface.

Past code was immediatly turning the interface up, but
some packets could be sent to l2-input without bridge domain
between interface creation and association with a bridge domain.

The tunnel is now created as down and has to be set up later
(typically after being associated with a bridge-domain).

Another option would have been to change the api and enforce
a bridge-domain to be specified before the tunnel, but this
is less flexible for the user.

Change-Id: I26d1f36bb4f327d9fa1c8044023f2210c4117904
Signed-off-by: Pierre Pfister <ppfister@cisco.com>
vnet/vnet/l2tp/decap.c
vnet/vnet/l2tp/encap.c
vnet/vnet/l2tp/l2tp.c
vnet/vnet/l2tp/l2tp.h

index 5440028..68b7fab 100644 (file)
@@ -27,7 +27,8 @@
 _(USER_TO_NETWORK, "L2TP user (ip6) to L2 network pkts")        \
 _(SESSION_ID_MISMATCH, "l2tpv3 local session id mismatches")    \
 _(COOKIE_MISMATCH, "l2tpv3 local cookie mismatches")            \
-_(NO_SESSION, "l2tpv3 session not found")
+_(NO_SESSION, "l2tpv3 session not found")                       \
+_(ADMIN_DOWN, "l2tpv3 tunnel is down")
 
 static char * l2t_decap_error_strings[] = {
 #define _(sym,string) string,
@@ -169,6 +170,12 @@ static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
 
     vnet_buffer(b)->sw_if_index[VLIB_RX] = session->sw_if_index;
 
+    if (PREDICT_FALSE(!(session->admin_up))) {
+       b->error = node->errors[L2T_DECAP_ERROR_ADMIN_DOWN];
+       next_index = L2T_DECAP_NEXT_DROP;
+       goto done;
+    }
+
     /* strip the ip6 and L2TP header */
     vlib_buffer_advance (b, sizeof (*ip6) + session->l2tp_hdr_size);
 
index eca098c..49f5a15 100644 (file)
@@ -25,7 +25,8 @@
 /* Statistics (not really errors) */
 #define foreach_l2t_encap_error                                        \
 _(NETWORK_TO_USER, "L2TP L2 network to user (ip6) pkts")       \
-_(LOOKUP_FAIL_TO_L3, "L2TP L2 session lookup failed pkts")
+_(LOOKUP_FAIL_TO_L3, "L2TP L2 session lookup failed pkts")      \
+_(ADMIN_DOWN, "L2TP tunnel is down")
 
 static char * l2t_encap_error_strings[] = {
 #define _(sym,string) string,
@@ -105,6 +106,7 @@ static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
     l2t_session_t *s;
     ip6_header_t *ip6;
     u16 payload_length;
+    u32 next_index = L2T_ENCAP_NEXT_IP6_LOOKUP;
 
     /* Other-than-output pkt? We're done... */
     if (vnet_buffer(b)->l2t.next_index != L2T_ENCAP_NEXT_IP6_LOOKUP)
@@ -144,6 +146,12 @@ static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
     vlib_buffer_advance (b, -(sizeof (*ip6)));
     ip6 = vlib_buffer_get_current (b);
 
+    if (PREDICT_FALSE(!(s->admin_up))) {
+       b->error = node->errors[L2T_ENCAP_ERROR_ADMIN_DOWN];
+       next_index = L2T_ENCAP_NEXT_DROP;
+       goto done;
+    }
+
     ip6->ip_version_traffic_class_and_flow_label = 
         clib_host_to_net_u32 (0x6<<28);
 
@@ -159,6 +167,8 @@ static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
     ip6->dst_address.as_u64[0] = s->client_address.as_u64[0];
     ip6->dst_address.as_u64[1] = s->client_address.as_u64[1];
 
+
+ done:
     if (PREDICT_FALSE(b->flags & VLIB_BUFFER_IS_TRACED)) {
         l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
         t->is_user_to_network = 0;
@@ -173,7 +183,7 @@ static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
         t->session_index = session_index;
     }
 
-    return L2T_ENCAP_NEXT_IP6_LOOKUP;
+    return next_index;
 }
 
 #include <vnet/pipeline.h>
index 4380137..85f9c30 100644 (file)
@@ -345,6 +345,7 @@ int create_l2tpv3_ipv6_tunnel (l2t_main_t * lm,
   s->l2tp_hdr_size = l2_sublayer_present ? 
     sizeof (l2tpv3_header_t) :
     sizeof (l2tpv3_header_t) - sizeof(l2tp_hdr.l2_specific_sublayer);
+  s->admin_up = 0;
 
   /* Setup hash table entries */
   switch (lm->lookup_type) {
@@ -402,9 +403,6 @@ int create_l2tpv3_ipv6_tunnel (l2t_main_t * lm,
   if (sw_if_index)
     *sw_if_index = hi->sw_if_index;
 
-  vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 
-                               VNET_SW_INTERFACE_FLAG_ADMIN_UP);
-
   return 0;
 }
 
@@ -665,6 +663,25 @@ l2tp_config (vlib_main_t * vm, unformat_input_t * input)
 
 VLIB_CONFIG_FUNCTION (l2tp_config, "l2tp");
 
+
+clib_error_t *
+l2tp_sw_interface_up_down (vnet_main_t * vnm,
+                                  u32 sw_if_index,
+                                  u32 flags)
+{
+  l2t_main_t *lm = &l2t_main;
+  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
+  if (hi->hw_class_index != l2tpv3_hw_class.index)
+    return 0;
+
+  u32 session_index = hi->dev_instance;
+  l2t_session_t *s = pool_elt_at_index (lm->sessions, session_index);
+  s->admin_up = !! (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+  return 0;
+}
+
+VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2tp_sw_interface_up_down);
+
 clib_error_t *l2tp_init (vlib_main_t *vm)
 {
     l2t_main_t *lm = &l2t_main;
index 2fc90fb..6ca9d7b 100644 (file)
@@ -42,6 +42,8 @@ typedef struct {
     u8  l2tp_hdr_size;
     u8  l2_sublayer_present;
     u8  cookie_flags;           /* in host byte order */
+
+    u8 admin_up;
 } l2t_session_t;
 
 typedef enum {