VPP-226 - adding UDP TCP to port-range 98/2198/8
authorKeith Burns (alagalah) <alagalah@gmail.com>
Tue, 2 Aug 2016 18:57:37 +0000 (11:57 -0700)
committerDave Barach <openvpp@barachs.net>
Wed, 3 Aug 2016 22:02:27 +0000 (22:02 +0000)
Change-Id: I5f4261279dcdbb03e182b18d05602407c0e55f89
Signed-off-by: Keith Burns (alagalah) <alagalah@gmail.com>
vnet/vnet/ip/ip4_source_and_port_range_check.c
vnet/vnet/ip/ip_source_and_port_range_check.h
vpp-api-test/vat/api_format.c
vpp/vpp-api/api.c
vpp/vpp-api/custom_dump.c
vpp/vpp-api/vpe.api

index 9dfb522..c36678c 100644 (file)
@@ -4,7 +4,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * limitations under the License.
  */
 #include <vnet/ip/ip.h>
+#include <vnet/ip/ip_source_and_port_range_check.h>
 
-typedef struct {
-  u32 ranges_per_adjacency;
-  u32 special_adjacency_format_function_index;
-
-  /* convenience */
-  vlib_main_t *vlib_main;
-  vnet_main_t *vnet_main;
-} source_range_check_main_t;
-
-source_range_check_main_t source_range_check_main;
 
 vlib_node_registration_t ip4_source_port_and_range_check;
 
-typedef struct {
-  union {
-    u16x8 as_u16x8;
-    u16 as_u16[8];
-  };
-} u16x8vec_t;
-
-typedef struct {
-  u16x8vec_t low;
-  u16x8vec_t hi;
-} port_range_t;
-
-#define foreach_ip4_source_and_port_range_check_error          \
-_(CHECK_FAIL, "ip4 source and port range check bad packets")   \
-_(CHECK_OK, "ip4 source and port range check good packets")
+#define foreach_ip4_source_and_port_range_check_error                  \
+  _(CHECK_FAIL, "ip4 source and port range check bad packets") \
+  _(CHECK_OK, "ip4 source and port range check good packets")
 
 typedef enum {
 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
@@ -62,6 +41,7 @@ typedef struct {
   u32 is_tcp;
   ip4_address_t src_addr;
   u16 dst_port;
+  u32 fib_index;
 } ip4_source_and_port_range_check_trace_t;
 
 static u8 * format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
@@ -74,10 +54,10 @@ static u8 * format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
   if (t->bypass)
     s = format (s, "PASS (bypass case)");
   else
-    s = format (s, "src ip %U %s dst port %d: %s",
-        format_ip4_address, &t->src_addr, t->is_tcp ? "TCP" : "UDP",
-        (u32) t->dst_port,
-        (t->pass == 1) ? "PASS" : "FAIL");
+    s = format (s, "fib %d src ip %U %s dst port %d: %s",
+                t->fib_index, format_ip4_address, &t->src_addr, t->is_tcp ? "TCP" : "UDP",
+                (u32) t->dst_port,
+                (t->pass == 1) ? "PASS" : "FAIL");
   return s;
 }
 
@@ -86,15 +66,12 @@ typedef enum {
   IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
 } ip4_source_and_port_range_check_next_t;
 
-typedef union {
-  u32 fib_index;
-} ip4_source_and_port_range_check_config_t;
 
 static inline u32 check_adj_port_range_x1 (ip_adjacency_t * adj,
                                            u16 dst_port,
                                            u32 next)
 {
-  port_range_t *range;
+  protocol_port_range_t *range;
   u16x8vec_t key;
   u16x8vec_t diff1;
   u16x8vec_t diff2;
@@ -107,14 +84,14 @@ static inline u32 check_adj_port_range_x1 (ip_adjacency_t * adj,
     return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
 
   rwh = (u8 *)(&adj->rewrite_header);
-  range = (port_range_t *)rwh;
+  range = (protocol_port_range_t *)rwh;
 
   /* Make the obvious screw-case work. A variant also works w/ no MMX */
   if (PREDICT_FALSE(dst_port == 65535))
     {
       int j;
 
-      for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(port_range_t); i++)
+      for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(protocol_port_range_t); i++)
         {
           for (j = 0; j < 8; j++)
             if (range->low.as_u16x8[j] == 65535)
@@ -126,7 +103,7 @@ static inline u32 check_adj_port_range_x1 (ip_adjacency_t * adj,
 
   key.as_u16x8 = u16x8_splat (dst_port);
 
-  for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(port_range_t); i++)
+  for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(protocol_port_range_t); i++)
     {
       diff1.as_u16x8 = u16x8_sub_saturate (range->low.as_u16x8, key.as_u16x8);
       diff2.as_u16x8 = u16x8_sub_saturate (range->hi.as_u16x8, key.as_u16x8);
@@ -154,6 +131,7 @@ ip4_source_and_port_range_check_inline
   u32 next_index;
   vlib_node_runtime_t * error_node = node;
   u32 good_packets = 0;
+  int i;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -164,130 +142,166 @@ ip4_source_and_port_range_check_inline
       u32 n_left_to_next;
 
       vlib_get_next_frame (vm, node, next_index,
-               to_next, n_left_to_next);
+                           to_next, n_left_to_next);
+
 
       while (n_left_from >= 4 && n_left_to_next >= 2)
-    {
+        {
           vlib_buffer_t * b0, * b1;
-      ip4_header_t * ip0, * ip1;
-      ip4_fib_mtrie_t * mtrie0, * mtrie1;
-      ip4_fib_mtrie_leaf_t leaf0, leaf1;
-      ip4_source_and_port_range_check_config_t * c0, * c1;
-      ip_adjacency_t * adj0, * adj1;
-      u32 bi0, next0, adj_index0, pass0, save_next0;
-      u32 bi1, next1, adj_index1, pass1, save_next1;
+          ip4_header_t * ip0, * ip1;
+          ip4_fib_mtrie_t * mtrie0, * mtrie1;
+          ip4_fib_mtrie_leaf_t leaf0, leaf1;
+          ip_source_and_port_range_check_config_t * c0, * c1;
+          ip_adjacency_t * adj0 = 0, * adj1 = 0;
+          u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
+          u32 bi1, next1, adj_index1, pass1, save_next1, fib_index1;
           udp_header_t * udp0, * udp1;
 
-      /* Prefetch next iteration. */
-      {
-        vlib_buffer_t * p2, * p3;
+          /* Prefetch next iteration. */
+          {
+            vlib_buffer_t * p2, * p3;
+
+            p2 = vlib_get_buffer (vm, from[2]);
+            p3 = vlib_get_buffer (vm, from[3]);
 
-        p2 = vlib_get_buffer (vm, from[2]);
-        p3 = vlib_get_buffer (vm, from[3]);
+            vlib_prefetch_buffer_header (p2, LOAD);
+            vlib_prefetch_buffer_header (p3, LOAD);
 
-        vlib_prefetch_buffer_header (p2, LOAD);
-        vlib_prefetch_buffer_header (p3, LOAD);
+            CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
+            CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
+          }
 
-        CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
-        CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
-      }
+          bi0 = to_next[0] = from[0];
+          bi1 = to_next[1] = from[1];
+          from += 2;
+          to_next += 2;
+          n_left_from -= 2;
+          n_left_to_next -= 2;
 
-      bi0 = to_next[0] = from[0];
-      bi1 = to_next[1] = from[1];
-      from += 2;
-      to_next += 2;
-      n_left_from -= 2;
-      n_left_to_next -= 2;
+          b0 = vlib_get_buffer (vm, bi0);
+          b1 = vlib_get_buffer (vm, bi1);
 
-      b0 = vlib_get_buffer (vm, bi0);
-      b1 = vlib_get_buffer (vm, bi1);
+          fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
+          fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (b1)->sw_if_index[VLIB_RX]);
 
-      ip0 = vlib_buffer_get_current (b0);
-      ip1 = vlib_buffer_get_current (b1);
+          ip0 = vlib_buffer_get_current (b0);
+          ip1 = vlib_buffer_get_current (b1);
 
-      c0 = vnet_get_config_data (&cm->config_main,
-                     &b0->current_config_index,
-                     &next0,
-                     sizeof (c0[0]));
-      c1 = vnet_get_config_data (&cm->config_main,
-                     &b1->current_config_index,
-                     &next1,
-                     sizeof (c1[0]));
+          c0 = vnet_get_config_data (&cm->config_main,
+                                     &b0->current_config_index,
+                                     &next0,
+                                     sizeof (c0[0]));
+          c1 = vnet_get_config_data (&cm->config_main,
+                                     &b1->current_config_index,
+                                     &next1,
+                                     sizeof (c1[0]));
 
           /* we can't use the default VRF here... */
-          ASSERT (c0->fib_index && c1->fib_index);
+          for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+            {
+              ASSERT(c0->fib_index[i] && c1->fib_index[i]);
+            }
+
+
+          if (ip0->protocol == IP_PROTOCOL_UDP)
+            fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
+          if (ip0->protocol == IP_PROTOCOL_TCP)
+            fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+
+          if (PREDICT_TRUE(fib_index0 != ~0))
+            {
 
-      mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
-      mtrie1 = &vec_elt_at_index (im->fibs, c1->fib_index)->mtrie;
+              mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
 
-      leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
+              leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 0);
-      leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
-                                             &ip1->src_address, 0);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 0);
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 1);
-      leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
-                                             &ip1->src_address, 1);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 1);
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 2);
-      leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
-                                             &ip1->src_address, 2);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 2);
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 3);
-      leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
-                                             &ip1->src_address, 3);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 3);
 
