ip: reassembly - add a way to disable for forus 94/34994/11
authorKlement Sekera <ksekera@cisco.com>
Tue, 14 Dec 2021 18:25:11 +0000 (18:25 +0000)
committerOle Tr�an <otroan@employees.org>
Mon, 31 Jan 2022 15:07:58 +0000 (15:07 +0000)
Add API to disable full reassembly of "forus" packets. Mark packets
passing through ip[4|6]-local nodes with a new buffer flag and check for
that flag in reassembly.

Enable IP6 "forus" full reassembly by default to be consistent with
existing IP4 setting.

Type: improvement
Change-Id: I7067792fcd4304182654237968e4c4d9293c6143
Signed-off-by: Klement Sekera <ksekera@cisco.com>
13 files changed:
src/vnet/ip/ip.api
src/vnet/ip/ip4_forward.c
src/vnet/ip/ip4_input.c
src/vnet/ip/ip4_input.h
src/vnet/ip/ip6_forward.c
src/vnet/ip/ip_api.c
src/vnet/ip/ip_test.c
src/vnet/ip/reass/ip4_full_reass.c
src/vnet/ip/reass/ip4_full_reass.h
src/vnet/ip/reass/ip6_full_reass.c
src/vnet/ip/reass/ip6_full_reass.h
test/Makefile
test/test_reassembly.py

index ca1e200..cd18098 100644 (file)
@@ -836,6 +836,30 @@ autoreply define ip_reassembly_enable_disable
   vl_api_ip_reass_type_t type;
 };
 
+/** enable/disable full reassembly of packets aimed at our addresses */
+autoreply define ip_local_reass_enable_disable
+{
+  u32 client_index;
+  u32 context;
+  bool enable_ip4;
+  bool enable_ip6;
+};
+
+/** get status of local reassembly */
+define ip_local_reass_get
+{
+  u32 client_index;
+  u32 context;
+};
+
+define ip_local_reass_get_reply
+{
+  u32 context;
+  i32 retval;
+  bool ip4_is_enabled;
+  bool ip6_is_enabled;
+};
+
 /**
     @brief Set a Path MTU value. i.e. a MTU value for a given neighbour.
            The neighbour can be described as attached (w/ interface and next-hop)
index de8e8e8..4d06382 100644 (file)
@@ -61,6 +61,7 @@
 #include <vnet/ip/ip4_forward.h>
 #include <vnet/interface_output.h>
 #include <vnet/classify/vnet_classify.h>
+#include <vnet/ip/reass/ip4_full_reass.h>
 
 /** @brief IPv4 lookup node.
     @node ip4-lookup
@@ -1880,7 +1881,7 @@ VLIB_REGISTER_NODE (ip4_local_node) =
     [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
     [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
-    [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly",
+    [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
   },
 };
 
index 3b3edf9..0e8d22e 100644 (file)
@@ -399,7 +399,6 @@ VLIB_REGISTER_NODE (ip4_input_node) = {
     [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
     [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
     [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-    [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-full-reassembly",
   },
 
   .format_buffer = format_ip4_header,
index 53948d6..57aef0b 100644 (file)
@@ -52,7 +52,6 @@ typedef enum
   IP4_INPUT_NEXT_LOOKUP,
   IP4_INPUT_NEXT_LOOKUP_MULTICAST,
   IP4_INPUT_NEXT_ICMP_ERROR,
-  IP4_INPUT_NEXT_REASSEMBLY,
   IP4_INPUT_N_NEXT,
 } ip4_input_next_t;
 
index ce165e0..b876b6f 100644 (file)
@@ -1677,7 +1677,7 @@ VLIB_REGISTER_NODE (ip6_local_node) =
     [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
     [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
-    [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly",
+    [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-local-full-reassembly",
   },
 };
 
index b1b7ff3..3ff3a6c 100644 (file)
@@ -1875,6 +1875,30 @@ void
   REPLY_MACRO (VL_API_IP_REASSEMBLY_ENABLE_DISABLE_REPLY);
 }
 
+void
+vl_api_ip_local_reass_enable_disable_t_handler (
+  vl_api_ip_local_reass_enable_disable_t *mp)
+{
+  vl_api_ip_local_reass_enable_disable_reply_t *rmp;
+  int rv = 0;
+
+  ip4_local_full_reass_enable_disable (mp->enable_ip4);
+  ip6_local_full_reass_enable_disable (mp->enable_ip6);
+
+  REPLY_MACRO (VL_API_IP_LOCAL_REASS_ENABLE_DISABLE_REPLY);
+}
+
+void
+vl_api_ip_local_reass_get_t_handler (vl_api_ip_local_reass_get_t *mp)
+{
+  vl_api_ip_local_reass_get_reply_t *rmp;
+  int rv = 0;
+  REPLY_MACRO2 (VL_API_IP_LOCAL_REASS_GET, {
+    rmp->ip4_is_enabled = ip4_local_full_reass_enabled ();
+    rmp->ip6_is_enabled = ip6_local_full_reass_enabled ();
+  });
+}
+
 static walk_rc_t
 send_ip_punt_redirect_details (u32 rx_sw_if_index,
                               const ip_punt_redirect_rx_t * ipr, void *arg)
index f87b47f..7c99486 100644 (file)
@@ -1014,6 +1014,24 @@ api_ip_reassembly_enable_disable (vat_main_t *vat)
   return -1;
 }
 
+static int
+api_ip_local_reass_enable_disable (vat_main_t *vat)
+{
+  return -1;
+}
+
+static int
+api_ip_local_reass_get (vat_main_t *vat)
+{
+  return -1;
+}
+
+static void
+vl_api_ip_local_reass_get_reply_t_handler (
+  vl_api_ip_local_reass_get_reply_t *mp)
+{
+}
+
 static void
 vl_api_ip_reassembly_get_reply_t_handler (vl_api_ip_reassembly_get_reply_t *mp)
 {
index 79f4673..2201172 100644 (file)
@@ -183,11 +183,15 @@ typedef struct
 
   /** Worker handoff */
   u32 fq_index;
