VPP-337 Add per interface IN filtering 18/2418/6
authorDave Barach <dave@barachs.net>
Wed, 17 Aug 2016 15:54:30 +0000 (11:54 -0400)
committerKeith Burns <alagalah@gmail.com>
Fri, 19 Aug 2016 18:42:04 +0000 (18:42 +0000)
- ip post-rewrite feature subgraph arc support

Change-Id: Ia4b07197463021ade916326231af246e2559a290
Signed-off-by: Dave Barach <dave@barachs.net>
Signed-off-by: Keith Burns (alagalah) <alagalah@gmail.com>
24 files changed:
plugins/ila-plugin/ila/ila.c
plugins/snat-plugin/snat/out2in.c
plugins/snat-plugin/snat/snat.c
vnet/vnet/classify/input_acl.c
vnet/vnet/classify/policer_classify.c
vnet/vnet/ip/ip.h
vnet/vnet/ip/ip4.h
vnet/vnet/ip/ip4_forward.c
vnet/vnet/ip/ip4_input.c
vnet/vnet/ip/ip4_source_and_port_range_check.c
vnet/vnet/ip/ip4_source_check.c
vnet/vnet/ip/ip6.h
vnet/vnet/ip/ip6_forward.c
vnet/vnet/ip/ip6_input.c
vnet/vnet/ip/ip_feature_registration.c
vnet/vnet/ip/ip_feature_registration.h
vnet/vnet/ip/ip_init.c
vnet/vnet/ip/lookup.h
vnet/vnet/ipsec/ipsec.c
vnet/vnet/ipsec/ipsec_input.c
vnet/vnet/l2tp/decap.c
vnet/vnet/l2tp/l2tp.c
vnet/vnet/vnet.h
vpp/vpp-api/api.c