-      adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
-      adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
+              adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
 
-      ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, c0->fib_index,
-                               &ip0->src_address,
+              ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
+                                                           &ip0->src_address,
                                                            0 /* use dflt rt */));
+              adj0 = ip_get_adjacency (lm, adj_index0);
+            }
+
+          if (ip1->protocol == IP_PROTOCOL_UDP)
+            fib_index1 = c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
+          if (ip1->protocol == IP_PROTOCOL_TCP)
+            fib_index1 = c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+
+          if (PREDICT_TRUE(fib_index1 != ~0))
+            {
+
+              mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
+
+              leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
+
+              leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
+                                                 &ip1->src_address, 0);
+
+              leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
+                                                 &ip1->src_address, 1);
+
+              leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
+                                                 &ip1->src_address, 2);
+
+              leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
+                                                 &ip1->src_address, 3);
+
+              adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
 
-      ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, c1->fib_index,
-                               &ip1->src_address,
-                               0));
-      adj0 = ip_get_adjacency (lm, adj_index0);
-      adj1 = ip_get_adjacency (lm, adj_index1);
+              ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
+                                                           &ip1->src_address,
+                                                           0));
+              adj1 = ip_get_adjacency (lm, adj_index1);
+            }
 
           pass0 = 0;
+          pass0 |= adj0 == 0;
           pass0 |= ip4_address_is_multicast (&ip0->src_address);
           pass0 |= ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
           pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) &&
-        (ip0->protocol != IP_PROTOCOL_TCP);
+            (ip0->protocol != IP_PROTOCOL_TCP);
 
           pass1 = 0;
+          pass1 |= adj1 == 0;
           pass1 |= ip4_address_is_multicast (&ip1->src_address);
           pass1 |= ip1->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
           pass1 |= (ip1->protocol != IP_PROTOCOL_UDP) &&
-        (ip1->protocol != IP_PROTOCOL_TCP);
+            (ip1->protocol != IP_PROTOCOL_TCP);
 
-      save_next0 = next0;
-      udp0 = ip4_next_header (ip0);
-      save_next1 = next1;
-      udp1 = ip4_next_header (ip1);
+          save_next0 = next0;
+          udp0 = ip4_next_header (ip0);
+          save_next1 = next1;
+          udp1 = ip4_next_header (ip1);
 
           if (PREDICT_TRUE(pass0 == 0))
             {
-          good_packets ++;
+              good_packets ++;
               next0 = check_adj_port_range_x1
                 (adj0, clib_net_to_host_u16(udp0->dst_port), next0);
-          good_packets -= (save_next0 != next0);
+              good_packets -= (save_next0 != next0);
               b0->error = error_node->errors
                 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
             }
 
           if (PREDICT_TRUE(pass1 == 0))
             {
-          good_packets ++;
+              good_packets ++;
               next1 = check_adj_port_range_x1
                 (adj1, clib_net_to_host_u16(udp1->dst_port), next1);
-          good_packets -= (save_next1 != next1);
+              good_packets -= (save_next1 != next1);
               b1->error = error_node->errors
                 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
             }
@@ -295,103 +309,121 @@ ip4_source_and_port_range_check_inline
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
                             && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
             ip4_source_and_port_range_check_trace_t * t =
-          vlib_add_trace (vm, node, b0, sizeof (*t));
+              vlib_add_trace (vm, node, b0, sizeof (*t));
             t->pass = next0 == save_next0;