+  u32 fq_local_index;
   u32 fq_feature_index;
   u32 fq_custom_index;
 
   // reference count for enabling/disabling feature - per interface
   u32 *feature_use_refcount_per_intf;
+
+  // whether local fragmented packets are reassembled or not
+  int is_local_reass_enabled;
 } ip4_full_reass_main_t;
 
 extern ip4_full_reass_main_t ip4_full_reass_main;
@@ -219,6 +223,7 @@ typedef enum
   RANGE_OVERLAP,
   FINALIZE,
   HANDOFF,
+  PASSTHROUGH,
 } ip4_full_reass_trace_operation_e;
 
 typedef struct
@@ -329,6 +334,9 @@ format_ip4_full_reass_trace (u8 * s, va_list * args)
        format (s, "handoff from thread #%u to thread #%u", t->thread_id,
                t->thread_id_to);
       break;
+    case PASSTHROUGH:
+      s = format (s, "passthrough - not a fragment");
+      break;
     }
   return s;
 }
@@ -1090,8 +1098,9 @@ ip4_full_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node,
 }
 
 always_inline uword
-ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
-                      vlib_frame_t * frame, ip4_full_reass_node_type_t type)
+ip4_full_reass_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                      vlib_frame_t *frame, ip4_full_reass_node_type_t type,
+                      bool is_local)
 {
   u32 *from = vlib_frame_vector_args (frame);
   u32 n_left_from, n_left_to_next, *to_next, next_index;
@@ -1127,8 +1136,17 @@ ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                {
                  next0 = vnet_buffer (b0)->ip.reass.next_index;
                }
+             ip4_full_reass_add_trace (vm, node, NULL, bi0, PASSTHROUGH, 0,
+                                       ~0);
+             goto packet_enqueue;
+           }
+
+         if (is_local && !rm->is_local_reass_enabled)
+           {
+             next0 = IP4_FULL_REASS_NEXT_DROP;
              goto packet_enqueue;
            }
+
          const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0);
          const u32 fragment_length =
            clib_net_to_host_u16 (ip0->length) - ip4_header_bytes (ip0);
@@ -1269,7 +1287,7 @@ VLIB_NODE_FN (ip4_full_reass_node) (vlib_main_t * vm,
                                    vlib_node_runtime_t * node,
                                    vlib_frame_t * frame)
 {
-  return ip4_full_reass_inline (vm, node, frame, NORMAL);
+  return ip4_full_reass_inline (vm, node, frame, NORMAL, false /* is_local */);
 }
 
 VLIB_REGISTER_NODE (ip4_full_reass_node) = {
@@ -1288,11 +1306,34 @@ VLIB_REGISTER_NODE (ip4_full_reass_node) = {
         },
 };
 