index 2673c62..99d1db8 100644 (file)
@@ -421,7 +421,7 @@ ila_sir2ila (vlib_main_t * vm,
 {
   ip6_main_t *im = &ip6_main;
   ip_lookup_main_t *lm = &im->lookup_main;
-  ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
   ila_main_t *ilm = &ila_main;
 
@@ -592,9 +592,10 @@ VLIB_REGISTER_NODE (ila_sir2ila_node, static) =
 
 VNET_IP6_UNICAST_FEATURE_INIT (ila_sir2ila, static) =
 {
-  .node_name = "sir-to-ila",.runs_before =
-  {
-"ip6-lookup", 0},.feature_index = &ila_main.ila_sir2ila_feature_index,};
+  .node_name = "sir-to-ila",
+  .runs_before = ORDER_CONSTRAINTS{"ip6-lookup", 0},
+  .feature_index = &ila_main.ila_sir2ila_feature_index,
+};
 
 int
 ila_add_del_entry (ila_add_del_entry_args_t * args)
@@ -769,7 +770,7 @@ ila_interface (u32 sw_if_index, u8 disable)
   ila_main_t *ilm = &ila_main;
   ip6_main_t *im = &ip6_main;
   ip_lookup_main_t *lm = &im->lookup_main;
-  ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   vnet_config_main_t *vcm = &cm->config_main;
   u32 ci, feature_index;
 
index 0fa96c9..861dae6 100644 (file)
@@ -163,7 +163,7 @@ snat_out2in_node_fn (vlib_main_t * vm,
   u32 pkts_processed = 0;
   snat_main_t * sm = &snat_main;
   ip_lookup_main_t * lm = sm->ip4_lookup_main;
-  ip_config_main_t * cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   f64 now = vlib_time_now (vm);
 
   from = vlib_frame_vector_args (frame);
index 3675602..f3e278b 100644 (file)
@@ -80,12 +80,12 @@ do {                                                            \
 /* Hook up input features */
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_snat_in2out, static) = {
   .node_name = "snat-in2out",
-  .runs_before = {"snat-out2in", 0},
+  .runs_before = (char *[]){"snat-out2in", 0},
   .feature_index = &snat_main.rx_feature_in2out,
 };
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_snat_out2in, static) = {
   .node_name = "snat-out2in",
-  .runs_before = {"ip4-lookup", 0},
+  .runs_before = (char *[]){"ip4-lookup", 0},
   .feature_index = &snat_main.rx_feature_out2in,
 };
 
@@ -257,7 +257,7 @@ vl_api_snat_interface_add_del_feature_t_handler
   u32 ci;
   ip4_main_t * im = &ip4_main;
   ip_lookup_main_t * lm = &im->lookup_main;
-  ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t * rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   u32 feature_index;
   int rv = 0;
 
@@ -471,7 +471,7 @@ snat_feature_command_fn (vlib_main_t * vm,
   snat_main_t * sm = &snat_main;
   ip4_main_t * im = &ip4_main;
   ip_lookup_main_t * lm = &im->lookup_main;
-  ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t * rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   clib_error_t * error = 0;
   u32 sw_if_index, ci;
   u32 feature_index;
index fb9a2a4..91ae068 100644 (file)
@@ -49,7 +49,7 @@ vnet_inacl_ip_feature_enable (vlib_main_t * vnm,
           ftype = ip6_main.ip6_unicast_rx_feature_check_access;
         }
 
-      ipcm = &lm->rx_config_mains[VNET_UNICAST];
+      ipcm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
 
       ci = ipcm->config_index_by_sw_if_index[sw_if_index];
       ci = ((feature_enable)
index c4c4484..e4580a2 100644 (file)
@@ -44,7 +44,7 @@ vnet_policer_classify_feature_enable (vlib_main_t * vnm,
           ftype = ip6_main.ip6_unicast_rx_feature_policer_classify;
         }
 
-      ipcm = &lm->rx_config_mains[VNET_UNICAST];
+      ipcm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
 
       ci = ipcm->config_index_by_sw_if_index[sw_if_index];
       ci = (feature_enable ? vnet_config_add_feature : vnet_config_del_feature)
index c9a8293..c5882c5 100644 (file)
@@ -217,4 +217,10 @@ void ip_del_all_interface_addresses (vlib_main_t *vm, u32 sw_if_index);
 extern vlib_node_registration_t ip4_inacl_node;
 extern vlib_node_registration_t ip6_inacl_node;
 
+void
+vnet_config_update_tx_feature_count (ip_lookup_main_t * lm, 
+                                     ip_config_main_t * tx_cm, 
+                                     u32 sw_if_index, 
+                                     int is_add);
+
 #endif /* included_ip_main_h */
index 9a54300..fc74e9d 100644 (file)
@@ -141,31 +141,38 @@ typedef struct ip4_main_t {
   /** Feature path configuration lists */
   vnet_ip_feature_registration_t * next_uc_feature;
   vnet_ip_feature_registration_t * next_mc_feature;
+  vnet_ip_feature_registration_t * next_tx_feature;
 
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_check_access;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_source_reachable_via_rx;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_source_reachable_via_any;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_policer_classify;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_ipsec;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_vpath;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_lookup;
-  /** Built-in unicast feature path indice, see @ref ip_feature_init_cast()  */
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
   u32 ip4_unicast_rx_feature_source_and_port_range_check;
 
-  /** Built-in multicast feature path indices */
+  /** Built-in multicast feature path index */
   u32 ip4_multicast_rx_feature_vpath;
-  /** Built-in multicast feature path indices */
+  /** Built-in multicast feature path index */
   u32 ip4_multicast_rx_feature_lookup;
 
+  /** Built-in unicast feature path index, see @ref ip_feature_init_cast()  */
+  u32 ip4_unicast_tx_feature_source_and_port_range_check;
+
+  /** Built-in tx feature path index */
+  u32 ip4_tx_feature_interface_output;
+
   /** Save results for show command */
-  char ** feature_nodes[VNET_N_CAST];
+  char ** feature_nodes[VNET_N_IP_FEAT];
 
   /** Seed for Jenkins hash used to compute ip4 flow hash. */
   u32 flow_hash_seed;
@@ -209,6 +216,18 @@ static void __vnet_add_feature_registration_mc_##x (void)       \
 }                                                               \
 __VA_ARGS__ vnet_ip_feature_registration_t mc_##x 
 
+#define VNET_IP4_TX_FEATURE_INIT(x,...)                         \
+  __VA_ARGS__ vnet_ip_feature_registration_t tx_##x;            \
+static void __vnet_add_feature_registration_tx_##x (void)       \
+  __attribute__((__constructor__)) ;                            \
+static void __vnet_add_feature_registration_tx_##x (void)       \
+{                                                               \
+  ip4_main_t * im = &ip4_main;                                  \
+  tx_##x.next = im->next_tx_feature;                            \
+  im->next_tx_feature = &tx_##x;                                \
+}                                                               \
+__VA_ARGS__ vnet_ip_feature_registration_t tx_##x 
+
 
 /** Global ip4 input node.  Errors get attached to ip4 input node. */
 extern vlib_node_registration_t ip4_input_node;
index 4b019bc..dd9fce4 100644 (file)
@@ -1387,91 +1387,127 @@ VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
 /* Built-in ip4 unicast rx feature path definition */
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_inacl, static) = {
   .node_name = "ip4-inacl", 
-  .runs_before = {"ip4-source-check-via-rx", 0}, 
+  .runs_before = ORDER_CONSTRAINTS {"ip4-source-check-via-rx", 0},
   .feature_index = &ip4_main.ip4_unicast_rx_feature_check_access,
 };
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_1, static) = {
   .node_name = "ip4-source-check-via-rx",
-  .runs_before = {"ip4-source-check-via-any", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip4-source-check-via-any", 0},
   .feature_index = 
   &ip4_main.ip4_unicast_rx_feature_source_reachable_via_rx,
 };
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_2, static) = {
   .node_name = "ip4-source-check-via-any",
-  .runs_before = {"ip4-policer-classify", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip4-policer-classify", 0},
   .feature_index = 
   &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
 };
 
-VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_and_port_range_check, static) = {
-  .node_name = "ip4-source-and-port-range-check",
-  .runs_before = {"ip4-policer-classify", 0},
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) = {
+  .node_name = "ip4-source-and-port-range-check-rx",
+  .runs_before = ORDER_CONSTRAINTS {"ip4-policer-classify", 0},
   .feature_index =
   &ip4_main.ip4_unicast_rx_feature_source_and_port_range_check,
 };
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_policer_classify, static) = {
   .node_name = "ip4-policer-classify",
-  .runs_before = {"ipsec-input-ip4", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ipsec-input-ip4", 0},
   .feature_index =
   &ip4_main.ip4_unicast_rx_feature_policer_classify,
 };
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
   .node_name = "ipsec-input-ip4",
-  .runs_before = {"vpath-input-ip4", 0},
+  .runs_before = ORDER_CONSTRAINTS {"vpath-input-ip4", 0},
   .feature_index = &ip4_main.ip4_unicast_rx_feature_ipsec,
 };
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_vpath, static) = {
   .node_name = "vpath-input-ip4",
-  .runs_before = {"ip4-lookup", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip4-lookup", 0},
   .feature_index = &ip4_main.ip4_unicast_rx_feature_vpath,
 };
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = {
   .node_name = "ip4-lookup",
-  .runs_before = {0}, /* not before any other features */
+  .runs_before = 0, /* not before any other features */
   .feature_index = &ip4_main.ip4_unicast_rx_feature_lookup,
 };
 
 /* Built-in ip4 multicast rx feature path definition */
 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
   .node_name = "vpath-input-ip4",
-  .runs_before = {"ip4-lookup-multicast", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip4-lookup-multicast", 0},
   .feature_index = &ip4_main.ip4_multicast_rx_feature_vpath,
 };
 
 VNET_IP4_MULTICAST_FEATURE_INIT (ip4_lookup_mc, static) = {
   .node_name = "ip4-lookup-multicast",
-  .runs_before = {0}, /* not before any other features */
+  .runs_before = 0, /* not before any other features */
   .feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
 };
 
-static char * feature_start_nodes[] = 
+static char * rx_feature_start_nodes[] = 
   { "ip4-input", "ip4-input-no-checksum"};
 
+static char * tx_feature_start_nodes[] = 
+{ "ip4-rewrite-transit"};
+
+/* Source and port-range check ip4 tx feature path definition */
+VNET_IP4_TX_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) = {
+  .node_name = "ip4-source-and-port-range-check-tx",
+  .runs_before = ORDER_CONSTRAINTS {"interface-output", 0},
+  .feature_index =
+  &ip4_main.ip4_unicast_tx_feature_source_and_port_range_check,
+
+};
+
+/* Built-in ip4 tx feature path definition */
+VNET_IP4_TX_FEATURE_INIT (interface_output, static) = {
+  .node_name = "interface-output",
+  .runs_before = 0, /* not before any other features */
+  .feature_index = &ip4_main.ip4_tx_feature_interface_output,
+};
+
+
 static clib_error_t *
 ip4_feature_init (vlib_main_t * vm, ip4_main_t * im)
 {
   ip_lookup_main_t * lm = &im->lookup_main;
   clib_error_t * error;
   vnet_cast_t cast;
+  ip_config_main_t * cm;
+  vnet_config_main_t * vcm;
+  char **feature_start_nodes;
+  int feature_start_len;
 
-  for (cast = 0; cast < VNET_N_CAST; cast++)
+  for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
     {
-      ip_config_main_t * cm = &lm->rx_config_mains[cast];
-      vnet_config_main_t * vcm = &cm->config_main;
+      cm = &lm->feature_config_mains[cast];
+      vcm = &cm->config_main;
 
+      if (cast < VNET_IP_TX_FEAT)
+        {
+          feature_start_nodes = rx_feature_start_nodes;
+          feature_start_len = ARRAY_LEN(rx_feature_start_nodes);
+        }
+      else
+        {
+          feature_start_nodes = tx_feature_start_nodes;
+          feature_start_len = ARRAY_LEN(tx_feature_start_nodes);
+        }
+      
       if ((error = ip_feature_init_cast (vm, cm, vcm, 
                                          feature_start_nodes,
-                                         ARRAY_LEN(feature_start_nodes),
+                                         feature_start_len,
                                          cast,
                                          1 /* is_ip4 */)))
         return error;
     }
+
   return 0;
 }
 