-        t->bypass = pass0;
-        t->src_addr.as_u32 = ip0->src_address.as_u32;
-        t->dst_port = (pass0 == 0) ?
-          clib_net_to_host_u16(udp0->dst_port) : 0;
-        t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
-            }
+            t->bypass = pass0;
+            t->fib_index = fib_index0;
+            t->src_addr.as_u32 = ip0->src_address.as_u32;
+            t->dst_port = (pass0 == 0) ?
+              clib_net_to_host_u16(udp0->dst_port) : 0;
+            t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
+          }
 
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
                             && (b1->flags & VLIB_BUFFER_IS_TRACED))) {
             ip4_source_and_port_range_check_trace_t * t =
-          vlib_add_trace (vm, node, b1, sizeof (*t));
+              vlib_add_trace (vm, node, b1, sizeof (*t));
             t->pass = next1 == save_next1;
-        t->bypass = pass1;
-        t->src_addr.as_u32 = ip1->src_address.as_u32;
-        t->dst_port = (pass1 == 0) ?
-          clib_net_to_host_u16(udp1->dst_port) : 0;
-        t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
-            }
+            t->bypass = pass1;
+            t->fib_index = fib_index1;
+            t->src_addr.as_u32 = ip1->src_address.as_u32;
+            t->dst_port = (pass1 == 0) ?
+              clib_net_to_host_u16(udp1->dst_port) : 0;
+            t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
+          }
 
-      vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
-                       to_next, n_left_to_next,
-                       bi0, bi1, next0, next1);
-    }
+          vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+                                           to_next, n_left_to_next,
+                                           bi0, bi1, next0, next1);
+        }
 
       while (n_left_from > 0 && n_left_to_next > 0)
-    {
-      vlib_buffer_t * b0;
-      ip4_header_t * ip0;
-      ip4_fib_mtrie_t * mtrie0;
-      ip4_fib_mtrie_leaf_t leaf0;
-      ip4_source_and_port_range_check_config_t * c0;
-      ip_adjacency_t * adj0;
-      u32 bi0, next0, adj_index0, pass0, save_next0;
+        {
+          vlib_buffer_t * b0;
+          ip4_header_t * ip0;
+          ip4_fib_mtrie_t * mtrie0;
+          ip4_fib_mtrie_leaf_t leaf0;
+          ip_source_and_port_range_check_config_t * c0;
+          ip_adjacency_t * adj0 = 0;
+          u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
           udp_header_t * udp0;
 
-      bi0 = from[0];
-      to_next[0] = bi0;
-      from += 1;
-      to_next += 1;
-      n_left_from -= 1;
-      n_left_to_next -= 1;
+          bi0 = from[0];
+          to_next[0] = bi0;
+          from += 1;
+          to_next += 1;
+          n_left_from -= 1;
+          n_left_to_next -= 1;
+
+          b0 = vlib_get_buffer (vm, bi0);
+
+          fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
 
-      b0 = vlib_get_buffer (vm, bi0);
-      ip0 = vlib_buffer_get_current (b0);
+          ip0 = vlib_buffer_get_current (b0);
 
-      c0 = vnet_get_config_data
+          c0 = vnet_get_config_data
             (&cm->config_main, &b0->current_config_index,
              &next0,
              sizeof (c0[0]));
 
           /* we can't use the default VRF here... */
-          ASSERT(c0->fib_index);
+          for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+            {
+              ASSERT(c0->fib_index[i]);
+            }
+
 
-      mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
+          if (ip0->protocol == IP_PROTOCOL_UDP)
+            fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
+          if (ip0->protocol == IP_PROTOCOL_TCP)
+            fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
 
-      leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
+          if (fib_index0 != ~0)
+            {
+
+              mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 0);
+              leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 1);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 0);
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 2);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 1);
 
-      leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
-                                             &ip0->src_address, 3);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 2);
 
-      adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
+              leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
+                                                 &ip0->src_address, 3);
 
-      ASSERT (adj_index0 == ip4_fib_lookup_with_table
-                  (im, c0->fib_index,
-                   &ip0->src_address,
-                   0 /* use default route */));
-          adj0 = ip_get_adjacency (lm, adj_index0);
+              adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
 
-      /*
-       * $$$ which (src,dst) categories should we always pass?
-       */
+              ASSERT (adj_index0 == ip4_fib_lookup_with_table
+                      (im, fib_index0,
+                       &ip0->src_address,
+                       0 /* use default route */));
+              adj0 = ip_get_adjacency (lm, adj_index0);
+            }
+          /*
+           * $$$ which (src,dst) categories should we always pass?
+           */
           pass0 = 0;
+          pass0 |= adj0 == 0;
           pass0 |= ip4_address_is_multicast (&ip0->src_address);
           pass0 |= ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
           pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) &&
-        (ip0->protocol != IP_PROTOCOL_TCP);
+            (ip0->protocol != IP_PROTOCOL_TCP);
 
-      save_next0 = next0;
-      udp0 = ip4_next_header (ip0);
+          save_next0 = next0;
+          udp0 = ip4_next_header (ip0);
 
           if (PREDICT_TRUE(pass0 == 0))
             {
-          good_packets ++;
+              good_packets ++;
               next0 = check_adj_port_range_x1
                 (adj0, clib_net_to_host_u16(udp0->dst_port), next0);
-          good_packets -= (save_next0 != next0);
+              good_packets -= (save_next0 != next0);
               b0->error = error_node->errors
                 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
             }
@@ -399,26 +431,27 @@ ip4_source_and_port_range_check_inline
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
                             && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
             ip4_source_and_port_range_check_trace_t * t =
-          vlib_add_trace (vm, node, b0, sizeof (*t));
+              vlib_add_trace (vm, node, b0, sizeof (*t));
             t->pass = next0 == save_next0;
-        t->bypass = pass0;
-        t->src_addr.as_u32 = ip0->src_address.as_u32;
-        t->dst_port = (pass0 == 0) ?
-          clib_net_to_host_u16(udp0->dst_port) : 0;
-        t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
-            }
+            t->bypass = pass0;
+            t->fib_index = fib_index0;
+            t->src_addr.as_u32 = ip0->src_address.as_u32;
+            t->dst_port = (pass0 == 0) ?
+              clib_net_to_host_u16(udp0->dst_port) : 0;
+            t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
+          }
 
-      vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                       to_next, n_left_to_next,
-                       bi0, next0);
-    }
+          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);
     }
 
   vlib_node_increment_counter (vm, ip4_source_port_and_range_check.index,
-                   IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
-                   good_packets);
+                               IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
+                               good_packets);
   return frame->n_vectors;
 }
 