+VLIB_NODE_FN (ip4_local_full_reass_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return ip4_full_reass_inline (vm, node, frame, NORMAL, true /* is_local */);
+}
+
+VLIB_REGISTER_NODE (ip4_local_full_reass_node) = {
+    .name = "ip4-local-full-reassembly",
+    .vector_size = sizeof (u32),
+    .format_trace = format_ip4_full_reass_trace,
+    .n_errors = ARRAY_LEN (ip4_full_reass_error_strings),
+    .error_strings = ip4_full_reass_error_strings,
+    .n_next_nodes = IP4_FULL_REASS_N_NEXT,
+    .next_nodes =
+        {
+                [IP4_FULL_REASS_NEXT_INPUT] = "ip4-input",
+                [IP4_FULL_REASS_NEXT_DROP] = "ip4-drop",
+                [IP4_FULL_REASS_NEXT_HANDOFF] = "ip4-local-full-reassembly-handoff",
+
+        },
+};
+
 VLIB_NODE_FN (ip4_full_reass_node_feature) (vlib_main_t * vm,
                                            vlib_node_runtime_t * node,
                                            vlib_frame_t * frame)
 {
-  return ip4_full_reass_inline (vm, node, frame, FEATURE);
+  return ip4_full_reass_inline (vm, node, frame, FEATURE,
+                               false /* is_local */);
 }
 
 VLIB_REGISTER_NODE (ip4_full_reass_node_feature) = {
@@ -1322,7 +1363,7 @@ VLIB_NODE_FN (ip4_full_reass_node_custom) (vlib_main_t * vm,
                                           vlib_node_runtime_t * node,
                                           vlib_frame_t * frame)
 {
-  return ip4_full_reass_inline (vm, node, frame, CUSTOM);
+  return ip4_full_reass_inline (vm, node, frame, CUSTOM, false /* is_local */);
 }
 
 VLIB_REGISTER_NODE (ip4_full_reass_node_custom) = {
@@ -1495,12 +1536,16 @@ ip4_full_reass_init_function (vlib_main_t * vm)
   rm->ip4_drop_idx = node->index;
 
   rm->fq_index = vlib_frame_queue_main_init (ip4_full_reass_node.index, 0);
+  rm->fq_local_index =
+    vlib_frame_queue_main_init (ip4_local_full_reass_node.index, 0);
   rm->fq_feature_index =
     vlib_frame_queue_main_init (ip4_full_reass_node_feature.index, 0);
   rm->fq_custom_index =
     vlib_frame_queue_main_init (ip4_full_reass_node_custom.index, 0);
 
   rm->feature_use_refcount_per_intf = NULL;
+  rm->is_local_reass_enabled = 1;
+
   return error;
 }
 
@@ -1745,10 +1790,10 @@ format_ip4_full_reass_handoff_trace (u8 * s, va_list * args)
 }
 
 always_inline uword
-ip4_full_reass_handoff_node_inline (vlib_main_t * vm,
-                                   vlib_node_runtime_t * node,
-                                   vlib_frame_t * frame,
-                                   ip4_full_reass_node_type_t type)
+ip4_full_reass_handoff_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                                   vlib_frame_t *frame,
+                                   ip4_full_reass_node_type_t type,
+                                   bool is_local)
 {
   ip4_full_reass_main_t *rm = &ip4_full_reass_main;
 
@@ -1767,7 +1812,14 @@ ip4_full_reass_handoff_node_inline (vlib_main_t * vm,
   switch (type)
     {
     case NORMAL:
-      fq_index = rm->fq_index;
+      if (is_local)
+       {
+         fq_index = rm->fq_local_index;
+       }
+      else
+       {
+         fq_index = rm->fq_index;
+       }
       break;
     case FEATURE:
       fq_index = rm->fq_feature_index;
@@ -1777,7 +1829,6 @@ ip4_full_reass_handoff_node_inline (vlib_main_t * vm,
       break;
     default:
       clib_warning ("Unexpected `type' (%d)!", type);
-      ASSERT (0);
     }
 
   while (n_left_from > 0)
@@ -1811,7 +1862,8 @@ VLIB_NODE_FN (ip4_full_reass_handoff_node) (vlib_main_t * vm,
                                            vlib_node_runtime_t * node,
                                            vlib_frame_t * frame)
 {
-  return ip4_full_reass_handoff_node_inline (vm, node, frame, NORMAL);
+  return ip4_full_reass_handoff_node_inline (vm, node, frame, NORMAL,
+                                            false /* is_local */);
 }
 
 
@@ -1829,13 +1881,34 @@ VLIB_REGISTER_NODE (ip4_full_reass_handoff_node) = {
   },
 };
 
+VLIB_NODE_FN (ip4_local_full_reass_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return ip4_full_reass_handoff_node_inline (vm, node, frame, NORMAL,
+                                            true /* is_local */);
+}
+
+VLIB_REGISTER_NODE (ip4_local_full_reass_handoff_node) = {
+  .name = "ip4-local-full-reassembly-handoff",
+  .vector_size = sizeof (u32),
+  .n_errors = ARRAY_LEN(ip4_full_reass_handoff_error_strings),
+  .error_strings = ip4_full_reass_handoff_error_strings,
+  .format_trace = format_ip4_full_reass_handoff_trace,
+
+  .n_next_nodes = 1,
+
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
 
 VLIB_NODE_FN (ip4_full_reass_feature_handoff_node) (vlib_main_t * vm,
                                                    vlib_node_runtime_t *
                                                    node,
                                                    vlib_frame_t * frame)
 {
-  return ip4_full_reass_handoff_node_inline (vm, node, frame, FEATURE);
+  return ip4_full_reass_handoff_node_inline (vm, node, frame, FEATURE,
+                                            false /* is_local */);
 }
 
 
@@ -1858,7 +1931,8 @@ VLIB_NODE_FN (ip4_full_reass_custom_handoff_node) (vlib_main_t * vm,
                                                    node,
                                                    vlib_frame_t * frame)
 {
-  return ip4_full_reass_handoff_node_inline (vm, node, frame, CUSTOM);
+  return ip4_full_reass_handoff_node_inline (vm, node, frame, CUSTOM,
+                                            false /* is_local */);
 }
 
 
@@ -1903,6 +1977,26 @@ ip4_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable)
     }
   return -1;
 }