@@ -1486,21 +1522,23 @@ ip4_sw_interface_add_del (vnet_main_t * vnm,
   u32 ci, cast;
   u32 feature_index;
 
-  for (cast = 0; cast < VNET_N_CAST; cast++)
+  for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
     {
-      ip_config_main_t * cm = &lm->rx_config_mains[cast];
+      ip_config_main_t * cm = &lm->feature_config_mains[cast];
       vnet_config_main_t * vcm = &cm->config_main;
 
       vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
       ci = cm->config_index_by_sw_if_index[sw_if_index];
 
-      if (cast == VNET_UNICAST)
+      if (cast == VNET_IP_RX_UNICAST_FEAT)
         feature_index = im->ip4_unicast_rx_feature_lookup;
-      else
+      else if (cast == VNET_IP_RX_MULTICAST_FEAT)
         feature_index = im->ip4_multicast_rx_feature_lookup;
+      else
+        feature_index = im->ip4_tx_feature_interface_output;
 
       if (is_add)
-       ci = vnet_config_add_feature (vm, vcm,
+        ci = vnet_config_add_feature (vm, vcm, 
                                      ci,
                                       feature_index,
                                      /* config data */ 0,
@@ -1513,6 +1551,9 @@ ip4_sw_interface_add_del (vnet_main_t * vnm,
                                      /* # bytes of config data */ 0);
 
       cm->config_index_by_sw_if_index[sw_if_index] = ci;
+      /* 
+       * note: do not update the tx feature count here.
+       */
     }
 
   return /* no error */ 0;
@@ -1533,7 +1574,7 @@ VLIB_REGISTER_NODE (ip4_lookup_node) = {
   .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
 
 static uword
 ip4_indirect (vlib_main_t * vm,
@@ -1555,7 +1596,7 @@ VLIB_REGISTER_NODE (ip4_indirect_node) = {
   .n_next_nodes = 0,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect);
 
 
 /* Global IP4 main. */
@@ -1825,7 +1866,7 @@ VLIB_REGISTER_NODE (ip4_drop_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
 
 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
   .function = ip4_punt,
@@ -1840,7 +1881,7 @@ VLIB_REGISTER_NODE (ip4_punt_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
 
 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
   .function = ip4_miss,
@@ -1855,7 +1896,7 @@ VLIB_REGISTER_NODE (ip4_miss_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss);
 
 /* Compute TCP/UDP/ICMP4 checksum in software. */
 u16
@@ -2299,7 +2340,7 @@ VLIB_REGISTER_NODE (ip4_local_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
 
 void ip4_register_protocol (u32 protocol, u32 node_index)
 {
@@ -2644,6 +2685,7 @@ ip4_rewrite_inline (vlib_main_t * vm,
   u32 n_left_from, n_left_to_next, * to_next, next_index;
   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
   vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
+  ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
 
   n_left_from = frame->n_vectors;
   next_index = node->cached_next_index;
@@ -2661,6 +2703,7 @@ ip4_rewrite_inline (vlib_main_t * vm,
          u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
          u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
           u32 next0_override, next1_override;
+          u32 tx_sw_if_index0, tx_sw_if_index1;
       
           if (rewrite_for_locally_received_packets)
               next0_override = next1_override = 0;
@@ -2826,17 +2869,44 @@ ip4_rewrite_inline (vlib_main_t * vm,
             {
               p0->current_data -= rw_len0;
               p0->current_length += rw_len0;
-              p0->error = error_node->errors[error0];
+              tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
               vnet_buffer (p0)->sw_if_index[VLIB_TX] =
-                  adj0[0].rewrite_header.sw_if_index;
+                  tx_sw_if_index0;
+
+              if (PREDICT_FALSE 
+                  (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features, 
+                                    tx_sw_if_index0)))
+                {
+                  p0->current_config_index = 
+                    vec_elt (cm->config_index_by_sw_if_index, 
+                             tx_sw_if_index0);
+                  vnet_get_config_data (&cm->config_main,
+                                        &p0->current_config_index,
+                                        &next0,
+                                        /* # bytes of config data */ 0);
+                }
             }
           if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
             {
               p1->current_data -= rw_len1;
               p1->current_length += rw_len1;
-              p1->error = error_node->errors[error1];
+
+              tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
               vnet_buffer (p1)->sw_if_index[VLIB_TX] =
-                  adj1[0].rewrite_header.sw_if_index;
+                  tx_sw_if_index1;
+
+              if (PREDICT_FALSE 
+                  (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features, 
+                                    tx_sw_if_index1)))
+                {
+                  p1->current_config_index = 
+                    vec_elt (cm->config_index_by_sw_if_index, 
+                             tx_sw_if_index1);
+                  vnet_get_config_data (&cm->config_main,
+                                        &p1->current_config_index,
+                                        &next1,
+                                        /* # bytes of config data */ 0);
+                }
             }
 
          /* Guess we are only writing on simple Ethernet header. */
@@ -2856,6 +2926,7 @@ ip4_rewrite_inline (vlib_main_t * vm,
          ip4_header_t * ip0;
          u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
           u32 next0_override;
+          u32 tx_sw_if_index0;
       
           if (rewrite_for_locally_received_packets)
               next0_override = 0;
@@ -2957,10 +3028,23 @@ ip4_rewrite_inline (vlib_main_t * vm,
             {
               p0->current_data -= rw_len0;
               p0->current_length += rw_len0;
+              tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
 
-              vnet_buffer (p0)->sw_if_index[VLIB_TX] =
-                  adj0[0].rewrite_header.sw_if_index;
+              vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
               next0 = adj0[0].rewrite_header.next_index;
+
+              if (PREDICT_FALSE 
+                  (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features, 
+                                    tx_sw_if_index0)))
+                  {
+                    p0->current_config_index = 
+                      vec_elt (cm->config_index_by_sw_if_index, 
+                               tx_sw_if_index0);
+                    vnet_get_config_data (&cm->config_main,
+                                          &p0->current_config_index,
+                                          &next0,
+                                          /* # bytes of config data */ 0);
+                  }
             }
 
           if (rewrite_for_locally_received_packets)
@@ -3084,7 +3168,7 @@ VLIB_REGISTER_NODE (ip4_rewrite_node) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit);
 
 VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
   .function = ip4_rewrite_local,
@@ -3098,7 +3182,7 @@ VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
   .n_next_nodes = 0,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local);
 
 static clib_error_t *
 add_del_interface_table (vlib_main_t * vm,
@@ -3377,7 +3461,7 @@ VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
   .n_next_nodes = 0,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast);
 
 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
   .function = ip4_drop,
@@ -3602,3 +3686,44 @@ VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
     .function = set_ip_classify_command_fn,
 };
 
+
+#define TEST_CODE 1
+#if TEST_CODE > 0
+
+static clib_error_t *
+set_interface_output_feature_command_fn (vlib_main_t * vm,
+                                         unformat_input_t * input,
+                                         vlib_cli_command_t * cmd)
+{
+  vnet_main_t * vnm = vnet_get_main();
+  u32 sw_if_index = ~0;
+  int is_add = 1;
+  ip4_main_t * im = &ip4_main;
+  ip_lookup_main_t * lm = &im->lookup_main;
+
+  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, "del"))
+        is_add = 0;
+      else
+        break;
+    }
+
+  if (sw_if_index == ~0)
+    return clib_error_return (0, "unknown interface `%U'",
+                              format_unformat_error, input);
+
+  lm->tx_sw_if_has_ip_output_features =
+    clib_bitmap_set (lm->tx_sw_if_has_ip_output_features, sw_if_index, is_add);
+
+  return 0;
+}
+
+VLIB_CLI_COMMAND (set_interface_output_feature, static) = {
+  .path = "set interface output feature",
+  .function = set_interface_output_feature_command_fn,
+  .short_help = "set interface output feature <intfc>",
+};
+#endif /* TEST_CODE */
index 96a6866..2de2d47 100644 (file)
@@ -144,11 +144,11 @@ ip4_input_inline (vlib_main_t * vm,
          sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
          sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
 
-         cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
-         cast1 = ip4_address_is_multicast (&ip1->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
+         cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+         cast1 = ip4_address_is_multicast (&ip1->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
 
-         cm0 = lm->rx_config_mains + cast0;
-         cm1 = lm->rx_config_mains + cast1;
+         cm0 = lm->feature_config_mains + cast0;
+         cm1 = lm->feature_config_mains + cast1;
 
          p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
          p1->current_config_index = vec_elt (cm1->config_index_by_sw_if_index, sw_if_index1);
@@ -195,8 +195,8 @@ ip4_input_inline (vlib_main_t * vm,
          error1 = ip4_get_fragment_offset (ip1) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
 
          /* TTL < 1? Drop it. */
-         error0 = (ip0->ttl < 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
-         error1 = (ip1->ttl < 1 && cast1 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error1;
+         error0 = (ip0->ttl < 1 && cast0 == VNET_IP_RX_UNICAST_FEAT) ? IP4_ERROR_TIME_EXPIRED : error0;
+         error1 = (ip1->ttl < 1 && cast1 == VNET_IP_RX_UNICAST_FEAT) ? IP4_ERROR_TIME_EXPIRED : error1;
 
          /* Verify lengths. */
          ip_len0 = clib_net_to_host_u16 (ip0->length);
@@ -262,8 +262,8 @@ ip4_input_inline (vlib_main_t * vm,
 
          sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
 
-         cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
-         cm0 = lm->rx_config_mains + cast0;
+         cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+         cm0 = lm->feature_config_mains + cast0;
          p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
          vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
          vnet_get_config_data (&cm0->config_main,
@@ -294,7 +294,7 @@ ip4_input_inline (vlib_main_t * vm,
          error0 = ip4_get_fragment_offset (ip0) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
 
          /* TTL < 1? Drop it. */
-          error0 = (ip0->ttl < 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
+          error0 = (ip0->ttl < 1 && cast0 == VNET_IP_RX_UNICAST_FEAT) ? IP4_ERROR_TIME_EXPIRED : error0;
 
          /* Verify lengths. */
          ip_len0 = clib_net_to_host_u16 (ip0->length);
index 00faddf..ebfa767 100644 (file)
@@ -16,7 +16,8 @@
 #include <vnet/ip/ip_source_and_port_range_check.h>
 
 
-vlib_node_registration_t ip4_source_port_and_range_check;
+vlib_node_registration_t ip4_source_port_and_range_check_rx;
+vlib_node_registration_t ip4_source_port_and_range_check_tx;
 
 #define foreach_ip4_source_and_port_range_check_error                  \
   _(CHECK_FAIL, "ip4 source and port range check bad packets") \
@@ -42,7 +43,7 @@ typedef struct
   u32 bypass;
   u32 is_tcp;
   ip4_address_t src_addr;
-  u16 dst_port;
+  u16 port;
   u32 fib_index;
 } ip4_source_and_port_range_check_trace_t;
 
@@ -59,7 +60,7 @@ format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
   else
     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->is_tcp ? "TCP" : "UDP", (u32) t->port,
                (t->pass == 1) ? "PASS" : "FAIL");
   return s;
 }
@@ -127,12 +128,15 @@ check_adj_port_range_x1 (ip_adjacency_t * adj, u16 dst_port, u32 next)
 }
 
 always_inline uword
-  ip4_source_and_port_range_check_inline
-  (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+ip4_source_and_port_range_check_inline (vlib_main_t * vm,
+                                       vlib_node_runtime_t * node,
+                                       vlib_frame_t * frame, int is_tx)
 {
   ip4_main_t *im = &ip4_main;
   ip_lookup_main_t *lm = &im->lookup_main;
-  ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *rx_cm =
+    &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
+  ip_config_main_t *tx_cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
   u32 n_left_from, *from, *to_next;
   u32 next_index;
   vlib_node_runtime_t *error_node = node;
@@ -196,12 +200,24 @@ always_inline uword
          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]));
+         if (is_tx)
+           {
+             c0 = vnet_get_config_data (&tx_cm->config_main,
+                                        &b0->current_config_index,
+                                        &next0, sizeof (c0[0]));
+             c1 = vnet_get_config_data (&tx_cm->config_main,
+                                        &b1->current_config_index,
+                                        &next1, sizeof (c1[0]));
+           }
+         else
+           {
+             c0 = vnet_get_config_data (&rx_cm->config_main,
+                                        &b0->current_config_index,
+                                        &next0, sizeof (c0[0]));
+             c1 = vnet_get_config_data (&rx_cm->config_main,
+                                        &b1->current_config_index,
+                                        &next1, sizeof (c1[0]));
+           }
 
          /* we can't use the default VRF here... */
          for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
@@ -210,12 +226,28 @@ always_inline uword
            }
 
 
-         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 (is_tx)
+           {
+             if (ip0->protocol == IP_PROTOCOL_UDP)
+               fib_index0 =
+                 c0->fib_index
+                 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
+             if (ip0->protocol == IP_PROTOCOL_TCP)
+               fib_index0 =
+                 c0->fib_index
+                 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
+           }
+         else
+           {
+             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))
            {
@@ -239,19 +271,35 @@ always_inline uword
              adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
 
              ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
-                                                              &ip0->
-                                                              src_address, 0
+                                                              &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 (is_tx)
+           {
+             if (ip1->protocol == IP_PROTOCOL_UDP)
+               fib_index1 =
+                 c1->fib_index
+                 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
+             if (ip1->protocol == IP_PROTOCOL_TCP)
+               fib_index1 =
+                 c1->fib_index
+                 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
+           }
+         else
+           {
+             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))
            {
@@ -275,8 +323,7 @@ always_inline uword
              adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
 
              ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
-                                                              &ip1->
-                                                              src_address,
+                                                              &ip1->src_address,
                                                               0));
              adj1 = ip_get_adjacency (lm, adj_index1);
            }
@@ -331,7 +378,7 @@ always_inline uword
              t->bypass = pass0;
              t->fib_index = fib_index0;
              t->src_addr.as_u32 = ip0->src_address.as_u32;
-             t->dst_port = (pass0 == 0) ?
+             t->port = (pass0 == 0) ?
                clib_net_to_host_u16 (udp0->dst_port) : 0;
              t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
            }
@@ -345,7 +392,7 @@ always_inline uword
              t->bypass = pass1;
              t->fib_index = fib_index1;
              t->src_addr.as_u32 = ip1->src_address.as_u32;
-             t->dst_port = (pass1 == 0) ?
+             t->port = (pass1 == 0) ?
                clib_net_to_host_u16 (udp1->dst_port) : 0;
              t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
            }
@@ -379,11 +426,23 @@ always_inline uword
            vec_elt (im->fib_index_by_sw_if_index,
                     vnet_buffer (b0)->sw_if_index[VLIB_RX]);
 
+         if (is_tx)
+           vlib_buffer_advance (b0, sizeof (ethernet_header_t));
+
          ip0 = vlib_buffer_get_current (b0);
 
-         c0 = vnet_get_config_data
-           (&cm->config_main, &b0->current_config_index,
-            &next0, sizeof (c0[0]));
+         if (is_tx)
+           {
+             c0 = vnet_get_config_data
+               (&tx_cm->config_main, &b0->current_config_index,
+                &next0, sizeof (c0[0]));
+           }
+         else
+           {
+             c0 = vnet_get_config_data
+               (&rx_cm->config_main, &b0->current_config_index,
+                &next0, sizeof (c0[0]));
+           }
 
          /* we can't use the default VRF here... */
          for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
@@ -392,12 +451,28 @@ always_inline uword
            }
 
 
-         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 (is_tx)
+           {
+             if (ip0->protocol == IP_PROTOCOL_UDP)
+               fib_index0 =
+                 c0->fib_index
+                 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
+             if (ip0->protocol == IP_PROTOCOL_TCP)
+               fib_index0 =
+                 c0->fib_index
+                 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
+           }
+         else
+           {
+             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 (fib_index0 != ~0)
            {
@@ -458,11 +533,14 @@ always_inline uword
              t->bypass = pass0;
              t->fib_index = fib_index0;
              t->src_addr.as_u32 = ip0->src_address.as_u32;
-             t->dst_port = (pass0 == 0) ?
+             t->port = (pass0 == 0) ?
                clib_net_to_host_u16 (udp0->dst_port) : 0;
              t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
            }
 
+         if (is_tx)
+           vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
+
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                           to_next, n_left_to_next,
                                           bi0, next0);
@@ -471,24 +549,63 @@ always_inline uword
       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);
+  if (is_tx)
+    vlib_node_increment_counter (vm, ip4_source_port_and_range_check_tx.index,
+                                IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
+                                good_packets);
+  else
+    vlib_node_increment_counter (vm, ip4_source_port_and_range_check_rx.index,
+                                IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
+                                good_packets);
   return frame->n_vectors;
 }
 
 static uword
-ip4_source_and_port_range_check (vlib_main_t * vm,
-                                vlib_node_runtime_t * node,
-                                vlib_frame_t * frame)
+ip4_source_and_port_range_check_rx (vlib_main_t * vm,
+                                   vlib_node_runtime_t * node,
+                                   vlib_frame_t * frame)
 {
-  return ip4_source_and_port_range_check_inline (vm, node, frame);
+  return ip4_source_and_port_range_check_inline (vm, node, frame,
+                                                0 /* !is_tx */ );
 }
 
+static uword
+ip4_source_and_port_range_check_tx (vlib_main_t * vm,
+                                   vlib_node_runtime_t * node,
+                                   vlib_frame_t * frame)
+{
+  return ip4_source_and_port_range_check_inline (vm, node, frame,
+                                                1 /* is_tx */ );
+}
+
+/* Note: Calling same function for both RX and TX nodes
+   as always checking dst_port, although
+   if this changes can easily make new function
+*/
+
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
-  .function = ip4_source_and_port_range_check,
-  .name = "ip4-source-and-port-range-check",
+VLIB_REGISTER_NODE (ip4_source_port_and_range_check_rx) = {
+  .function = ip4_source_and_port_range_check_rx,
+  .name = "ip4-source-and-port-range-check-rx",
+  .vector_size = sizeof (u32),
+
+  .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
+  .error_strings = ip4_source_and_port_range_check_error_strings,
+
+  .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
+  .next_nodes = {
+    [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
+  },
+
+  .format_buffer = format_ip4_header,
+  .format_trace = format_ip4_source_and_port_range_check_trace,
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip4_source_port_and_range_check_tx) = {
+  .function = ip4_source_and_port_range_check_tx,
+  .name = "ip4-source-and-port-range-check-tx",
   .vector_size = sizeof (u32),
 
   .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
@@ -511,7 +628,9 @@ set_ip_source_and_port_range_check (vlib_main_t * vm,
 {
   ip4_main_t *im = &ip4_main;
   ip_lookup_main_t *lm = &im->lookup_main;
-  ip_config_main_t *rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *rx_cm =
+    &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
+  ip_config_main_t *tx_cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
   u32 ci;
   ip_source_and_port_range_check_config_t config;
   u32 feature_index;
@@ -523,17 +642,41 @@ set_ip_source_and_port_range_check (vlib_main_t * vm,
       config.fib_index[i] = fib_index[i];
     }
 
-  feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
+  /* For OUT we are in the RX path */
+  if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] != ~0) ||
+      (fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] != ~0))
+    {
+      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_add
+           ? vnet_config_add_feature
+           : vnet_config_del_feature)
+       (vm, &rx_cm->config_main, ci, feature_index, &config,
+        sizeof (config));
+      rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
+    }
+
+  /* For IN we are in the TX path */
+  if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] != ~0) ||
+      (fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] != ~0))
+    {
+      feature_index = im->ip4_unicast_tx_feature_source_and_port_range_check;
 
-  vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
+      vec_validate (tx_cm->config_index_by_sw_if_index, sw_if_index);
 
-  ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
-  ci = (is_add
-       ? vnet_config_add_feature
-       : vnet_config_del_feature)
-    (vm, &rx_cm->config_main, ci, feature_index, &config, sizeof (config));
-  rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
+      ci = tx_cm->config_index_by_sw_if_index[sw_if_index];
+      ci = (is_add
+           ? vnet_config_add_feature
+           : vnet_config_del_feature)
+       (vm, &tx_cm->config_main, ci, feature_index, &config,
+        sizeof (config));
+      tx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
 
+      vnet_config_update_tx_feature_count (lm, tx_cm, sw_if_index, is_add);
+    }
   return rv;
 }
 