@@ -448,7 +481,7 @@ VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
 };
 
 int set_ip_source_and_port_range_check (vlib_main_t * vm,
-                                        u32 fib_index,
+                                        u32 fib_index,
                                         u32 sw_if_index,
                                         u32 is_add)
 {
@@ -456,20 +489,24 @@ int set_ip_source_and_port_range_check (vlib_main_t * vm,
   ip_lookup_main_t * lm = &im->lookup_main;
   ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
   u32 ci;
-  ip4_source_and_port_range_check_config_t config;
+  ip_source_and_port_range_check_config_t config;
   u32 feature_index;
   int rv = 0;
-  u8 is_del = !is_add;
+  int i;
+
+  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+    {
+      config.fib_index[i] = fib_index[i];
+    }
 
-  config.fib_index = fib_index;
   feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
 
   vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
 
   ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
-  ci = (is_del
-    ? vnet_config_del_feature
-    : vnet_config_add_feature)
+  ci = (is_add
+        ? vnet_config_add_feature
+        : vnet_config_del_feature)
     (vm, &rx_cm->config_main,
      ci,
      feature_index,
@@ -482,49 +519,69 @@ int set_ip_source_and_port_range_check (vlib_main_t * vm,
 
 static clib_error_t *
 set_ip_source_and_port_range_check_fn (vlib_main_t * vm,
-             unformat_input_t * input,
-             vlib_cli_command_t * cmd)
+                                       unformat_input_t * input,
+                                       vlib_cli_command_t * cmd)
 {
   vnet_main_t * vnm = vnet_get_main();
   ip4_main_t * im = &ip4_main;
   clib_error_t * error = 0;
-  u32 is_add = 1;
+  u8 is_add = 1;
   u32 sw_if_index = ~0;
-  u32 vrf_id = ~0;
-  u32 fib_index;
+  u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
+  u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
+  int vrf_set = 0;
   uword * p;
   int rv = 0;
+  int i;
 
   sw_if_index = ~0;
+  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+    {
+      fib_index[i] = ~0;
+      vrf_id[i] = ~0;
+    }
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
-            &sw_if_index))
-       ;
-      else if (unformat (input, "vrf %d", &vrf_id))
-       ;
+                    &sw_if_index))
+        ;
+      else if (unformat (input, "tcp-out-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]))
+        vrf_set = 1;
+      else if (unformat (input, "udp-out-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]))
+        vrf_set = 1;
+      else if (unformat (input, "tcp-in-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]))
+        vrf_set = 1;
+      else if (unformat (input, "udp-in-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]))
+        vrf_set = 1;
       else if (unformat (input, "del"))
-       is_add = 0;
+        is_add = 0;
       else
-       break;
+        break;
     }
 
   if (sw_if_index == ~0)
     return clib_error_return (0, "Interface required but not specified");
 
-  if (vrf_id == ~0)
-    return clib_error_return (0, "VRF ID required but not specified");
+  if (!vrf_set)
+    return clib_error_return (0, "TCP or UDP VRF ID required but not specified");
 
-  if (vrf_id == 0)
-    return clib_error_return (0, "VRF ID should not be default. Should be distinct VRF for this purpose. ");
+  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+    {
 
-  p = hash_get (im->fib_index_by_table_id, vrf_id);
+      if (vrf_id[i] == 0)
+        return clib_error_return (0, "TCP, UDP VRF ID should not be 0 (default). Should be distinct VRF for this purpose. ");
 
-  if (p == 0)
-    return clib_error_return (0, "Invalid VRF ID %d", vrf_id);
+      if (vrf_id[i] != ~0)
+        {
+          p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
 
-  fib_index = p[0];
+          if (p == 0)
+            return clib_error_return (0, "Invalid VRF ID %d", vrf_id[i]);
+
+          fib_index[i] = p[0];
+        }
+    }
   rv = set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
 
   switch(rv)
@@ -543,7 +600,7 @@ VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command,
                   static) = {
   .path = "set interface ip source-and-port-range-check",
   .function = set_ip_source_and_port_range_check_fn,
-  .short_help = "set int ip source-and-port-range-check <intfc> vrf <n> [del]",
+  .short_help = "set int ip source-and-port-range-check <intfc> [tcp-out-vrf <n>] [udp-out-vrf <n>] [tcp-in-vrf <n>] [udp-in-vrf <n>] [del]",
 };
 
 static u8 * format_source_and_port_rc_adjacency (u8 * s, va_list * args)
@@ -554,11 +611,11 @@ static u8 * format_source_and_port_rc_adjacency (u8 * s, va_list * args)
   ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
   source_range_check_main_t * srm = &source_range_check_main;
   u8 * rwh = (u8 *) (&adj->rewrite_header);
-  port_range_t * range;
+  protocol_port_range_t * range;
   int i, j;
   int printed = 0;
 
-  range = (port_range_t *) rwh;
+  range = (protocol_port_range_t *) rwh;
 
   s = format (s, "allow ");
 
@@ -594,8 +651,8 @@ clib_error_t * ip4_source_and_port_range_check_init (vlib_main_t * vm)
 
   srm->ranges_per_adjacency = VLIB_BUFFER_PRE_DATA_SIZE / (2*sizeof(u16x8));
   srm->special_adjacency_format_function_index =
-      vnet_register_special_adjacency_format_function
-      (lm, format_source_and_port_rc_adjacency);
+    vnet_register_special_adjacency_format_function
+    (lm, format_source_and_port_rc_adjacency);
   ASSERT (srm->special_adjacency_format_function_index);
 
   return 0;
@@ -603,155 +660,199 @@ clib_error_t * ip4_source_and_port_range_check_init (vlib_main_t * vm)
 
 VLIB_INIT_FUNCTION (ip4_source_and_port_range_check_init);
 
-
-int ip4_source_and_port_range_check_add_del
-(ip4_address_t * address, u32 length, u32 vrf_id, u16 * low_ports,
- u16 * hi_ports, int is_add)
+int add_port_range_adjacency(ip4_address_t * address,
+                             u32 length,
+                             u32 adj_index,
+                             u16 * low_ports,
+                             u16 * high_ports,
+                             u32 fib_index)
 {
+  ip_adjacency_t * adj;
+  int i, j, k;
   source_range_check_main_t * srm = &source_range_check_main;
   ip4_main_t * im = &ip4_main;
   ip_lookup_main_t * lm = &im->lookup_main;
-  uword * p;
-  u32 fib_index;
-  u32 adj_index;
-  ip_adjacency_t * adj;
-  int i, j, k;
-  port_range_t * range;
+  protocol_port_range_t * range;
   u8 *rwh;
 
-  p = hash_get (im->fib_index_by_table_id, vrf_id);
-  if (!p)
-    {
-      ip4_fib_t * f;
-      f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */);
-      fib_index = f->index;
-    }
-  else
-    fib_index = p[0];
+  adj = ip_get_adjacency (lm, adj_index);
+  /* $$$$ fixme: add ports if address + mask match */
+  if (adj->lookup_next_index == IP_LOOKUP_NEXT_ICMP_ERROR)
+    return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
 
-  adj_index = ip4_fib_lookup_with_table
-    (im, fib_index, address, 0 /* disable_default_route */);
+  ip_adjacency_t template_adj;
+  ip4_add_del_route_args_t a;
 
-  if (is_add == 0)
-    {
-      adj = ip_get_adjacency (lm, adj_index);
-      if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR)
-        return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
+  memset (&template_adj, 0, sizeof (template_adj));
 
-      rwh = (u8 *)(&adj->rewrite_header);
+  template_adj.lookup_next_index = IP_LOOKUP_NEXT_ICMP_ERROR;
+  template_adj.if_address_index = ~0;
+  template_adj.special_adjacency_format_function_index =
+    srm->special_adjacency_format_function_index;
 
-      for (i = 0; i < vec_len (low_ports); i++)
+  rwh = (u8 *) (&template_adj.rewrite_header);
+
+  range = (protocol_port_range_t *) rwh;
+
+  if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
+    return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
+
+  j = k = 0;
+
+  for (i = 0; i < vec_len (low_ports); i++)
+    {
+      for (; j < srm->ranges_per_adjacency; j++)
         {
-          range = (port_range_t *) rwh;
-          for (j = 0; j < srm->ranges_per_adjacency; j++)
+          for (; k < 8; k++)
             {
-              for (k = 0; k < 8; k++)
+              if (range->low.as_u16[k] == 0)
                 {
-                  if (low_ports[i] == range->low.as_u16[k] &&
-                      hi_ports[i] == range->hi.as_u16[k])
+                  range->low.as_u16[k] = low_ports[i];
+                  range->hi.as_u16[k] = high_ports[i];
+                  k++;
+                  if (k == 7)
                     {
-                      range->low.as_u16[k] = range->hi.as_u16[k] = 0;
-                      goto doublebreak;
+                      k = 0;
+                      j++;
                     }
+                  goto doublebreak2;
                 }
-              range++;
             }
-        doublebreak: ;
+          k = 0;
+          range++;
         }
+      j = 0;
+      /* Too many ports specified... */
+      return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
 
-      range = (port_range_t *) rwh;
-      /* Have we deleted all ranges yet? */
-      for (i = 0; i < srm->ranges_per_adjacency; i++)
+    doublebreak2: ;
+    }
+
+  memset (&a, 0, sizeof(a));
+  a.flags = IP4_ROUTE_FLAG_FIB_INDEX;
+  a.table_index_or_table_id = fib_index;
+  a.dst_address = address[0];
+  a.dst_address_length = length;
+  a.add_adj = &template_adj;
+  a.n_add_adj = 1;
+
+  ip4_add_del_route (im, &a);
+  return 0;
+}
+
+int remove_port_range_adjacency(ip4_address_t * address,
+                                u32 length,
+                                u32 adj_index,
+                                u16 * low_ports,
+                                u16 * high_ports,
+                                u32 fib_index)
+{
+  ip_adjacency_t * adj;
+  int i, j, k;
+  source_range_check_main_t * srm = &source_range_check_main;
+  ip4_main_t * im = &ip4_main;
+  ip_lookup_main_t * lm = &im->lookup_main;
+  protocol_port_range_t * range;
+  u8 *rwh;
+
+  adj = ip_get_adjacency (lm, adj_index);
+  if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR) /* _ICMP_ERROR is a dummy placeholder */
+    return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
+
+  rwh = (u8 *)(&adj->rewrite_header);
+
+  for (i = 0; i < vec_len (low_ports); i++)
+    {
+      range = (protocol_port_range_t *) rwh;
+      for (j = 0; j < srm->ranges_per_adjacency; j++)
         {
-          for (j = 0; j < 8; j++)
+          for (k = 0; k < 8; k++)
             {
-              if (range->low.as_u16[i] != 0)
-                goto still_occupied;
+              if (low_ports[i] == range->low.as_u16[k] &&
+                  high_ports[i] == range->hi.as_u16[k])
+                {
+                  range->low.as_u16[k] = range->hi.as_u16[k] = 0;
+                  goto doublebreak;
+                }
             }
           range++;
         }
-      /* Yes, lose the adjacency... */
-      {
-    ip4_add_del_route_args_t a;
-
-        memset (&a, 0, sizeof(a));
-        a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
-        a.table_index_or_table_id = fib_index;
-        a.dst_address = address[0];
-        a.dst_address_length = length;
-        a.adj_index = adj_index;
-        ip4_add_del_route (im, &a);
-      }
-
-    still_occupied:
-      ;
+    doublebreak: ;
     }
-  else
-    {
-      adj = ip_get_adjacency (lm, adj_index);
-      /* $$$$ fixme: add ports if address + mask match */
-      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ICMP_ERROR)
-        return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
 
-      {
-        ip_adjacency_t template_adj;
-        ip4_add_del_route_args_t a;
-
-        memset (&template_adj, 0, sizeof (template_adj));
-
-        template_adj.lookup_next_index = IP_LOOKUP_NEXT_ICMP_ERROR;
-        template_adj.if_address_index = ~0;
-        template_adj.special_adjacency_format_function_index =
-          srm->special_adjacency_format_function_index;
-
-        rwh = (u8 *) (&template_adj.rewrite_header);
+  range = (protocol_port_range_t *) rwh;
+  /* Have we deleted all ranges yet? */
+  for (i = 0; i < srm->ranges_per_adjacency; i++)
+    {
+      for (j = 0; j < 8; j++)
+        {
+          if (range->low.as_u16[i] != 0)
+            goto still_occupied;
+        }
+      range++;
+    }
+  /* Yes, lose the adjacency... */
+  {
+    ip4_add_del_route_args_t a;
 
-        range = (port_range_t *) rwh;
+    memset (&a, 0, sizeof(a));
+    a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
+    a.table_index_or_table_id = fib_index;
+    a.dst_address = address[0];
+    a.dst_address_length = length;
+    a.adj_index = adj_index;
+    ip4_add_del_route (im, &a);
+  }
+
+ still_occupied:
+  ;
+  return 0;
+}
 
-        if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
-          return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
+// This will be moved to another file and implemented post API freeze.
+int ip6_source_and_port_range_check_add_del (ip6_address_t * address,
+                                             u32 length,
+                                             u32 vrf_id,
+                                             u16 * low_ports,
+                                             u16 * high_ports,
+                                             int is_add)
+{
+  return 0;
+}
+int ip4_source_and_port_range_check_add_del (ip4_address_t * address,
+                                             u32 length,
+                                             u32 vrf_id,
+                                             u16 * low_ports,
+                                             u16 * high_ports,
+                                             int is_add)
+{
 
-        j = k = 0;
+  ip4_main_t * im = &ip4_main;
+  //  ip_lookup_main_t * lm = &im->lookup_main;
+  uword * p;
+  u32 fib_index;
+  u32 adj_index;
 
-        for (i = 0; i < vec_len (low_ports); i++)
-          {
-            for (; j < srm->ranges_per_adjacency; j++)
-              {
-                for (; k < 8; k++)
-                  {
-                    if (range->low.as_u16[k] == 0)
-                      {
-                        range->low.as_u16[k] = low_ports[i];
-                        range->hi.as_u16[k] = hi_ports[i];
-                        k++;
-                        if (k == 7)
-                          {
-                            k = 0;
-                            j++;
-                          }
-                        goto doublebreak2;
-                      }
-                  }
-                k = 0;
-                range++;
-              }
-            j = 0;
-            /* Too many ports specified... */
-            return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
-
-          doublebreak2: ;
-          }
+  p = hash_get (im->fib_index_by_table_id, vrf_id);
+  if (!p)
+    {
+      ip4_fib_t * f;
+      f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */);
+      fib_index = f->index;
+    }
+  else
+    fib_index = p[0];
 
-        memset (&a, 0, sizeof(a));
-        a.flags = IP4_ROUTE_FLAG_FIB_INDEX;
-        a.table_index_or_table_id = fib_index;
-        a.dst_address = address[0];
-        a.dst_address_length = length;
-        a.add_adj = &template_adj;
-        a.n_add_adj = 1;
+  adj_index = ip4_fib_lookup_with_table
+    (im, fib_index, address, 0 /* disable_default_route */);
 
-        ip4_add_del_route (im, &a);
-      }
+  if (is_add == 0)
+    {
+      remove_port_range_adjacency(address, length, adj_index, low_ports, high_ports, fib_index);
+    }
+  else
+    {
+      add_port_range_adjacency(address, length, adj_index, low_ports, high_ports, fib_index);
     }
 
   return 0;
@@ -766,18 +867,21 @@ ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
   u16 * high_ports = 0;
   u16 this_low;
   u16 this_hi;
-  ip4_address_t addr;
+  ip4_address_t ip4_addr;
+  ip6_address_t ip6_addr; //This function will be moved to generic impl when v6 done.
   u32 length;
   u32 tmp, tmp2;
-  u8 prefix_set = 0;
   u32 vrf_id = ~0;
-  int is_add = 1;
+  int is_add = 1, ip_ver = ~0;
   int rv;
 
+
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "%U/%d", unformat_ip4_address, &addr, &length))
-        prefix_set = 1;
+      if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length))
+        ip_ver = 4;
+      else if (unformat (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length))
+        ip_ver = 6;
       else if (unformat (input, "vrf %d", &vrf_id))
         ;
       else if (unformat (input, "del"))