+
+void
+ip4_local_full_reass_enable_disable (int enable)
+{
+  if (enable)
+    {
+      ip4_full_reass_main.is_local_reass_enabled = 1;
+    }
+  else
+    {
+      ip4_full_reass_main.is_local_reass_enabled = 0;
+    }
+}
+
+int
+ip4_local_full_reass_enabled ()
+{
+  return ip4_full_reass_main.is_local_reass_enabled;
+}
+
 #endif
 
 /*
index 000c80c..5df8107 100644 (file)
@@ -47,6 +47,9 @@ int ip4_full_reass_enable_disable_with_refcnt (u32 sw_if_index,
                                               int is_enable);
 
 uword ip4_full_reass_custom_register_next_node (uword node_index);
+
+void ip4_local_full_reass_enable_disable (int enable);
+int ip4_local_full_reass_enabled ();
 #endif /* __included_ip4_full_reass_h__ */
 
 /*
index 12cacfc..1bcb6bd 100644 (file)
@@ -164,10 +164,14 @@ typedef struct
 
   /** Worker handoff */
   u32 fq_index;
+  u32 fq_local_index;
   u32 fq_feature_index;
 
   // reference count for enabling/disabling feature - per interface
   u32 *feature_use_refcount_per_intf;
+
+  // whether local fragmented packets are reassembled or not
+  int is_local_reass_enabled;
 } ip6_full_reass_main_t;
 
 extern ip6_full_reass_main_t ip6_full_reass_main;
@@ -194,6 +198,7 @@ typedef enum
   ICMP_ERROR_FL_NOT_MULT_8,
   FINALIZE,
   HANDOFF,
+  PASSTHROUGH,
 } ip6_full_reass_trace_operation_e;
 
 typedef struct
@@ -306,6 +311,9 @@ format_ip6_full_reass_trace (u8 * s, va_list * args)
        format (s, "handoff from thread #%u to thread #%u", t->thread_id,
                t->thread_id_to);
       break;
+    case PASSTHROUGH:
+      s = format (s, "passthrough - not a fragment");
+      break;
     }
   return s;
 }
@@ -1084,10 +1092,9 @@ ip6_full_reass_verify_packet_size_lt_64k (vlib_main_t * vm,
 }
 
 always_inline uword
-ip6_full_reassembly_inline (vlib_main_t * vm,
-                           vlib_node_runtime_t * node,
-                           vlib_frame_t * frame, bool is_feature,
-                           bool is_custom_app)
+ip6_full_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                           vlib_frame_t *frame, bool is_feature,
+                           bool is_custom_app, bool is_local)
 {
   u32 *from = vlib_frame_vector_args (frame);
   u32 n_left_from, n_left_to_next, *to_next, next_index;
@@ -1121,6 +1128,13 @@ ip6_full_reassembly_inline (vlib_main_t * vm,
              hdr_chain.eh[res].protocol != IP_PROTOCOL_IPV6_FRAGMENTATION)
            {
              // this is a mangled packet - no fragmentation
+             next0 = IP6_FULL_REASSEMBLY_NEXT_DROP;
+             ip6_full_reass_add_trace (vm, node, NULL, bi0, NULL, PASSTHROUGH,
+                                       ~0);
+             goto skip_reass;
+           }
+         if (is_local && !rm->is_local_reass_enabled)
+           {
              next0 = IP6_FULL_REASSEMBLY_NEXT_DROP;
              goto skip_reass;
            }
@@ -1303,8 +1317,9 @@ VLIB_NODE_FN (ip6_full_reass_node) (vlib_main_t * vm,
                                    vlib_node_runtime_t * node,
                                    vlib_frame_t * frame)
 {
-  return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */ ,
-                                    false /* is_custom_app */ );
+  return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */,
+                                    false /* is_custom_app */,
+                                    false /* is_local */);
 }
 
 VLIB_REGISTER_NODE (ip6_full_reass_node) = {
@@ -1323,12 +1338,37 @@ VLIB_REGISTER_NODE (ip6_full_reass_node) = {
         },
 };
 