@@ -1006,7 +1149,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> tcp-vrf <id>] [vrf <id>] [del]",
+  "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn> - <nn>] [vrf <id>] [del]",
 };
 /* *INDENT-ON* */
 
index 64b1e0a..1f8e721 100644 (file)
@@ -82,7 +82,7 @@ ip4_source_check_inline (vlib_main_t * vm,
 {
   ip4_main_t * im = &ip4_main;
   ip_lookup_main_t * lm = &im->lookup_main;
-  ip_config_main_t * cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   u32 n_left_from, * from, * to_next;
   u32 next_index;
   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
@@ -325,7 +325,7 @@ set_ip_source_check (vlib_main_t * vm,
   vnet_main_t * vnm = vnet_get_main();
   ip4_main_t * im = &ip4_main;
   ip_lookup_main_t * lm = &im->lookup_main;
-  ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t * rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   clib_error_t * error = 0;
   u32 sw_if_index, is_del, ci;
   ip4_source_check_config_t config;
index 3d6c9f4..0d5d8d0 100644 (file)
@@ -145,6 +145,7 @@ typedef struct ip6_main_t {
   /* feature path configuration lists */
   vnet_ip_feature_registration_t * next_uc_feature;
   vnet_ip_feature_registration_t * next_mc_feature;
+  vnet_ip_feature_registration_t * next_tx_feature;
 
   /* Built-in unicast feature path indices, see ip_feature_init_cast(...)  */
   u32 ip6_unicast_rx_feature_check_access;
@@ -157,9 +158,12 @@ typedef struct ip6_main_t {
   /* Built-in multicast feature path indices */
   u32 ip6_multicast_rx_feature_vpath;
   u32 ip6_multicast_rx_feature_lookup;
+  
+  /* Built-in tx feature path index */
+  u32 ip6_tx_feature_interface_output;
 
   /* Save results for show command */
-  char ** feature_nodes[VNET_N_CAST];
+  char ** feature_nodes[VNET_N_IP_FEAT];
 
   /* Seed for Jenkins hash used to compute ip6 flow hash. */
   u32 flow_hash_seed;
@@ -202,6 +206,19 @@ static void __vnet_add_feature_registration_mc_##x (void)       \
 }                                                               \
 __VA_ARGS__ vnet_ip_feature_registration_t mc_##x 
 
+#define VNET_IP6_TX_FEATURE_INIT(x,...)                         \
+  __VA_ARGS__ vnet_ip_feature_registration_t tx_##x;            \
+static void __vnet_add_feature_registration_tx_##x (void)       \
+  __attribute__((__constructor__)) ;                            \
+static void __vnet_add_feature_registration_tx_##x (void)       \
+{                                                               \
+  ip6_main_t * im = &ip6_main;                                  \
+  tx_##x.next = im->next_tx_feature;                            \
+  im->next_tx_feature = &tx_##x;                                \
+}                                                               \
+__VA_ARGS__ vnet_ip_feature_registration_t tx_##x 
+
+
 /* Global ip6 input node.  Errors get attached to ip6 input node. */
 extern vlib_node_registration_t ip6_input_node;
 extern vlib_node_registration_t ip6_rewrite_node;
index 1e4afa8..f79acf7 100644 (file)
@@ -1252,71 +1252,96 @@ VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
 /* Built-in ip6 unicast rx feature path definition */
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_inacl, static) = {
   .node_name = "ip6-inacl", 
-  .runs_before = {"ip6-policer-classify", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip6-policer-classify", 0},
   .feature_index = &ip6_main.ip6_unicast_rx_feature_check_access,
 };
 
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_policer_classify, static) = {
   .node_name = "ip6-policer-classify",
-  .runs_before = {"ipsec-input-ip6", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ipsec-input-ip6", 0},
   .feature_index = &ip6_main.ip6_unicast_rx_feature_policer_classify,
 };
 
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_ipsec, static) = {
   .node_name = "ipsec-input-ip6",
-  .runs_before = {"l2tp-decap", 0},
+  .runs_before = ORDER_CONSTRAINTS {"l2tp-decap", 0},
   .feature_index = &ip6_main.ip6_unicast_rx_feature_ipsec,
 };
 
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_l2tp, static) = {
   .node_name = "l2tp-decap",
-  .runs_before = {"vpath-input-ip6", 0},
+  .runs_before = ORDER_CONSTRAINTS {"vpath-input-ip6", 0},
   .feature_index = &ip6_main.ip6_unicast_rx_feature_l2tp_decap,
 };
 
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_vpath, static) = {
   .node_name = "vpath-input-ip6",
-  .runs_before = {"ip6-lookup", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip6-lookup", 0},
   .feature_index = &ip6_main.ip6_unicast_rx_feature_vpath,
 };
 
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_lookup, static) = {
   .node_name = "ip6-lookup",
-  .runs_before = {0}, /* not before any other features */
+  .runs_before = 0, /* not before any other features */
   .feature_index = &ip6_main.ip6_unicast_rx_feature_lookup,
 };
 
 /* Built-in ip6 multicast rx feature path definition (none now) */
-VNET_IP6_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
+VNET_IP6_MULTICAST_FEATURE_INIT (ip6_vpath_mc, static) = {
   .node_name = "vpath-input-ip6",
-  .runs_before = {"ip6-lookup", 0},
+  .runs_before = ORDER_CONSTRAINTS {"ip6-lookup", 0},
   .feature_index = &ip6_main.ip6_multicast_rx_feature_vpath,
 };
 
 VNET_IP6_MULTICAST_FEATURE_INIT (ip6_lookup, static) = {
   .node_name = "ip6-lookup",
-  .runs_before = {0}, /* not before any other features */
+  .runs_before = 0, /* not before any other features */
   .feature_index = &ip6_main.ip6_multicast_rx_feature_lookup,
 };
 
-static char * feature_start_nodes[] = 
+static char * rx_feature_start_nodes[] = 
   {"ip6-input"};
 
+static char * tx_feature_start_nodes[] = 
+  {"ip6-rewrite"};
+
+/* Built-in ip4 tx feature path definition */
+VNET_IP6_TX_FEATURE_INIT (interface_output, static) = {
+  .node_name = "interface-output",
+  .runs_before = 0, /* not before any other features */
+  .feature_index = &ip6_main.ip6_tx_feature_interface_output,
+};
+
 static clib_error_t *
 ip6_feature_init (vlib_main_t * vm, ip6_main_t * im)
 {
   ip_lookup_main_t * lm = &im->lookup_main;
   clib_error_t * error;
   vnet_cast_t cast;
+  ip_config_main_t * cm;
+  vnet_config_main_t * vcm;
+  char **feature_start_nodes;
+  int feature_start_len;
   
-  for (cast = 0; cast < VNET_N_CAST; cast++)
+  for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
     {
-      ip_config_main_t * cm = &lm->rx_config_mains[cast];
-      vnet_config_main_t * vcm = &cm->config_main;
+      cm = &lm->feature_config_mains[cast];
+      vcm = &cm->config_main;
       
+      if (cast < VNET_IP_TX_FEAT)
+        {
+          feature_start_nodes = rx_feature_start_nodes;
+          feature_start_len = ARRAY_LEN(rx_feature_start_nodes);
+        }
+      else
+        {
+          feature_start_nodes = tx_feature_start_nodes;
+          feature_start_len = ARRAY_LEN(tx_feature_start_nodes);
+        }
+
       if ((error = ip_feature_init_cast (vm, cm, vcm, 
                                          feature_start_nodes,
-                                         ARRAY_LEN(feature_start_nodes),
+                                         feature_start_len,
                                          cast,
                                          0 /* is_ip4 */)))
         return error;
@@ -1335,18 +1360,20 @@ ip6_sw_interface_add_del (vnet_main_t * vnm,
   u32 ci, cast;
   u32 feature_index;
 
-  for (cast = 0; cast < VNET_N_CAST; cast++)
+  for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
     {
-      ip_config_main_t * cm = &lm->rx_config_mains[cast];
+      ip_config_main_t * cm = &lm->feature_config_mains[cast];
       vnet_config_main_t * vcm = &cm->config_main;
 
       vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
       ci = cm->config_index_by_sw_if_index[sw_if_index];
 
-      if (cast == VNET_UNICAST)
+      if (cast == VNET_IP_RX_UNICAST_FEAT)
         feature_index = im->ip6_unicast_rx_feature_lookup;
-      else
+      else if (cast == VNET_IP_RX_MULTICAST_FEAT)
         feature_index = im->ip6_multicast_rx_feature_lookup;
+      else 
+        feature_index = im->ip6_tx_feature_interface_output;
 
       if (is_add)
        ci = vnet_config_add_feature (vm, vcm,
@@ -1362,6 +1389,9 @@ ip6_sw_interface_add_del (vnet_main_t * vnm,
                                      /* # bytes of config data */ 0);
 
       cm->config_index_by_sw_if_index[sw_if_index] = ci;
+      /* 
+       * note: do not update the tx feature count here.
+       */
     }
   return /* no error */ 0;
 }
@@ -1389,7 +1419,7 @@ VLIB_REGISTER_NODE (ip6_lookup_node) = {
   .next_nodes = IP6_LOOKUP_NEXT_NODES,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
 
 static uword
 ip6_indirect (vlib_main_t * vm,
@@ -1409,7 +1439,7 @@ VLIB_REGISTER_NODE (ip6_indirect_node) = {
   .n_next_nodes = 0,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_indirect_node, ip6_indirect)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_indirect_node, ip6_indirect);
 
 typedef struct {
   /* Adjacency taken. */
@@ -1617,7 +1647,7 @@ VLIB_REGISTER_NODE (ip6_drop_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
 
 VLIB_REGISTER_NODE (ip6_punt_node,static) = {
   .function = ip6_punt,
@@ -1632,7 +1662,7 @@ VLIB_REGISTER_NODE (ip6_punt_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
 
 VLIB_REGISTER_NODE (ip6_miss_node,static) = {
   .function = ip6_miss,
@@ -1647,7 +1677,7 @@ VLIB_REGISTER_NODE (ip6_miss_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_miss_node, ip6_miss)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_miss_node, ip6_miss);
 
 VLIB_REGISTER_NODE (ip6_multicast_node,static) = {
   .function = ip6_drop,
@@ -2027,7 +2057,7 @@ VLIB_REGISTER_NODE (ip6_local_node,static) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
 
 void ip6_register_protocol (u32 protocol, u32 node_index)
 {
@@ -2346,6 +2376,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
   u32 n_left_from, n_left_to_next, * to_next, next_index;
   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_input_node.index);
   vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
+  ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
 
   n_left_from = frame->n_vectors;
   next_index = node->cached_next_index;
@@ -2362,6 +2393,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
          ip6_header_t * ip0, * ip1;
          u32 pi0, rw_len0, next0, error0, adj_index0;
          u32 pi1, rw_len1, next1, error1, adj_index1;
+          u32 tx_sw_if_index0, tx_sw_if_index1;
       
          /* Prefetch next iteration. */
          {
@@ -2485,18 +2517,44 @@ ip6_rewrite_inline (vlib_main_t * vm,
               p0->current_data -= rw_len0;
               p0->current_length += rw_len0;
 
+              tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
               vnet_buffer (p0)->sw_if_index[VLIB_TX] =
-                  adj0[0].rewrite_header.sw_if_index;
-              next0 = adj0[0].rewrite_header.next_index;
+                  tx_sw_if_index0;
+
+              if (PREDICT_FALSE 
+                  (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features, 
+                                    tx_sw_if_index0)))
+                {
+                  p0->current_config_index = 
+                    vec_elt (cm->config_index_by_sw_if_index, 
+                             tx_sw_if_index0);
+                  vnet_get_config_data (&cm->config_main,
+                                        &p0->current_config_index,
+                                        &next0,
+                                        /* # bytes of config data */ 0);
+                }
             }
           if (PREDICT_TRUE(error1 == IP6_ERROR_NONE))
             {
               p1->current_data -= rw_len1;
               p1->current_length += rw_len1;
 
-             vnet_buffer (p1)->sw_if_index[VLIB_TX] =
-                  adj1[0].rewrite_header.sw_if_index;
-              next1 = adj1[0].rewrite_header.next_index;
+              tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
+              vnet_buffer (p1)->sw_if_index[VLIB_TX] =
+                  tx_sw_if_index1;
+
+              if (PREDICT_FALSE 
+                  (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features, 
+                                    tx_sw_if_index1)))
+                {
+                  p1->current_config_index = 
+                    vec_elt (cm->config_index_by_sw_if_index, 
+                             tx_sw_if_index1);
+                  vnet_get_config_data (&cm->config_main,
+                                        &p1->current_config_index,
+                                        &next1,
+                                        /* # bytes of config data */ 0);
+                }
             }
 
          /* Guess we are only writing on simple Ethernet header. */
@@ -2516,6 +2574,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
          ip6_header_t * ip0;
          u32 pi0, rw_len0;
          u32 adj_index0, next0, error0;
+          u32 tx_sw_if_index0;
       
          pi0 = to_next[0] = from[0];
 
@@ -2589,9 +2648,23 @@ ip6_rewrite_inline (vlib_main_t * vm,
              p0->current_data -= rw_len0;
              p0->current_length += rw_len0;
 
-             vnet_buffer (p0)->sw_if_index[VLIB_TX] =
-                  adj0[0].rewrite_header.sw_if_index;
+              tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
+
+              vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
               next0 = adj0[0].rewrite_header.next_index;
+
+              if (PREDICT_FALSE 
+                  (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features, 
+                                    tx_sw_if_index0)))
+                  {
+                    p0->current_config_index = 
+                      vec_elt (cm->config_index_by_sw_if_index, 
+                               tx_sw_if_index0);
+                    vnet_get_config_data (&cm->config_main,
+                                          &p0->current_config_index,
+                                          &next0,
+                                          /* # bytes of config data */ 0);
+                  }
             }
 
          p0->error = error_node->errors[error0];
@@ -2648,7 +2721,7 @@ VLIB_REGISTER_NODE (ip6_rewrite_node) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite_transit)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite_transit);
 
 VLIB_REGISTER_NODE (ip6_rewrite_local_node) = {
   .function = ip6_rewrite_local,
@@ -2662,7 +2735,7 @@ VLIB_REGISTER_NODE (ip6_rewrite_local_node) = {
   .n_next_nodes = 0,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_local_node, ip6_rewrite_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_local_node, ip6_rewrite_local);
 
 /*
  * Hop-by-Hop handling
@@ -2884,7 +2957,7 @@ VLIB_REGISTER_NODE (ip6_hop_by_hop_node) = {
   .n_next_nodes = 0,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
 
 static clib_error_t *
 ip6_hop_by_hop_init (vlib_main_t * vm)
@@ -3328,3 +3401,43 @@ ip6_config (vlib_main_t * vm, unformat_input_t * input)
 
 VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
 
+#define TEST_CODE 1
+#if TEST_CODE > 0
+
+static clib_error_t *
+set_interface_ip6_output_feature_command_fn (vlib_main_t * vm,
+                                             unformat_input_t * input,
+                                             vlib_cli_command_t * cmd)
+{
+  vnet_main_t * vnm = vnet_get_main();
+  u32 sw_if_index = ~0;
+  int is_add = 1;
+  ip6_main_t * im = &ip6_main;
+  ip_lookup_main_t * lm = &im->lookup_main;
+
+  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, "del"))
+        is_add = 0;
+      else
+        break;
+    }
+
+  if (sw_if_index == ~0)
+    return clib_error_return (0, "unknown interface `%U'",
+                              format_unformat_error, input);
+
+  lm->tx_sw_if_has_ip_output_features =
+    clib_bitmap_set (lm->tx_sw_if_has_ip_output_features, sw_if_index, is_add);
+
+  return 0;
+}
+
+VLIB_CLI_COMMAND (set_interface_ip6_output_feature, static) = {
+  .path = "set interface ip6 output feature",
+  .function = set_interface_ip6_output_feature_command_fn,
+  .short_help = "set interface output feature <intfc>",
+};
+#endif /* TEST_CODE */
index 05929c5..1579124 100644 (file)
@@ -143,11 +143,11 @@ ip6_input (vlib_main_t * vm,
          sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
          sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
 
-         cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
-         cast1 = ip6_address_is_multicast (&ip1->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
+         cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+         cast1 = ip6_address_is_multicast (&ip1->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
 
-         cm0 = lm->rx_config_mains + cast0;
-         cm1 = lm->rx_config_mains + cast1;
+         cm0 = lm->feature_config_mains + cast0;
+         cm1 = lm->feature_config_mains + cast1;
 
          p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
          p1->current_config_index = vec_elt (cm1->config_index_by_sw_if_index, sw_if_index1);
@@ -232,8 +232,8 @@ ip6_input (vlib_main_t * vm,
          ip0 = vlib_buffer_get_current (p0);
 
          sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
-         cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
-         cm0 = lm->rx_config_mains + cast0;
+         cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+         cm0 = lm->feature_config_mains + cast0;
          p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
          vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
 
index 5f0d58e..72deee4 100644 (file)
@@ -57,7 +57,7 @@ ip_feature_init_cast (vlib_main_t * vm,
   int a_index, b_index;
   int n_features;
   u32 * result = 0;
-  vnet_ip_feature_registration_t * this_reg, * first_reg;
+  vnet_ip_feature_registration_t * this_reg, * first_reg = 0;
   char ** feature_nodes = 0;
   hash_pair_t * hp;
   u8 ** keys_to_delete = 0;
@@ -67,20 +67,28 @@ ip_feature_init_cast (vlib_main_t * vm,
   index_by_name = hash_create_string (0, sizeof (uword));
   reg_by_index = hash_create (0, sizeof (uword));
 
-  if (cast == VNET_UNICAST)
+  if (cast == VNET_IP_RX_UNICAST_FEAT)
     {
       if (is_ip4)
         first_reg = im4->next_uc_feature;
       else
         first_reg = im6->next_uc_feature;
     }
-  else
+  else if (cast == VNET_IP_RX_MULTICAST_FEAT)
     {
       if (is_ip4)
         first_reg = im4->next_mc_feature;
       else
         first_reg = im6->next_mc_feature;
+    } 
+  else if (cast == VNET_IP_TX_FEAT)
+    {
+      if (is_ip4)
+        first_reg = im4->next_tx_feature;
+      else
+        first_reg = im6->next_tx_feature;
     }
+
   
   this_reg = first_reg;
 
@@ -95,8 +103,7 @@ ip_feature_init_cast (vlib_main_t * vm,
       vec_add1 (node_names, node_name);
 
       these_constraints = this_reg->runs_before;
-
-      while (these_constraints [0])
+      while (these_constraints && these_constraints [0])
         {
           this_constraint_c = these_constraints[0];
 
@@ -105,6 +112,19 @@ ip_feature_init_cast (vlib_main_t * vm,
           vec_add1 (constraints, constraint_tuple);
           these_constraints++;
         }
+
+      these_constraints = this_reg->runs_after;
+      while (these_constraints && these_constraints [0])
+        {
+          this_constraint_c = these_constraints[0];
+
+          constraint_tuple = format (0, "%s,%s%c", 
+                                     this_constraint_c, 
+                                     node_name, 0);
+          vec_add1 (constraints, constraint_tuple);
+          these_constraints++;
+        }
+
       this_reg = this_reg->next;
     }
 
@@ -220,10 +240,12 @@ ip_feature_init_cast (vlib_main_t * vm,
 }
 
 #define foreach_af_cast                         \
-_(4, VNET_UNICAST, "ip4 unicast")               \
-_(4, VNET_MULTICAST, "ip4 multicast")           \
-_(6, VNET_UNICAST, "ip6 unicast")               \
-_(6, VNET_MULTICAST, "ip6 multicast")
+_(4, VNET_IP_RX_UNICAST_FEAT, "ip4 unicast")               \
+_(4, VNET_IP_RX_MULTICAST_FEAT, "ip4 multicast")           \
+_(4, VNET_IP_TX_FEAT, "ip4 output")                 \
+_(6, VNET_IP_RX_UNICAST_FEAT, "ip6 unicast")               \
+_(6, VNET_IP_RX_MULTICAST_FEAT, "ip6 multicast")               \
+_(6, VNET_IP_TX_FEAT, "ip6 output")
 
 static clib_error_t *
 show_ip_features_command_fn (vlib_main_t * vm,
@@ -295,14 +317,14 @@ show_ip_interface_features_command_fn (vlib_main_t * vm,
       else
         lm = lm6;
 
-      for (cast = VNET_UNICAST; cast < VNET_N_CAST; cast++)
+      for (cast = VNET_IP_RX_UNICAST_FEAT; cast < VNET_N_IP_FEAT; cast++)
         {
-          cm = lm->rx_config_mains + cast;
+          cm = lm->feature_config_mains + cast;
           vcm = &cm->config_main;
       
           vlib_cli_output (vm, "\nipv%s %scast:", 
                            (af == 0) ? "4" : "6",
-                           cast == VNET_UNICAST ?
+                           cast == VNET_IP_RX_UNICAST_FEAT ?
                            "uni": "multi");
 
           current_config_index = vec_elt (cm->config_index_by_sw_if_index, 
index da2a005..3c78abc 100644 (file)
@@ -20,9 +20,12 @@ typedef struct _vnet_ip_feature_registration {
   struct _vnet_ip_feature_registration * next;
   char * node_name;
   u32 * feature_index;
-  char * runs_before[];
+  char ** runs_before;
+  char ** runs_after;
 } vnet_ip_feature_registration_t;
 
+#define ORDER_CONSTRAINTS (char*[])
+
 clib_error_t *
 ip_feature_init_cast (vlib_main_t * vm,
                       ip_config_main_t * cm,
index c0c1c95..02da664 100644 (file)
@@ -140,3 +140,25 @@ do {                                               \
 }
 
 VLIB_INIT_FUNCTION (ip_main_init);
+
+void
+vnet_config_update_tx_feature_count (ip_lookup_main_t * lm, 
+                                     ip_config_main_t * tx_cm, 
+                                     u32 sw_if_index, 
+                                     int is_add)
+{
+  ASSERT (tx_cm == &lm->feature_config_mains[VNET_IP_TX_FEAT]);
+
+  vec_validate (lm->tx_feature_count_by_sw_if_index, sw_if_index);
+
+  lm->tx_feature_count_by_sw_if_index[sw_if_index] += is_add ? 1 : -1;
+
+  ASSERT (lm->tx_feature_count_by_sw_if_index[sw_if_index] >= 0);
+
+  lm->tx_sw_if_has_ip_output_features =
+    clib_bitmap_set (lm->tx_sw_if_has_ip_output_features, sw_if_index,
+                     lm->tx_feature_count_by_sw_if_index[sw_if_index] > 0);
+}
+
+
+
index 2b682d2..fcd080a 100644 (file)
@@ -408,6 +408,12 @@ typedef struct ip_lookup_main_t {
   /** Adjacency by signature hash */
   uword * adj_index_by_signature;
 
+  /** any-tx-feature-enabled interface bitmap */
+  uword * tx_sw_if_has_ip_output_features;
+
+  /** count of enabled features, per sw_if_index, to maintain bitmap */
+  i16 * tx_feature_count_by_sw_if_index;
+
   /** Temporary vectors for looking up next hops in hash. */
   ip_multipath_next_hop_t * next_hop_hash_lookup_key;
   ip_multipath_next_hop_t * next_hop_hash_lookup_key_normalized;
@@ -444,8 +450,8 @@ typedef struct ip_lookup_main_t {
   /** First table index to use for this interface, ~0 => none */
   u32 * classify_table_index_by_sw_if_index;
 
-  /** rx/tx interface/feature configuration. */
-  ip_config_main_t rx_config_mains[VNET_N_CAST], tx_config_main;
+  /** rx unicast, multicast, tx interface/feature configuration. */
+  ip_config_main_t feature_config_mains[VNET_N_IP_FEAT];
 
   /** Number of bytes in a fib result.  Must be at least
      sizeof (uword).  First word is always adjacency index. */
index 1b3b9ff..3e34383 100644 (file)
@@ -78,7 +78,7 @@ ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id,
 
   /* IPv4 */
   lm = &ip4_main.lookup_main;
-  rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
 
   ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
 
@@ -89,7 +89,7 @@ ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id,
 
   /* IPv6 */
   lm = &ip6_main.lookup_main;
-  rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
 
   ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
 
index 8364e22..4087981 100644 (file)
@@ -185,7 +185,7 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm,
 {
   ip4_main_t *i4m = &ip4_main;
   ip_lookup_main_t *lm = &i4m->lookup_main;
-  ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   u32 n_left_from, *from, next_index, *to_next;
   ipsec_main_t *im = &ipsec_main;
 
@@ -316,7 +316,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (ipsec_input_ip4_node, ipsec_input_ip4_node_fn)
 {
   ip6_main_t *i6m = &ip6_main;
   ip_lookup_main_t *lm = &i6m->lookup_main;
-  ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   u32 n_left_from, *from, next_index, *to_next;
   ipsec_main_t *im = &ipsec_main;
 
index 1b97e71..dfd846a 100644 (file)
@@ -220,7 +220,8 @@ done:
          /* Go to next node on the ip6 configuration chain */
          ip6_main_t *im = &ip6_main;
          ip_lookup_main_t *lm = &im->lookup_main;
-         ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+         ip_config_main_t *cm =
+           &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
          ip6_l2tpv3_config_t *c0;
 
          vnet_get_config_data (&cm->config_main,
index 99443ce..a043483 100644 (file)
@@ -616,7 +616,8 @@ l2tpv3_interface_enable_disable (vnet_main_t * vnm,
 {
   ip6_main_t *im = &ip6_main;
   ip_lookup_main_t *lm = &im->lookup_main;
-  ip_config_main_t *rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+  ip_config_main_t *rx_cm =
+    &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
   u32 ci;
   ip6_l2tpv3_config_t config;
   u32 feature_index;
index 3bca6bf..31faef7 100644 (file)
 
 typedef enum
 {
-  VNET_UNICAST,
-  VNET_MULTICAST,
-  VNET_N_CAST,
+  VNET_IP_RX_UNICAST_FEAT,
+  VNET_IP_RX_MULTICAST_FEAT,
+  VNET_IP_TX_FEAT,
+  VNET_N_IP_FEAT,
 } vnet_cast_t;
 
 #include <vnet/unix/pcap.h>
index e142be6..93401ed 100644 (file)
@@ -1455,10 +1455,14 @@ vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t * mp)
   ip6_main_t *ip6m = &ip6_main;
   ip_lookup_main_t *ip4lm = &ip4m->lookup_main;
   ip_lookup_main_t *ip6lm = &ip6m->lookup_main;
-  ip_config_main_t *rx_cm4u = &ip4lm->rx_config_mains[VNET_UNICAST];
-  ip_config_main_t *rx_cm4m = &ip4lm->rx_config_mains[VNET_MULTICAST];
-  ip_config_main_t *rx_cm6u = &ip6lm->rx_config_mains[VNET_UNICAST];
-  ip_config_main_t *rx_cm6m = &ip6lm->rx_config_mains[VNET_MULTICAST];
+  ip_config_main_t *rx_cm4u =
+    &ip4lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
+  ip_config_main_t *rx_cm4m =
+    &ip4lm->feature_config_mains[VNET_IP_RX_MULTICAST_FEAT];
+  ip_config_main_t *rx_cm6u =
+    &ip6lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
+  ip_config_main_t *rx_cm6m =
+    &ip6lm->feature_config_mains[VNET_IP_RX_MULTICAST_FEAT];
 
   VALIDATE_SW_IF_INDEX (mp);