@@ -799,7 +903,7 @@ ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
           if (tmp == 0 || tmp > 65535)
             return clib_error_return (0, "low port %d out of range", tmp);
           if (tmp2 == 0 || tmp2 > 65535)
-            return clib_error_return (0, "hi port %d out of range", tmp2);
+            return clib_error_return (0, "high port %d out of range", tmp2);
           this_low = tmp;
           this_hi = tmp2+1;
           vec_add1 (low_ports, this_low);
@@ -809,20 +913,24 @@ ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
         break;
     }
 
-  if (prefix_set == 0)
-    return clib_error_return (0, "<address>/<mask> not specified");
+  if (ip_ver == ~0)
+    return clib_error_return (0, " <address>/<mask> not specified");
 
   if (vrf_id == ~0)
-    return clib_error_return (0, "VRF ID required, not specified");
+    return clib_error_return (0, " VRF ID required, not specified");
+
+  if ( vec_len (low_ports) == 0)
+    return clib_error_return (0, " Both VRF ID and range/port must be set for a protocol.");
 
   if (vrf_id == 0)
-    return clib_error_return (0, "VRF ID should not be default. Should be distinct VRF for this purpose. ");
+    return clib_error_return (0, " VRF ID can not be 0 (default).");
 
-  if (vec_len(low_ports) == 0)
-    return clib_error_return (0, "At least one port or port range required");
 