+VLIB_NODE_FN (ip6_local_full_reass_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */,
+                                    false /* is_custom_app */,
+                                    true /* is_local */);
+}
+
+VLIB_REGISTER_NODE (ip6_local_full_reass_node) = {
+    .name = "ip6-local-full-reassembly",
+    .vector_size = sizeof (u32),
+    .format_trace = format_ip6_full_reass_trace,
+    .n_errors = ARRAY_LEN (ip6_full_reassembly_error_strings),
+    .error_strings = ip6_full_reassembly_error_strings,
+    .n_next_nodes = IP6_FULL_REASSEMBLY_N_NEXT,
+    .next_nodes =
+        {
+                [IP6_FULL_REASSEMBLY_NEXT_INPUT] = "ip6-input",
+                [IP6_FULL_REASSEMBLY_NEXT_DROP] = "ip6-drop",
+                [IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR] = "ip6-icmp-error",
+                [IP6_FULL_REASSEMBLY_NEXT_HANDOFF] = "ip6-local-full-reassembly-handoff",
+        },
+};
+
 VLIB_NODE_FN (ip6_full_reass_node_feature) (vlib_main_t * vm,
                                            vlib_node_runtime_t * node,
                                            vlib_frame_t * frame)
 {
-  return ip6_full_reassembly_inline (vm, node, frame, true /* is_feature */ ,
-                                    false /* is_custom_app */ );
+  return ip6_full_reassembly_inline (vm, node, frame, true /* is_feature */,
+                                    false /* is_custom_app */,
+                                    false /* is_local */);
 }
 
 VLIB_REGISTER_NODE (ip6_full_reass_node_feature) = {
@@ -1500,9 +1540,12 @@ ip6_full_reass_init_function (vlib_main_t * vm)
   if ((error = vlib_call_init_function (vm, ip_main_init)))
     return error;
   ip6_register_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION,
-                        ip6_full_reass_node.index);
+                        ip6_local_full_reass_node.index);
+  rm->is_local_reass_enabled = 1;
 
   rm->fq_index = vlib_frame_queue_main_init (ip6_full_reass_node.index, 0);
+  rm->fq_local_index =
+    vlib_frame_queue_main_init (ip6_local_full_reass_node.index, 0);
   rm->fq_feature_index =
     vlib_frame_queue_main_init (ip6_full_reass_node_feature.index, 0);
 
@@ -1777,9 +1820,9 @@ format_ip6_full_reassembly_handoff_trace (u8 * s, va_list * args)
 }
 
 always_inline uword