-  rv = ip4_source_and_port_range_check_add_del
-    (&addr, length, vrf_id, low_ports, high_ports, is_add);
+  if (ip_ver == 4)
+    rv = ip4_source_and_port_range_check_add_del
+      (&ip4_addr, length, vrf_id, low_ports, high_ports, is_add);
+  else
+        return clib_error_return (0, " IPv6 in subsequent patch");
 
   switch(rv)
     {
@@ -831,19 +939,19 @@ ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
 
     case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
       return clib_error_return
-        (0, "Incorrect adjacency for add/del operation in ip4 source and port-range check.");
+        (0, " Incorrect adjacency for add/del operation");
 
     case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
       return clib_error_return
-        (0, "Too many ports in add/del operation in ip4 source and port-range check.");
+        (0, " Too many ports in add/del operation");
 
     case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
       return clib_error_return
-        (0, "Too many ranges requested for add operation in ip4 source and port-range check.");
+        (0, " Too many ranges requested for add operation");
 
     default:
       return clib_error_return
-        (0, "ip4_source_and_port_range_check_add returned an unexpected value: %d", rv);
+        (0, " returned an unexpected value: %d", rv);
     }
 
   return 0;
@@ -853,7 +961,7 @@ VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
   .path = "set ip source-and-port-range-check",
   .function = ip_source_and_port_range_check_command_fn,
   .short_help =
-  "set ip source-and-port-range-check <ip-addr>/<mask> range <nn>-<nn> vrf <id>",
+  "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn>-<nn> tcp-vrf <id>] [vrf <id>] [del]",
 };
 
 
@@ -865,7 +973,7 @@ show_source_and_port_range_check_fn (vlib_main_t * vm,
   source_range_check_main_t * srm = & source_range_check_main;
   ip4_main_t * im = &ip4_main;
   ip_lookup_main_t * lm = &im->lookup_main;
-  port_range_t * range;
+  protocol_port_range_t * range;
   u32 fib_index;
   ip4_address_t addr;
   u8 addr_set = 0;
@@ -929,7 +1037,7 @@ show_source_and_port_range_check_fn (vlib_main_t * vm,
 
       s = format (0, "%U: ", format_ip4_address, &addr);
 
-      range = (port_range_t *) rwh;
+      range = (protocol_port_range_t *) rwh;
 
       for (i = 0; i < srm->ranges_per_adjacency; i++)
         {
index 7fbb2b0..1429057 100644 (file)
 #ifndef included_ip_ip_source_and_port_range_check_h
 #define included_ip_ip_source_and_port_range_check_h
 
+
+typedef struct {
+  u32 ranges_per_adjacency;
+  u32 special_adjacency_format_function_index;
+
+  /* convenience */
+  vlib_main_t *vlib_main;
+  vnet_main_t *vnet_main;
+} source_range_check_main_t;
+
+source_range_check_main_t source_range_check_main;
+
+typedef enum {
+  IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT,
+  IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT,
+  IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN,
+  IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN,
+  IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS,
+} ip_source_and_port_range_check_protocol_t;
+
+typedef struct {
+  u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
+} ip_source_and_port_range_check_config_t;
+
+#define IP_SOURCE_AND_PORT_RANGE_CHECK_RANGE_LIMIT VLIB_BUFFER_PRE_DATA_SIZE/(2*sizeof(u16x8));
+
+typedef struct {
+  union {
+    u16x8 as_u16x8;
+    u16 as_u16[8];
+  };
+} u16x8vec_t;
+
+typedef struct {
+  u16x8vec_t low;
+  u16x8vec_t hi;
+} protocol_port_range_t;
+
 int ip4_source_and_port_range_check_add_del (ip4_address_t * address,
                                              u32 length,
                                              u32 vrf_id,
@@ -23,8 +61,16 @@ int ip4_source_and_port_range_check_add_del (ip4_address_t * address,
                                              u16 * hi_ports,
                                              int is_add);
 
+// This will be moved to another file in another patch -- for API freeze
+int ip6_source_and_port_range_check_add_del (ip6_address_t * address,
+                                             u32 length,
+                                             u32 vrf_id,
+                                             u16 * low_ports,
+                                             u16 * hi_ports,
+                                             int is_add);
+
 int set_ip_source_and_port_range_check (vlib_main_t * vm,
-                                        u32 fib_index,
+                                        u32 fib_index,
                                         u32 sw_if_index,
                                         u32 is_add);
 
index 3590a07..d410955 100644 (file)
@@ -13557,34 +13557,45 @@ int api_ip_source_and_port_range_check_interface_add_del (vat_main_t * vam)
     vl_api_ip_source_and_port_range_check_interface_add_del_t *mp;
     f64 timeout;
     u32 sw_if_index = ~0;
-    u32 vrf_id = ~0;
+    int vrf_set = 0;
+    u32 tcp_out_vrf_id = ~0, udp_out_vrf_id = ~0;
+    u32 tcp_in_vrf_id = ~0, udp_in_vrf_id = ~0;
     u8 is_add = 1;
 
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-        {
-            if (unformat (input, "%U", unformat_sw_if_index, vam, &sw_if_index))
+      {
+        if (unformat (input, "%U", unformat_sw_if_index, vam, &sw_if_index))
             ;
-            else if (unformat (input, "sw_if_index %d", &sw_if_index))
+        else if (unformat (input, "sw_if_index %d", &sw_if_index))
             ;
-            else if (unformat (input, "vrf %d", &vrf_id))
-                ;
-            else if (unformat (input, "del"))
-                is_add = 0;
-            else
-                break;
-        }
+        else if (unformat (input, "tcp-out-vrf %d", &tcp_out_vrf_id))
+            vrf_set=1;
+        else if (unformat (input, "udp-out-vrf %d", &udp_out_vrf_id))
+            vrf_set=1;
+        else if (unformat (input, "tcp-in-vrf %d", &tcp_in_vrf_id))
+            vrf_set=1;
+        else if (unformat (input, "udp-in-vrf %d", &udp_in_vrf_id))
+            vrf_set=1;
+        else if (unformat (input, "del"))
+            is_add = 0;
+        else
+              break;
+      }
 
     if (sw_if_index == ~0) {
-        errmsg ("Interface required but not specified\n");
-        return -99;
+          errmsg ("Interface required but not specified\n");
+          return -99;
     }
 
-    if (vrf_id == ~0) {
+    if (vrf_set == 0) {
         errmsg ("VRF ID required but not specified\n");
         return -99;
     }
 
-    if (vrf_id == 0) {
+    if (tcp_out_vrf_id == 0
+        || udp_out_vrf_id == 0
+        || tcp_in_vrf_id == 0
+        || udp_in_vrf_id == 0) {
         errmsg ("VRF ID should not be default. Should be distinct VRF for this purpose.\n");
         return -99;
     }
@@ -13594,7 +13605,10 @@ int api_ip_source_and_port_range_check_interface_add_del (vat_main_t * vam)
 
     mp->sw_if_index = ntohl (sw_if_index);
     mp->is_add = is_add;
-    mp->vrf_id = ntohl (vrf_id);
+    mp->tcp_out_vrf_id = ntohl (tcp_out_vrf_id);
+    mp->udp_out_vrf_id = ntohl (udp_out_vrf_id);
+    mp->tcp_in_vrf_id = ntohl (tcp_in_vrf_id);
+    mp->udp_in_vrf_id = ntohl (udp_in_vrf_id);
 
     /* send it... */
     S;
@@ -14135,7 +14149,8 @@ _(pg_enable_disable, "[stream <id>] disable")                           \
 _(ip_source_and_port_range_check_add_del,                               \
   "<ip-addr>/<mask> range <nn>-<nn> vrf <id>")                          \
 _(ip_source_and_port_range_check_interface_add_del,                     \
-  "<intf> | sw_if_index <nn> vrf <id>")
+  "<intf> | sw_if_index <nn> [tcp-out-vrf <id>] [tcp-in-vrf <id>]"      \
+  "[udp-in-vrf <id>] [udp-out-vrf <id>]")
 
 /* List of command functions, CLI names map directly to functions */
 #define foreach_cli_function                                    \
index 73ecbd7..18999a5 100644 (file)
@@ -7380,13 +7380,13 @@ static void vl_api_ip_source_and_port_range_check_add_del_t_handler (
     u8  is_add = mp->is_add;
     u8  mask_length = mp->mask_length;
     ip4_address_t ip4_addr;
-    //ip6_address_t ip6_addr;
-    u16 * low_ports = 0 ;
-    u16 * high_ports = 0 ;
+    ip6_address_t ip6_addr;
+    u16 * low_ports = 0;
+    u16 * high_ports = 0;
+    u32 vrf_id;
     u16 tmp_low, tmp_high;
     u8 num_ranges ;
     int i;
-    u32 vrf_id;
 
     // Validate port range
     num_ranges = mp->number_of_ranges;
@@ -7415,8 +7415,8 @@ static void vl_api_ip_source_and_port_range_check_add_del_t_handler (
     if (mask_length < 0 ||
         ( is_ipv6 && mask_length > 128) ||
         ( !is_ipv6 && mask_length > 32)) {
-            rv = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
-            goto reply;
+        rv = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
+        goto reply;
     }
 
     vrf_id = ntohl (mp->vrf_id);
@@ -7425,33 +7425,31 @@ static void vl_api_ip_source_and_port_range_check_add_del_t_handler (
         rv = VNET_API_ERROR_INVALID_VALUE;
         goto reply;
     }
-    //ip6
+
+
     if (is_ipv6) {
-    /* clib_memcpy (ip6_addr.as_u8, mp->address, */
-    /*         sizeof (ip6_addr.as_u8)); */
-        /* rv = ip6_source_and_port_range_check_add_del (ip6_addr, */
-        /*                                               mask_length, */
-        /*                                               vrf_id, */
-        /*                                               low_ports, */
-        /*                                               high_ports, */
-        /*                                               is_add); */
-
-    //ip4
-    } else {
-        clib_memcpy (ip4_addr.data, mp->address,
-                     sizeof (ip4_addr));
-        rv = ip4_source_and_port_range_check_add_del (&ip4_addr,
+        clib_memcpy (ip6_addr.as_u8, mp->address,
+                     sizeof (ip6_addr.as_u8));
+        rv = ip6_source_and_port_range_check_add_del (&ip6_addr,
                                                       mask_length,
                                                       vrf_id,
                                                       low_ports,
                                                       high_ports,
                                                       is_add);
+    } else {
+          clib_memcpy (ip4_addr.data, mp->address,
+                       sizeof (ip4_addr));
+          rv = ip4_source_and_port_range_check_add_del (&ip4_addr,
+                                                        mask_length,
+                                                        vrf_id,
+                                                        low_ports,
+                                                        high_ports,
+                                                        is_add);
     }
 
  reply:
     vec_free (low_ports);
     vec_free (high_ports);
-
     REPLY_MACRO(VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY);
 }
 
@@ -7463,20 +7461,35 @@ vl_api_ip_source_and_port_range_check_interface_add_del_t_handler
     vl_api_ip_source_and_port_range_check_interface_add_del_reply_t * rmp;
     ip4_main_t * im = &ip4_main;
     int rv;
-    u32 sw_if_index, fib_index, vrf_id;
+    u32 sw_if_index;
+    u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
+    u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
     uword * p = 0;
+    int i;
 
-    vrf_id  = ntohl(mp->vrf_id);
+    vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]  = ntohl(mp->tcp_out_vrf_id);
+    vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]  = ntohl(mp->udp_out_vrf_id);
+    vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]  = ntohl(mp->tcp_in_vrf_id);
+    vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]  = ntohl(mp->udp_in_vrf_id);
 
-    p = hash_get (im->fib_index_by_table_id, vrf_id);
 
-    if (p == 0) {
-        rv = VNET_API_ERROR_INVALID_VALUE;
-        goto reply;
-    }
+    for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+      {
+        if (vrf_id[i] !=0 && vrf_id[i] != ~0)
+          {
+            p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
 
-    fib_index = p[0];
+            if (p == 0)
+              {
+                rv = VNET_API_ERROR_INVALID_VALUE;
+                goto reply;
+              }
 
+            fib_index[i] = p[0];
+          }
+        else
+            fib_index[i] = ~0;
+        }
     sw_if_index = ntohl(mp->sw_if_index);
 
     VALIDATE_SW_IF_INDEX(mp);
index 51bf81d..bf02ac4 100644 (file)
@@ -2099,7 +2099,7 @@ static void *vl_api_ip_source_and_port_range_check_add_del_t_print
                     mp->mask_length);
 
     for (i = 0; i < mp->number_of_ranges; i++) {
-        s = format (s, "range %d - %d", mp->low_ports[i], mp->high_ports[i]);
+        s = format (s, "range %d - %d ", mp->low_ports[i], mp->high_ports[i]);
     }
 
     s = format (s, "vrf %d ", ntohl(mp->vrf_id));
@@ -2117,9 +2117,19 @@ static void *vl_api_ip_source_and_port_range_check_interface_add_del_t_print
 
     s = format (0, "SCRIPT: ip_source_and_port_range_check_interface_add_del ");
 
-    s = format (s, "%d ", ntohl(mp->sw_if_index));
+    s = format (s, "sw_if_index %d ", ntohl(mp->sw_if_index));
 
-    s = format (s, "vrf %d ", ntohl(mp->vrf_id));
+    if (mp->tcp_out_vrf_id != ~0)
+        s = format (s, "tcp-out-vrf %d ", ntohl(mp->tcp_out_vrf_id));
+
+    if (mp->udp_out_vrf_id != ~0)
+        s = format (s, "udp-out-vrf %d ", ntohl(mp->udp_out_vrf_id));
+
+    if (mp->tcp_in_vrf_id != ~0)
+        s = format (s, "tcp-in-vrf %d ", ntohl(mp->tcp_in_vrf_id));
+
+    if (mp->udp_in_vrf_id != ~0)
+        s = format (s, "udp-in-vrf %d ", ntohl(mp->udp_in_vrf_id));
 
     if (mp->is_add == 0)
         s = format (s, "del ");
index 67e742e..4b8aa81 100644 (file)
@@ -4342,7 +4342,7 @@ define pg_capture_reply {
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param is_enabled - 1 if enabling streams, 0 if disabling
-    @param stream - stream name to be enable/disabled, if not specified handle all streams 
+    @param stream - stream name to be enable/disabled, if not specified handle all streams
 */
 define pg_enable_disable {
     u32 client_index;
@@ -4368,6 +4368,7 @@ define pg_enable_disable_reply {
     @param is_add - 1 if add, 0 if delete
     @param mask_length - mask length for address entry
     @param address - array of address bytes
+    @param number_of_ranges - length of low_port and high_port arrays (must match)
     @param low_ports[32] - up to 32 low end of port range entries (must have corresponding high_ports entry)
     @param high_ports[32] - up to 32 high end of port range entries (must have corresponding low_ports entry)
     @param vrf_id - fib table/vrf id to associate the source and port-range check with
@@ -4399,14 +4400,18 @@ define ip_source_and_port_range_check_add_del_reply {
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param interface_id - interface index
-    @param vrf_id - VRF associated with source and L4 port-range check
+    @param tcp_vrf_id - VRF associated with source and TCP port-range check
+    @param udp_vrf_id - VRF associated with source and TCP port-range check
 */
 define ip_source_and_port_range_check_interface_add_del {
     u32 client_index;
     u32 context;
     u8  is_add;
     u32 sw_if_index;
-    u32 vrf_id;
+    u32 tcp_in_vrf_id;
+    u32 tcp_out_vrf_id;
+    u32 udp_in_vrf_id;
+    u32 udp_out_vrf_id;
 };
 
 /** \brief Set interface source and L4 port-range response