-ip6_full_reassembly_handoff_inline (vlib_main_t * vm,
-                                   vlib_node_runtime_t * node,
-                                   vlib_frame_t * frame, bool is_feature)
+ip6_full_reassembly_handoff_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                                   vlib_frame_t *frame, bool is_feature,
+                                   bool is_local)
 {
   ip6_full_reass_main_t *rm = &ip6_full_reass_main;
 
@@ -1795,7 +1838,21 @@ ip6_full_reassembly_handoff_inline (vlib_main_t * vm,
   b = bufs;
   ti = thread_indices;
 
-  fq_index = (is_feature) ? rm->fq_feature_index : rm->fq_index;
+  if (is_feature)
+    {
+      fq_index = rm->fq_feature_index;
+    }
+  else
+    {
+      if (is_local)
+       {
+         fq_index = rm->fq_local_index;
+       }
+      else
+       {
+         fq_index = rm->fq_index;
+       }
+    }
 
   while (n_left_from > 0)
     {
@@ -1828,8 +1885,8 @@ VLIB_NODE_FN (ip6_full_reassembly_handoff_node) (vlib_main_t * vm,
                                                 vlib_node_runtime_t * node,
                                                 vlib_frame_t * frame)
 {
-  return ip6_full_reassembly_handoff_inline (vm, node, frame,
-                                            false /* is_feature */ );
+  return ip6_full_reassembly_handoff_inline (
+    vm, node, frame, false /* is_feature */, false /* is_local */);
 }
 
 VLIB_REGISTER_NODE (ip6_full_reassembly_handoff_node) = {
@@ -1846,11 +1903,32 @@ VLIB_REGISTER_NODE (ip6_full_reassembly_handoff_node) = {
   },
 };
 
+VLIB_NODE_FN (ip6_local_full_reassembly_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return ip6_full_reassembly_handoff_inline (
+    vm, node, frame, false /* is_feature */, true /* is_feature */);
+}
+
+VLIB_REGISTER_NODE (ip6_local_full_reassembly_handoff_node) = {
+  .name = "ip6-local-full-reassembly-handoff",
+  .vector_size = sizeof (u32),
+  .n_errors = ARRAY_LEN(ip6_full_reassembly_handoff_error_strings),
+  .error_strings = ip6_full_reassembly_handoff_error_strings,
+  .format_trace = format_ip6_full_reassembly_handoff_trace,
+
+  .n_next_nodes = 1,
+
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
 
 VLIB_NODE_FN (ip6_full_reassembly_feature_handoff_node) (vlib_main_t * vm,
                                vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
-  return ip6_full_reassembly_handoff_inline (vm, node, frame, true /* is_feature */ );
+  return ip6_full_reassembly_handoff_inline (
+    vm, node, frame, true /* is_feature */, false /* is_local */);
 }
 
 
@@ -1895,6 +1973,35 @@ ip6_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable)
     }
   return -1;
 }
+
+void
+ip6_local_full_reass_enable_disable (int enable)
+{
+  if (enable)
+    {
+      if (!ip6_full_reass_main.is_local_reass_enabled)
+       {
+         ip6_full_reass_main.is_local_reass_enabled = 1;
+         ip6_register_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION,
+                                ip6_local_full_reass_node.index);
+       }
+    }
+  else
+    {
+      if (ip6_full_reass_main.is_local_reass_enabled)
+       {
+         ip6_full_reass_main.is_local_reass_enabled = 0;
+         ip6_unregister_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION);
+       }
+    }
+}
+
+int
+ip6_local_full_reass_enabled ()
+{
+  return ip6_full_reass_main.is_local_reass_enabled;
+}
+
 #endif
 
 /*
index 546075b..f66cb67 100644 (file)
@@ -46,6 +46,8 @@ vnet_api_error_t ip6_full_reass_enable_disable (u32 sw_if_index,
 int ip6_full_reass_enable_disable_with_refcnt (u32 sw_if_index,
                                               int is_enable);
 
+void ip6_local_full_reass_enable_disable (int enable);
+int ip6_local_full_reass_enabled ();
 #endif /* __included_ip6_full_reass_h */
 
 /*
index 5616e9c..3dbf007 100644 (file)
@@ -271,8 +271,8 @@ checkstyle-diff: $(PIP_INSTALL_DONE)
        @bash -c "source $(VENV_PATH)/bin/activate &&\
                  $(PYTHON_INTERP) -m pip install pycodestyle"
        @bash -c "source $(VENV_PATH)/bin/activate &&\
-               cd $(WS_ROOT) && git diff --name-only --no-color --relative HEAD~1 ':!*.patch' | grep '.py$$' | xargs -n 1 -I XXX \
-               pycodestyle --show-source --ignore=W504,E126,E241,E226,E305,E704,E741,E722 -v XXX ||\
+               cd $(WS_ROOT) && git diff --name-only --no-color --relative HEAD~1 ':!*.patch' | grep '.py$$' | xargs -n 1 \
+               pycodestyle --show-source --ignore=W504,E126,E241,E226,E305,E704,E741,E722 -v ||\
                (echo \"*********************************************************************\" &&\
                 echo \"* Test framework PEP8 compliance check FAILED (checked changed files)\" &&\
                 echo \"*********************************************************************\" &&\
index faec5f4..2291c93 100644 (file)
@@ -8,10 +8,11 @@ from framework import VppTestCase, VppTestRunner
 import scapy.compat
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, GRE
-from scapy.layers.inet import IP, UDP, ICMP
+from scapy.layers.inet import IP, UDP, ICMP, icmptypes
 from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\
     ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment,\
-    IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, PadN, ICMPv6EchoRequest
+    IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, PadN, ICMPv6EchoRequest,\
+    ICMPv6EchoReply
 from framework import VppTestCase, VppTestRunner
 from util import ppp, ppc, fragment_rfc791, fragment_rfc8200
 from vpp_gre_interface import VppGreInterface
@@ -28,7 +29,7 @@ class TestIPv4Reassembly(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv4Reassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces([0, 1])
         cls.src_if = cls.pg0
@@ -48,11 +49,11 @@ class TestIPv4Reassembly(VppTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        super(TestIPv4Reassembly, cls).tearDownClass()
+        super().tearDownClass()
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv4Reassembly, self).setUp()
+        super().setUp()
         self.vapi.ip_reassembly_enable_disable(
             sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
@@ -64,7 +65,9 @@ class TestIPv4Reassembly(VppTestCase):
                                     expire_walk_interval_ms=10000)
 
     def tearDown(self):
-        super(TestIPv4Reassembly, self).tearDown()
+        self.vapi.ip_reassembly_enable_disable(
+            sw_if_index=self.src_if.sw_if_index, enable_ip4=False)
+        super().tearDown()
 
     def show_commands_at_teardown(self):
         self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
@@ -511,13 +514,31 @@ Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737'''
         self.verify_capture(packets, dropped_packet_indexes)
         self.src_if.assert_nothing_captured()
 
+    def test_local_enable_disable(self):
+        """ local reassembly enabled/disable """
+        self.vapi.ip_reassembly_enable_disable(
+            sw_if_index=self.src_if.sw_if_index, enable_ip4=False)
+        self.vapi.ip_local_reass_enable_disable(enable_ip4=True)
+        p = (Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) /
+             IP(src=self.src_if.remote_ip4, dst=self.src_if.local_ip4) /
+             ICMP(id=1234, type='echo-request') /
+             Raw('x' * 1000))
+        frags = fragment_rfc791(p, 400)
+        r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0]
+        self.assertEqual(1234, r[ICMP].id)
+        self.assertEqual(icmptypes[r[ICMP].type], 'echo-reply')
+        self.vapi.ip_local_reass_enable_disable()
+
+        self.send_and_assert_no_replies(self.src_if, frags)
+        self.vapi.ip_local_reass_enable_disable(enable_ip4=True)
+
 
 class TestIPv4SVReassembly(VppTestCase):
     """ IPv4 Shallow Virtual Reassembly """
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv4SVReassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces([0, 1])
         cls.src_if = cls.pg0
@@ -531,7 +552,7 @@ class TestIPv4SVReassembly(VppTestCase):
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv4SVReassembly, self).setUp()
+        super().setUp()
         self.vapi.ip_reassembly_enable_disable(
             sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
             type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
@@ -548,7 +569,7 @@ class TestIPv4SVReassembly(VppTestCase):
             expire_walk_interval_ms=10000)
 
     def tearDown(self):
-        super(TestIPv4SVReassembly, self).tearDown()
+        super().tearDown()
         self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
         self.logger.debug(self.vapi.ppcli("show buffers"))
 
@@ -791,7 +812,7 @@ class TestIPv4MWReassembly(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv4MWReassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
         cls.src_if = cls.pg0
@@ -815,11 +836,11 @@ class TestIPv4MWReassembly(VppTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        super(TestIPv4MWReassembly, cls).tearDownClass()
+        super().tearDownClass()
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv4MWReassembly, self).setUp()
+        super().setUp()
         for intf in self.send_ifs:
             self.vapi.ip_reassembly_enable_disable(
                 sw_if_index=intf.sw_if_index, enable_ip4=True)
@@ -832,7 +853,10 @@ class TestIPv4MWReassembly(VppTestCase):
                                     expire_walk_interval_ms=10000)
 
     def tearDown(self):
-        super(TestIPv4MWReassembly, self).tearDown()
+        for intf in self.send_ifs:
+            self.vapi.ip_reassembly_enable_disable(
+                sw_if_index=intf.sw_if_index, enable_ip4=False)
+        super().tearDown()
 
     def show_commands_at_teardown(self):
         self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
@@ -968,7 +992,7 @@ class TestIPv6Reassembly(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv6Reassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces([0, 1])
         cls.src_if = cls.pg0
@@ -988,11 +1012,11 @@ class TestIPv6Reassembly(VppTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        super(TestIPv6Reassembly, cls).tearDownClass()
+        super().tearDownClass()
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv6Reassembly, self).setUp()
+        super().setUp()
         self.vapi.ip_reassembly_enable_disable(
             sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
@@ -1006,7 +1030,9 @@ class TestIPv6Reassembly(VppTestCase):
         self.logger.debug(self.vapi.ppcli("show buffers"))
 
     def tearDown(self):
-        super(TestIPv6Reassembly, self).tearDown()
+        self.vapi.ip_reassembly_enable_disable(
+            sw_if_index=self.src_if.sw_if_index, enable_ip6=False)
+        super().tearDown()
 
     def show_commands_at_teardown(self):
         self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
@@ -1505,6 +1531,22 @@ class TestIPv6Reassembly(VppTestCase):
         rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
         self.assertNotIn(IPv6ExtHdrFragment, rx)
 
+    def test_local_enable_disable(self):
+        """ local reassembly enabled/disable """
+        self.vapi.ip_reassembly_enable_disable(
+            sw_if_index=self.src_if.sw_if_index, enable_ip6=False)
+        self.vapi.ip_local_reass_enable_disable(enable_ip6=True)
+        pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
+               IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) /
+               ICMPv6EchoRequest(id=1234)/Raw('X' * 1600))
+        frags = fragment_rfc8200(pkt, 1, 400)
+        r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0]
+        self.assertEqual(1234, r[ICMPv6EchoReply].id)
+        self.vapi.ip_local_reass_enable_disable()
+
+        self.send_and_assert_no_replies(self.src_if, frags)
+        self.vapi.ip_local_reass_enable_disable(enable_ip6=True)
+
 
 class TestIPv6MWReassembly(VppTestCase):
     """ IPv6 Reassembly (multiple workers) """
@@ -1512,7 +1554,7 @@ class TestIPv6MWReassembly(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv6MWReassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
         cls.src_if = cls.pg0
@@ -1536,11 +1578,11 @@ class TestIPv6MWReassembly(VppTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        super(TestIPv6MWReassembly, cls).tearDownClass()
+        super().tearDownClass()
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv6MWReassembly, self).setUp()
+        super().setUp()
         for intf in self.send_ifs:
             self.vapi.ip_reassembly_enable_disable(
                 sw_if_index=intf.sw_if_index, enable_ip6=True)
@@ -1553,7 +1595,10 @@ class TestIPv6MWReassembly(VppTestCase):
                                     expire_walk_interval_ms=1000, is_ip6=1)
 
     def tearDown(self):
-        super(TestIPv6MWReassembly, self).tearDown()
+        for intf in self.send_ifs:
+            self.vapi.ip_reassembly_enable_disable(
+                sw_if_index=intf.sw_if_index, enable_ip6=False)
+        super().tearDown()
 
     def show_commands_at_teardown(self):
         self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
@@ -1689,7 +1734,7 @@ class TestIPv6SVReassembly(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv6SVReassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces([0, 1])
         cls.src_if = cls.pg0
@@ -1703,7 +1748,7 @@ class TestIPv6SVReassembly(VppTestCase):
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv6SVReassembly, self).setUp()
+        super().setUp()
         self.vapi.ip_reassembly_enable_disable(
             sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
             type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
@@ -1720,7 +1765,7 @@ class TestIPv6SVReassembly(VppTestCase):
             expire_walk_interval_ms=10000, is_ip6=1)
 
     def tearDown(self):
-        super(TestIPv6SVReassembly, self).tearDown()
+        super().tearDown()
         self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
         self.logger.debug(self.vapi.ppcli("show buffers"))
 
@@ -1941,7 +1986,7 @@ class TestIPv4ReassemblyLocalNode(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces([0])
         cls.src_dst_if = cls.pg0
@@ -1958,11 +2003,11 @@ class TestIPv4ReassemblyLocalNode(VppTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
+        super().tearDownClass()
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestIPv4ReassemblyLocalNode, self).setUp()
+        super().setUp()
         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
                                     max_reassembly_length=1000,
                                     expire_walk_interval_ms=10)
@@ -1972,7 +2017,7 @@ class TestIPv4ReassemblyLocalNode(VppTestCase):
                                     expire_walk_interval_ms=10000)
 
     def tearDown(self):
-        super(TestIPv4ReassemblyLocalNode, self).tearDown()
+        super().tearDown()
 
     def show_commands_at_teardown(self):
         self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
@@ -2068,7 +2113,7 @@ class TestFIFReassembly(VppTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestFIFReassembly, cls).setUpClass()
+        super().setUpClass()
 
         cls.create_pg_interfaces([0, 1])
         cls.src_if = cls.pg0
@@ -2085,11 +2130,11 @@ class TestFIFReassembly(VppTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        super(TestFIFReassembly, cls).tearDownClass()
+        super().tearDownClass()
 
     def setUp(self):
         """ Test setup - force timeout on existing reassemblies """
-        super(TestFIFReassembly, self).setUp()
+        super().setUp()
         self.vapi.ip_reassembly_enable_disable(
             sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
             enable_ip6=True)
@@ -2111,7 +2156,7 @@ class TestFIFReassembly(VppTestCase):
                                     expire_walk_interval_ms=10000, is_ip6=1)
 
     def tearDown(self):
-        super(TestFIFReassembly, self).tearDown()
+        super().tearDown()
 
     def show_commands_at_teardown(self):
         self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))