punt and drop features: 48/8548/6
authorNeale Ranns <nranns@cisco.com>
Mon, 31 Jul 2017 09:30:50 +0000 (02:30 -0700)
committerDamjan Marion <dmarion.lists@gmail.com>
Tue, 10 Oct 2017 16:42:39 +0000 (16:42 +0000)
 - new IPv4 and IPv6 feature arcs on the punt and drop nodes
 - new features:
   - redirect punted traffic to an interface and nexthop
   - police punted traffic.

Change-Id: I53be8bf4e06545add8a3619e462de5ffedd0a95c
Signed-off-by: Neale Ranns <nranns@cisco.com>
19 files changed:
src/vat/api_format.c
src/vnet.am
src/vnet/ip/ip.api
src/vnet/ip/ip4.h
src/vnet/ip/ip4_error.h
src/vnet/ip/ip4_forward.c
src/vnet/ip/ip4_punt_drop.c [new file with mode: 0644]
src/vnet/ip/ip6.h
src/vnet/ip/ip6_error.h
src/vnet/ip/ip6_forward.c
src/vnet/ip/ip6_punt_drop.c [new file with mode: 0644]
src/vnet/ip/ip_api.c
src/vnet/ip/ip_punt_drop.h [new file with mode: 0644]
src/vnet/policer/node_funcs.c
src/vnet/policer/police_inlines.h [new file with mode: 0644]
src/vnet/policer/policer_api.c
test/test_ip4.py
test/test_ip6.py
test/vpp_papi_provider.py

index ba1a791..7cd4b22 100644 (file)
@@ -18349,10 +18349,10 @@ api_policer_add_del (vat_main_t * vam)
   clib_memcpy (mp->name, name, vec_len (name));
   vec_free (name);
   mp->is_add = is_add;
-  mp->cir = cir;
-  mp->eir = eir;
-  mp->cb = cb;
-  mp->eb = eb;
+  mp->cir = ntohl (cir);
+  mp->eir = ntohl (eir);
+  mp->cb = clib_net_to_host_u64 (cb);
+  mp->eb = clib_net_to_host_u64 (eb);
   mp->rate_type = rate_type;
   mp->round_type = round_type;
   mp->type = type;
index 15b3467..ab09780 100644 (file)
@@ -333,6 +333,7 @@ libvnet_la_SOURCES +=                               \
  vnet/ip/ip46_cli.c                            \
  vnet/ip/ip4_format.c                          \
  vnet/ip/ip4_forward.c                         \
+ vnet/ip/ip4_punt_drop.c                       \
  vnet/ip/ip4_input.c                           \
  vnet/ip/ip4_mtrie.c                           \
  vnet/ip/ip4_pg.c                              \
@@ -340,6 +341,7 @@ libvnet_la_SOURCES +=                               \
  vnet/ip/ip4_source_check.c                    \
  vnet/ip/ip6_format.c                          \
  vnet/ip/ip6_forward.c                         \
+ vnet/ip/ip6_punt_drop.c                       \
  vnet/ip/ip6_hop_by_hop.c                      \
  vnet/ip/ip6_input.c                           \
  vnet/ip/ip6_neighbor.c                                \
index 69ab701..e302b1e 100644 (file)
@@ -547,6 +547,42 @@ define mfib_signal_details
   u8 ip_packet_data[256];
 };
 
+/** \brief IP punt policer
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_add - 1 to add neighbor, 0 to delete
+    @param is_ipv6 - 1 for IPv6 neighbor, 0 for IPv4
+    @param policer_index - Index of policer to use
+*/
+autoreply define ip_punt_police
+{
+  u32 client_index;
+  u32 context;
+  u32 policer_index;
+  u8 is_add;
+  u8 is_ip6;
+};
+
+/** \brief IP punt redirect
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_add - 1 to add neighbor, 0 to delete
+    @param is_ipv6 - 1 for IPv6 neighbor, 0 for IPv4
+    @param tx_sw_if_index - the TX interface to which traffic shoulde be
+                            redirected.
+    @param nh - The next-hop to redirect the traffic to.
+*/
+autoreply define ip_punt_redirect
+{
+  u32 client_index;
+  u32 context;
+  u32 rx_sw_if_index;
+  u32 tx_sw_if_index;
+  u8 is_add;
+  u8 is_ip6;
+  u8 nh[16];
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
index af0e6b9..4c5cc05 100644 (file)
@@ -281,6 +281,12 @@ int vnet_set_ip4_flow_hash (u32 table_id,
 int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
                                 u32 table_index);
 
+void ip4_punt_policer_add_del (u8 is_add, u32 policer_index);
+
+void ip4_punt_redirect_add (u32 rx_sw_if_index,
+                           u32 tx_sw_if_index, ip46_address_t * nh);
+void ip4_punt_redirect_del (u32 rx_sw_if_index);
+
 /* Compute flow hash.  We'll use it to select which adjacency to use for this
    flow.  And other things. */
 always_inline u32
index 95d12ec..d277563 100644 (file)
@@ -57,8 +57,8 @@
   _ (MTU_EXCEEDED, "ip4 MTU exceeded and DF set")                      \
   _ (DST_LOOKUP_MISS, "ip4 destination lookup miss")                   \
   _ (SRC_LOOKUP_MISS, "ip4 source lookup miss")                                \
-  _ (ADJACENCY_DROP, "ip4 adjacency drop")                             \
-  _ (ADJACENCY_PUNT, "ip4 adjacency punt")                             \
+  _ (DROP, "ip4 drop")                                                  \
+  _ (PUNT, "ip4 punt")                                                  \
                                                                        \
   /* Errors signalled by ip4-local. */                                 \
   _ (UNKNOWN_PROTOCOL, "unknown ip protocol")                          \
index 3aebb18..daffae4 100755 (executable)
  * This file contains the source code for IPv4 forwarding.
  */
 
-void
-ip4_forward_next_trace (vlib_main_t * vm,
-                       vlib_node_runtime_t * node,
-                       vlib_frame_t * frame,
-                       vlib_rx_or_tx_t which_adj_index);
-
 always_inline uword
 ip4_lookup_inline (vlib_main_t * vm,
                   vlib_node_runtime_t * node,
@@ -1387,68 +1381,6 @@ ip4_forward_next_trace (vlib_main_t * vm,
     }
 }
 
-static uword
-ip4_drop_or_punt (vlib_main_t * vm,
-                 vlib_node_runtime_t * node,
-                 vlib_frame_t * frame, ip4_error_t error_code)
-{
-  u32 *buffers = vlib_frame_vector_args (frame);
-  uword n_packets = frame->n_vectors;
-
-  vlib_error_drop_buffers (vm, node, buffers,
-                          /* stride */ 1,
-                          n_packets,
-                          /* next */ 0,
-                          ip4_input_node.index, error_code);
-
-  if (node->flags & VLIB_NODE_FLAG_TRACE)
-    ip4_forward_next_trace (vm, node, frame, VLIB_TX);
-
-  return n_packets;
-}
-
-static uword
-ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
-  return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
-}
-
-static uword
-ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
-  return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip4_drop_node, static) =
-{
-  .function = ip4_drop,
-  .name = "ip4-drop",
-  .vector_size = sizeof (u32),
-  .format_trace = format_ip4_forward_next_trace,
-  .n_next_nodes = 1,
-  .next_nodes = {
-    [0] = "error-drop",
-  },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
-
-VLIB_REGISTER_NODE (ip4_punt_node, static) =
-{
-  .function = ip4_punt,
-  .name = "ip4-punt",
-  .vector_size = sizeof (u32),
-  .format_trace = format_ip4_forward_next_trace,
-  .n_next_nodes = 1,
-  .next_nodes = {
-    [0] = "error-punt",
-  },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
-/* *INDENT-ON */
-
 /* Compute TCP/UDP/ICMP4 checksum in software. */
 u16
 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
@@ -1483,11 +1415,12 @@ ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
 
   n_bytes_left = n_this_buffer = payload_length_host_byte_order;
   data_this_buffer = (void *) ip0 + ip_header_length;
-  n_ip_bytes_this_buffer = p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
+  n_ip_bytes_this_buffer =
+    p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
   if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
     {
       n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
-         n_ip_bytes_this_buffer - ip_header_length : 0;
+       n_ip_bytes_this_buffer - ip_header_length : 0;
     }
   while (1)
     {
@@ -1870,8 +1803,8 @@ VLIB_REGISTER_NODE (ip4_local_node) =
   .n_next_nodes = IP_LOCAL_N_NEXT,
   .next_nodes =
   {
-    [IP_LOCAL_NEXT_DROP] = "error-drop",
-    [IP_LOCAL_NEXT_PUNT] = "error-punt",
+    [IP_LOCAL_NEXT_DROP] = "ip4-drop",
+    [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
     [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
   },
diff --git a/src/vnet/ip/ip4_punt_drop.c b/src/vnet/ip/ip4_punt_drop.c
new file mode 100644 (file)
index 0000000..72f36f3
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ip/ip.h>
+#include <vnet/ip/ip_punt_drop.h>
+#include <vnet/policer/policer.h>
+#include <vnet/policer/police_inlines.h>
+
+/* *INDENT-OFF* */
+VNET_FEATURE_ARC_INIT (ip4_punt) =
+{
+  .arc_name  = "ip4-punt",
+  .start_nodes = VNET_FEATURES ("ip4-punt"),
+};
+
+VNET_FEATURE_ARC_INIT (ip4_drop) =
+{
+  .arc_name  = "ip4-drop",
+  .start_nodes = VNET_FEATURES ("ip4-drop"),
+};
+/* *INDENT-ON* */
+
+u8 *
+format_ip_punt_policer_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  ip_punt_policer_trace_t *t = va_arg (*args, ip_punt_policer_trace_t *);
+
+  s = format (s, "policer_index %d next %d", t->policer_index, t->next);
+  return s;
+}
+
+ip_punt_policer_t ip4_punt_policer_cfg = {
+  .policer_index = ~0,
+};
+
+static char *ip4_punt_policer_error_strings[] = {
+#define _(sym,string) string,
+  foreach_ip_punt_policer_error
+#undef _
+};
+
+static uword
+ip4_punt_policer (vlib_main_t * vm,
+                 vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (ip_punt_policer (vm, node, frame,
+                          vnet_feat_arc_ip4_punt.feature_arc_index,
+                          ip4_punt_policer_cfg.policer_index));
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip4_punt_policer_node, static) = {
+  .function = ip4_punt_policer,
+  .name = "ip4-punt-policer",
+  .vector_size = sizeof (u32),
+  .n_next_nodes = IP_PUNT_POLICER_N_NEXT,
+  .format_trace = format_ip_punt_policer_trace,
+  .n_errors = ARRAY_LEN(ip4_punt_policer_error_strings),
+  .error_strings = ip4_punt_policer_error_strings,
+
+  .next_nodes = {
+    [IP_PUNT_POLICER_NEXT_DROP] = "ip4-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_policer_node,
+                              ip4_punt_policer);
+
+VNET_FEATURE_INIT (ip4_punt_policer_node, static) = {
+  .arc_name = "ip4-punt",
+  .node_name = "ip4-punt-policer",
+  .runs_before = VNET_FEATURES("ip4-punt-redirect"),
+};
+/* *INDENT-ON* */
+
+u8 *
+format_ip_punt_redirect_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  ip_punt_redirect_trace_t *t = va_arg (*args, ip_punt_redirect_trace_t *);
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_sw_interface_t *si;
+
+  si = vnet_get_sw_interface_safe (vnm, t->redirect.tx_sw_if_index);
+
+  if (NULL != si)
+    s = format (s, "via %U on %U using adj:%d",
+               format_ip46_address, &t->redirect.nh, IP46_TYPE_ANY,
+               format_vnet_sw_interface_name, vnm, si,
+               t->redirect.adj_index);
+  else
+    s = format (s, "via %U on %d using adj:%d",
+               format_ip46_address, &t->redirect.nh, IP46_TYPE_ANY,
+               t->redirect.tx_sw_if_index, t->redirect.adj_index);
+
+  return s;
+}
+
+/* *INDENT-OFF* */
+ip_punt_redirect_t ip4_punt_redirect_cfg = {
+  .any_rx_sw_if_index = {
+    .tx_sw_if_index = ~0,
+  },
+};
+/* *INDENT-ON* */
+
+
+#define foreach_ip4_punt_redirect_error         \
+_(DROP, "ip4 punt redirect drop")
+
+typedef enum
+{
+#define _(sym,str) IP4_PUNT_REDIRECT_ERROR_##sym,
+  foreach_ip4_punt_redirect_error
+#undef _
+    IP4_PUNT_REDIRECT_N_ERROR,
+} ip4_punt_redirect_error_t;
+
+static char *ip4_punt_redirect_error_strings[] = {
+#define _(sym,string) string,
+  foreach_ip4_punt_redirect_error
+#undef _
+};
+
+static uword
+ip4_punt_redirect (vlib_main_t * vm,
+                  vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (ip_punt_redirect (vm, node, frame,
+                           vnet_feat_arc_ip4_punt.feature_arc_index,
+                           &ip4_punt_redirect_cfg));
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip4_punt_redirect_node, static) = {
+  .function = ip4_punt_redirect,
+  .name = "ip4-punt-redirect",
+  .vector_size = sizeof (u32),
+  .n_next_nodes = IP_PUNT_REDIRECT_N_NEXT,
+  .format_trace = format_ip_punt_redirect_trace,
+  .n_errors = ARRAY_LEN(ip4_punt_redirect_error_strings),
+  .error_strings = ip4_punt_redirect_error_strings,
+
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [IP_PUNT_REDIRECT_NEXT_DROP] = "ip4-drop",
+    [IP_PUNT_REDIRECT_NEXT_TX] = "ip4-rewrite",
+    [IP_PUNT_REDIRECT_NEXT_ARP] = "ip4-arp",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_redirect_node,
+                              ip4_punt_redirect);
+
+VNET_FEATURE_INIT (ip4_punt_redirect_node, static) = {
+  .arc_name = "ip4-punt",
+  .node_name = "ip4-punt-redirect",
+  .runs_before = VNET_FEATURES("error-punt"),
+};
+/* *INDENT-ON* */
+
+static uword
+ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (node->flags & VLIB_NODE_FLAG_TRACE)
+    ip4_forward_next_trace (vm, node, frame, VLIB_TX);
+
+  return ip_drop_or_punt (vm, node, frame,
+                         vnet_feat_arc_ip4_drop.feature_arc_index);
+
+}
+
+static uword
+ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (node->flags & VLIB_NODE_FLAG_TRACE)
+    ip4_forward_next_trace (vm, node, frame, VLIB_TX);
+
+  return ip_drop_or_punt (vm, node, frame,
+                         vnet_feat_arc_ip4_punt.feature_arc_index);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip4_drop_node, static) =
+{
+  .function = ip4_drop,
+  .name = "ip4-drop",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ip4_forward_next_trace,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
+
+VLIB_REGISTER_NODE (ip4_punt_node, static) =
+{
+  .function = ip4_punt,
+  .name = "ip4-punt",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ip4_forward_next_trace,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-punt",
+  },
+};
+
+VNET_FEATURE_INIT (ip4_punt_end_of_arc, static) = {
+  .arc_name = "ip4-punt",
+  .node_name = "error-punt",
+  .runs_before = 0, /* not before any other features */
+};
+
+VNET_FEATURE_INIT (ip4_drop_end_of_arc, static) = {
+  .arc_name = "ip4-drop",
+  .node_name = "error-drop",
+  .runs_before = 0, /* not before any other features */
+};
+/* *INDENT-ON */
+
+void
+ip4_punt_policer_add_del (u8 is_add, u32 policer_index)
+{
+  ip4_punt_policer_cfg.policer_index = policer_index;
+
+  vnet_feature_enable_disable ("ip4-punt", "ip4-punt-policer",
+                               0, is_add, 0, 0);
+}
+
+static clib_error_t *
+ip4_punt_police_cmd (vlib_main_t * vm,
+                     unformat_input_t * main_input,
+                     vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+  u32 policer_index;
+  u8 is_add = 1;
+
+  policer_index = ~0;
+
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%d", &policer_index))
+        ;
+      else if (unformat (line_input, "del"))
+        is_add = 0;
+      else if (unformat (line_input, "add"))
+        is_add = 1;
+      else
+        {
+          error = unformat_parse_error (line_input);
+          goto done;
+        }
+    }
+
+  if (is_add && ~0 == policer_index)
+  {
+      error = clib_error_return (0, "expected policer index `%U'",
+                                 format_unformat_error, line_input);
+      goto done;
+  }
+  if (!is_add)
+      policer_index = ~0;
+
+  ip4_punt_policer_add_del(is_add, policer_index);
+
+done:
+  unformat_free (line_input);
+  return (error);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{set ip punt policer <INDEX>}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ip4_punt_policer_command, static) =
+{
+  .path = "ip punt policer",
+  .function = ip4_punt_police_cmd,
+  .short_help = "ip punt policer [add|del] <index>",
+};
+/* *INDENT-ON* */
+
+/*
+ * an uninitalised rx-redirect strcut used to pad the vector
+ */
+ip_punt_redirect_rx_t uninit_rx_redirect = {
+  .tx_sw_if_index = ~0,
+};
+
+void
+ip_punt_redirect_add (ip_punt_redirect_t * cfg,
+                     u32 rx_sw_if_index,
+                     ip_punt_redirect_rx_t * redirect,
+                     fib_protocol_t fproto, vnet_link_t linkt)
+{
+  ip_punt_redirect_rx_t *new;
+
+  if (~0 == rx_sw_if_index)
+    {
+      cfg->any_rx_sw_if_index = *redirect;
+      new = &cfg->any_rx_sw_if_index;
+    }
+  else
+    {
+      vec_validate_init_empty (cfg->redirect_by_rx_sw_if_index,
+                              rx_sw_if_index, uninit_rx_redirect);
+      cfg->redirect_by_rx_sw_if_index[rx_sw_if_index] = *redirect;
+      new = &cfg->redirect_by_rx_sw_if_index[rx_sw_if_index];
+    }
+
+  new->adj_index = adj_nbr_add_or_lock (fproto, linkt,
+                                       &redirect->nh,
+                                       redirect->tx_sw_if_index);
+}
+
+void
+ip_punt_redirect_del (ip_punt_redirect_t * cfg, u32 rx_sw_if_index)
+{
+  ip_punt_redirect_rx_t *old;
+
+  if (~0 == rx_sw_if_index)
+    {
+      old = &cfg->any_rx_sw_if_index;
+    }
+  else
+    {
+      old = &cfg->redirect_by_rx_sw_if_index[rx_sw_if_index];
+    }
+
+  adj_unlock (old->adj_index);
+  *old = uninit_rx_redirect;
+}
+
+void
+ip4_punt_redirect_add (u32 rx_sw_if_index,
+                      u32 tx_sw_if_index, ip46_address_t * nh)
+{
+  ip_punt_redirect_rx_t rx = {
+    .tx_sw_if_index = tx_sw_if_index,
+    .nh = *nh,
+  };
+
+  ip_punt_redirect_add (&ip4_punt_redirect_cfg,
+                       rx_sw_if_index, &rx, FIB_PROTOCOL_IP4, VNET_LINK_IP4);
+
+  vnet_feature_enable_disable ("ip4-punt", "ip4-punt-redirect", 0, 1, 0, 0);
+}
+
+void
+ip4_punt_redirect_del (u32 rx_sw_if_index)
+{
+  vnet_feature_enable_disable ("ip4-punt", "ip4-punt-redirect", 0, 0, 0, 0);
+
+  ip_punt_redirect_del (&ip4_punt_redirect_cfg, rx_sw_if_index);
+}
+
+static clib_error_t *
+ip4_punt_redirect_cmd (vlib_main_t * vm,
+                      unformat_input_t * main_input,
+                      vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+  u32 rx_sw_if_index;
+  u32 tx_sw_if_index;
+  ip46_address_t nh;
+  vnet_main_t *vnm;
+  u8 is_add;
+
+  is_add = 1;
+  vnm = vnet_get_main ();
+
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "del"))
+       is_add = 0;
+      else if (unformat (line_input, "add"))
+       is_add = 1;
+      else if (unformat (line_input, "rx all"))
+       rx_sw_if_index = ~0;
+      else if (unformat (line_input, "rx %U",
+                        unformat_vnet_sw_interface, vnm, &rx_sw_if_index))
+       ;
+      else if (unformat (line_input, "via %U %U",
+                        unformat_ip4_address,
+                        &nh.ip4,
+                        unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
+       ;
+      else if (unformat (line_input, "via %U",
+                        unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
+       memset (&nh, 0, sizeof (nh));
+      else
+       {
+         error = unformat_parse_error (line_input);
+         goto done;
+       }
+    }
+
+  if (is_add)
+    ip4_punt_redirect_add (rx_sw_if_index, tx_sw_if_index, &nh);
+  else
+    ip4_punt_redirect_del (rx_sw_if_index);
+
+done:
+  unformat_free (line_input);
+  return (error);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{set ip punt policer}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ip4_punt_redirect_command, static) =
+{
+  .path = "ip punt redirect",
+  .function = ip4_punt_redirect_cmd,
+  .short_help = "ip punt redirect [add|del] rx [<interface>|all] via [<nh>] <tx_interface>",
+};
+/* *INDENT-ON* */
+
+u8 *
+format_ip_punt_redirect (u8 * s, va_list * args)
+{
+  ip_punt_redirect_t *cfg = va_arg (*args, ip_punt_redirect_t *);
+  ip_punt_redirect_rx_t *rx;
+  u32 rx_sw_if_index;
+  vnet_main_t *vnm = vnet_get_main ();
+
+  vec_foreach_index (rx_sw_if_index, cfg->redirect_by_rx_sw_if_index)
+  {
+    rx = &cfg->redirect_by_rx_sw_if_index[rx_sw_if_index];
+    if (~0 != rx->tx_sw_if_index)
+      {
+       s = format (s, " rx %U redirect via %U %U\n",
+                   format_vnet_sw_interface_name, vnm,
+                   vnet_get_sw_interface (vnm, rx_sw_if_index),
+                   format_ip46_address, &rx->nh, IP46_TYPE_ANY,
+                   format_vnet_sw_interface_name, vnm,
+                   vnet_get_sw_interface (vnm, rx->tx_sw_if_index));
+      }
+  }
+  if (~0 != cfg->any_rx_sw_if_index.tx_sw_if_index)
+    {
+      s = format (s, " rx all redirect via %U %U\n",
+                 format_ip46_address, &cfg->any_rx_sw_if_index.nh,
+                 IP46_TYPE_ANY, format_vnet_sw_interface_name, vnm,
+                 vnet_get_sw_interface (vnm,
+                                        cfg->
+                                        any_rx_sw_if_index.tx_sw_if_index));
+    }
+
+  return (s);
+}
+
+static clib_error_t *
+ip4_punt_redirect_show_cmd (vlib_main_t * vm,
+                           unformat_input_t * main_input,
+                           vlib_cli_command_t * cmd)
+{
+  vlib_cli_output (vm, "%U", format_ip_punt_redirect, &ip4_punt_redirect_cfg);
+
+  return (NULL);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{set ip punt redierect}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_ip4_punt_redirect_command, static) =
+{
+  .path = "show ip punt redirect",
+  .function = ip4_punt_redirect_show_cmd,
+  .short_help = "show ip punt redirect [add|del] rx [<interface>|all] via [<nh>] <tx_interface>",
+  .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 8aef53a..033ecfc 100644 (file)
@@ -230,6 +230,11 @@ extern vlib_node_registration_t ip6_discover_neighbor_node;
 extern vlib_node_registration_t ip6_glean_node;
 extern vlib_node_registration_t ip6_midchain_node;
 
+extern void ip6_forward_next_trace (vlib_main_t * vm,
+                                   vlib_node_runtime_t * node,
+                                   vlib_frame_t * frame,
+                                   vlib_rx_or_tx_t which_adj_index);
+
 always_inline uword
 ip6_destination_matches_route (const ip6_main_t * im,
                               const ip6_address_t * key,
@@ -394,6 +399,11 @@ u8 *format_ip6_forward_next_trace (u8 * s, va_list * args);
 
 u32 ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0);
 
+void ip6_punt_policer_add_del (u8 is_add, u32 policer_index);
+void ip6_punt_redirect_add (u32 rx_sw_if_index,
+                           u32 tx_sw_if_index, ip46_address_t * nh);
+void ip6_punt_redirect_del (u32 rx_sw_if_index);
+
 int vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
                                 u32 table_index);
 extern vlib_node_registration_t ip6_lookup_node;
index a280716..7bb4b77 100644 (file)
@@ -54,8 +54,8 @@
   _ (MTU_EXCEEDED, "ip6 MTU exceeded")                                  \
   _ (DST_LOOKUP_MISS, "ip6 destination lookup miss")                    \
   _ (SRC_LOOKUP_MISS, "ip6 source lookup miss")                         \
-  _ (ADJACENCY_DROP, "ip6 adjacency drop")                              \
-  _ (ADJACENCY_PUNT, "ip6 adjacency punt")                              \
+  _ (DROP, "ip6 drop")                                                  \
+  _ (PUNT, "ip6 punt")                                                  \
                                                                         \
   /* Errors signalled by ip6-local. */                                  \
   _ (UNKNOWN_PROTOCOL, "unknown ip protocol")                           \
index 4f9ad85..f54b433 100644 (file)
  * This file contains the source code for IPv6 forwarding.
  */
 
-void
-ip6_forward_next_trace (vlib_main_t * vm,
-                       vlib_node_runtime_t * node,
-                       vlib_frame_t * frame,
-                       vlib_rx_or_tx_t which_adj_index);
 
 always_inline uword
 ip6_lookup_inline (vlib_main_t * vm,
@@ -1133,70 +1128,6 @@ ip6_forward_next_trace (vlib_main_t * vm,
     }
 }
 
-static uword
-ip6_drop_or_punt (vlib_main_t * vm,
-                 vlib_node_runtime_t * node,
-                 vlib_frame_t * frame, ip6_error_t error_code)
-{
-  u32 *buffers = vlib_frame_vector_args (frame);
-  uword n_packets = frame->n_vectors;
-
-  vlib_error_drop_buffers (vm, node, buffers,
-                          /* stride */ 1,
-                          n_packets,
-                          /* next */ 0,
-                          ip6_input_node.index, error_code);
-
-  if (node->flags & VLIB_NODE_FLAG_TRACE)
-    ip6_forward_next_trace (vm, node, frame, VLIB_TX);
-
-  return n_packets;
-}
-
-static uword
-ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
-  return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
-}
-
-static uword
-ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
-  return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_drop_node, static) =
-{
-  .function = ip6_drop,
-  .name = "ip6-drop",
-  .vector_size = sizeof (u32),
-  .format_trace = format_ip6_forward_next_trace,
-  .n_next_nodes = 1,
-  .next_nodes =
-  {
-    [0] = "error-drop",},
-};
-/* *INDENT-ON* */
-
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_punt_node, static) =
-{
-  .function = ip6_punt,
-  .name = "ip6-punt",
-  .vector_size = sizeof (u32),
-  .format_trace = format_ip6_forward_next_trace,
-  .n_next_nodes = 1,
-  .next_nodes =
-  {
-    [0] = "error-punt",},
-};
-/* *INDENT-ON* */
-
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
-
 /* Compute TCP/UDP/ICMP6 checksum in software. */
 u16
 ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
@@ -1649,8 +1580,8 @@ VLIB_REGISTER_NODE (ip6_local_node, static) =
   .n_next_nodes = IP_LOCAL_N_NEXT,
   .next_nodes =
   {
-    [IP_LOCAL_NEXT_DROP] = "error-drop",
-    [IP_LOCAL_NEXT_PUNT] = "error-punt",
+    [IP_LOCAL_NEXT_DROP] = "ip6-drop",
+    [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
     [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
   },
diff --git a/src/vnet/ip/ip6_punt_drop.c b/src/vnet/ip/ip6_punt_drop.c
new file mode 100644 (file)
index 0000000..a1f0ebe
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ip/ip.h>
+#include <vnet/ip/ip_punt_drop.h>
+#include <vnet/policer/policer.h>
+#include <vnet/policer/police_inlines.h>
+
+/* *INDENT-OFF* */
+VNET_FEATURE_ARC_INIT (ip6_punt) =
+{
+  .arc_name  = "ip6-punt",
+  .start_nodes = VNET_FEATURES ("ip6-punt"),
+};
+
+VNET_FEATURE_ARC_INIT (ip6_drop) =
+{
+  .arc_name  = "ip6-drop",
+  .start_nodes = VNET_FEATURES ("ip6-drop"),
+};
+/* *INDENT-ON* */
+
+ip_punt_policer_t ip6_punt_policer_cfg;
+
+static char *ip6_punt_policer_error_strings[] = {
+#define _(sym,string) string,
+  foreach_ip_punt_policer_error
+#undef _
+};
+
+static uword
+ip6_punt_policer (vlib_main_t * vm,
+                 vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (ip_punt_policer (vm, node, frame,
+                          vnet_feat_arc_ip6_punt.feature_arc_index,
+                          ip6_punt_policer_cfg.policer_index));
+}
+
+
+/* *INDENT-OFF* */
+
+VLIB_REGISTER_NODE (ip6_punt_policer_node, static) = {
+  .function = ip6_punt_policer,
+  .name = "ip6-punt-policer",
+  .vector_size = sizeof (u32),
+  .n_next_nodes = IP_PUNT_POLICER_N_NEXT,
+  .format_trace = format_ip_punt_policer_trace,
+  .n_errors = ARRAY_LEN(ip6_punt_policer_error_strings),
+  .error_strings = ip6_punt_policer_error_strings,
+
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [IP_PUNT_POLICER_NEXT_DROP] = "ip6-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_policer_node,
+                              ip6_punt_policer);
+
+VNET_FEATURE_INIT (ip6_punt_policer_node, static) = {
+  .arc_name = "ip6-punt",
+  .node_name = "ip6-punt-policer",
+  .runs_before = VNET_FEATURES("ip6-punt-redirect")
+};
+/* *INDENT-ON* */
+
+static uword
+ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (node->flags & VLIB_NODE_FLAG_TRACE)
+    ip6_forward_next_trace (vm, node, frame, VLIB_TX);
+
+  return ip_drop_or_punt (vm, node, frame,
+                         vnet_feat_arc_ip6_drop.feature_arc_index);
+
+}
+
+static uword
+ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (node->flags & VLIB_NODE_FLAG_TRACE)
+    ip6_forward_next_trace (vm, node, frame, VLIB_TX);
+
+  return ip_drop_or_punt (vm, node, frame,
+                         vnet_feat_arc_ip6_punt.feature_arc_index);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip6_drop_node, static) =
+{
+  .function = ip6_drop,
+  .name = "ip6-drop",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ip6_forward_next_trace,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
+
+VLIB_REGISTER_NODE (ip6_punt_node, static) =
+{
+  .function = ip6_punt,
+  .name = "ip6-punt",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ip6_forward_next_trace,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-punt",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
+
+VNET_FEATURE_INIT (ip6_punt_end_of_arc, static) = {
+  .arc_name = "ip6-punt",
+  .node_name = "error-punt",
+  .runs_before = 0, /* not before any other features */
+};
+
+VNET_FEATURE_INIT (ip6_drop_end_of_arc, static) = {
+  .arc_name = "ip6-drop",
+  .node_name = "error-drop",
+  .runs_before = 0, /* not before any other features */
+};
+/* *INDENT-ON */
+
+void
+ip6_punt_policer_add_del (u8 is_add, u32 policer_index)
+{
+  ip6_punt_policer_cfg.policer_index = policer_index;
+
+  vnet_feature_enable_disable ("ip6-punt", "ip6-punt-policer",
+                               0, is_add, 0, 0);
+}
+
+static clib_error_t *
+ip6_punt_police_cmd (vlib_main_t * vm,
+                     unformat_input_t * main_input,
+                     vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+  u32 policer_index;
+  u8 is_add = 1;
+
+  policer_index = ~0;
+
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%d", &policer_index))
+        ;
+      else if (unformat (line_input, "del"))
+        is_add = 0;
+      else if (unformat (line_input, "add"))
+        is_add = 1;
+      else
+        {
+          error = unformat_parse_error (line_input);
+          goto done;
+        }
+    }
+
+  if (is_add && ~0 == policer_index)
+  {
+      error = clib_error_return (0, "expected policer index `%U'",
+                                 format_unformat_error, line_input);
+      goto done;
+  }
+  if (!is_add)
+      policer_index = ~0;
+
+  ip6_punt_policer_add_del(is_add, policer_index);
+
+done:
+  unformat_free (line_input);
+  return (error);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{set ip punt policer <INDEX>}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ip6_punt_policer_command, static) =
+{
+  .path = "ip6 punt policer",
+  .function = ip6_punt_police_cmd,
+  .short_help = "ip6 punt policer [add|del] <index>",
+};
+/* *INDENT-ON* */
+
+ip_punt_redirect_t ip6_punt_redirect_cfg = {
+  .any_rx_sw_if_index = {
+                        .tx_sw_if_index = ~0,
+                        }
+  ,
+};
+
+#define foreach_ip6_punt_redirect_error         \
+_(DROP, "ip6 punt redirect drop")
+
+typedef enum
+{
+#define _(sym,str) IP6_PUNT_REDIRECT_ERROR_##sym,
+  foreach_ip6_punt_redirect_error
+#undef _
+    IP6_PUNT_REDIRECT_N_ERROR,
+} ip6_punt_redirect_error_t;
+
+static char *ip6_punt_redirect_error_strings[] = {
+#define _(sym,string) string,
+  foreach_ip6_punt_redirect_error
+#undef _
+};
+
+static uword
+ip6_punt_redirect (vlib_main_t * vm,
+                  vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (ip_punt_redirect (vm, node, frame,
+                           vnet_feat_arc_ip6_punt.feature_arc_index,
+                           &ip6_punt_redirect_cfg));
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip6_punt_redirect_node, static) = {
+  .function = ip6_punt_redirect,
+  .name = "ip6-punt-redirect",
+  .vector_size = sizeof (u32),
+  .n_next_nodes = IP_PUNT_REDIRECT_N_NEXT,
+  .format_trace = format_ip_punt_redirect_trace,
+  .n_errors = ARRAY_LEN(ip6_punt_redirect_error_strings),
+  .error_strings = ip6_punt_redirect_error_strings,
+
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [IP_PUNT_REDIRECT_NEXT_DROP] = "ip6-drop",
+    [IP_PUNT_REDIRECT_NEXT_TX] = "ip6-rewrite",
+    [IP_PUNT_REDIRECT_NEXT_ARP] = "ip6-discover-neighbor",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_redirect_node,
+                              ip6_punt_redirect);
+
+VNET_FEATURE_INIT (ip6_punt_redirect_node, static) = {
+  .arc_name = "ip6-punt",
+  .node_name = "ip6-punt-redirect",
+  .runs_before = VNET_FEATURES("error-punt")
+};
+/* *INDENT-ON* */
+
+void
+ip6_punt_redirect_add (u32 rx_sw_if_index,
+                      u32 tx_sw_if_index, ip46_address_t * nh)
+{
+  ip_punt_redirect_rx_t rx = {
+    .tx_sw_if_index = tx_sw_if_index,
+    .nh = *nh,
+  };
+
+  ip_punt_redirect_add (&ip6_punt_redirect_cfg,
+                       rx_sw_if_index, &rx, FIB_PROTOCOL_IP6, VNET_LINK_IP6);
+
+  vnet_feature_enable_disable ("ip6-punt", "ip6-punt-redirect", 0, 1, 0, 0);
+}
+
+void
+ip6_punt_redirect_del (u32 rx_sw_if_index)
+{
+  vnet_feature_enable_disable ("ip6-punt", "ip6-punt-redirect", 0, 0, 0, 0);
+
+  ip_punt_redirect_del (&ip6_punt_redirect_cfg, rx_sw_if_index);
+}
+
+static clib_error_t *
+ip6_punt_redirect_cmd (vlib_main_t * vm,
+                      unformat_input_t * main_input,
+                      vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+  u32 rx_sw_if_index;
+  u32 tx_sw_if_index;
+  ip46_address_t nh;
+  vnet_main_t *vnm;
+  u8 is_add;
+
+  is_add = 1;
+  vnm = vnet_get_main ();
+
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "del"))
+       is_add = 0;
+      else if (unformat (line_input, "add"))
+       is_add = 1;
+      else if (unformat (line_input, "rx all"))
+       rx_sw_if_index = ~0;
+      else if (unformat (line_input, "rx %U",
+                        unformat_vnet_sw_interface, vnm, &rx_sw_if_index))
+       ;
+      else if (unformat (line_input, "via %U %U",
+                        unformat_ip6_address,
+                        &nh.ip6,
+                        unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
+       ;
+      else if (unformat (line_input, "via %U",
+                        unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
+       memset (&nh, 0, sizeof (nh));
+      else
+       {
+         error = unformat_parse_error (line_input);
+         goto done;
+       }
+    }
+
+  if (is_add)
+    ip6_punt_redirect_add (rx_sw_if_index, tx_sw_if_index, &nh);
+  else
+    ip6_punt_redirect_del (rx_sw_if_index);
+
+done:
+  unformat_free (line_input);
+  return (error);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{set ip punt policer <INDEX>}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (ip6_punt_redirect_command, static) =
+{
+  .path = "ip6 punt redirect",
+  .function = ip6_punt_redirect_cmd,
+  .short_help = "ip6 punt redirect [add|del] rx [<interface>|all] via [<nh>] <tx_interface>",
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+ip6_punt_redirect_show_cmd (vlib_main_t * vm,
+                           unformat_input_t * main_input,
+                           vlib_cli_command_t * cmd)
+{
+  vlib_cli_output (vm, "%U", format_ip_punt_redirect, &ip6_punt_redirect_cfg);
+
+  return (NULL);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{set ip punt policer <INDEX>}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_ip6_punt_redirect_command, static) =
+{
+  .path = "show ip6 punt redirect",
+  .function = ip6_punt_redirect_show_cmd,
+  .short_help = "show ip6 punt redirect [add|del] rx [<interface>|all] via [<nh>] <tx_interface>",
+  .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 4d4daac..d9ec4b4 100644 (file)
@@ -70,6 +70,8 @@ _(IP_DUMP, ip_dump)                                                     \
 _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del)                             \
 _(IP_ADD_DEL_ROUTE, ip_add_del_route)                                   \
 _(IP_TABLE_ADD_DEL, ip_table_add_del)                                   \
+_(IP_PUNT_POLICE, ip_punt_police)                                       \
+_(IP_PUNT_REDIRECT, ip_punt_redirect)                                   \
 _(SET_IP_FLOW_HASH,set_ip_flow_hash)                                    \
 _(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config)           \
 _(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix)           \
@@ -647,6 +649,64 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
   vec_free (api_rpaths);
 }
 
+static void
+vl_api_ip_punt_police_t_handler (vl_api_ip_punt_police_t * mp,
+                                vlib_main_t * vm)
+{
+  vl_api_ip_punt_police_reply_t *rmp;
+  int rv = 0;
+
+  if (mp->is_ip6)
+    ip6_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
+  else
+    ip4_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
+
+  REPLY_MACRO (VL_API_IP_PUNT_POLICE_REPLY);
+}
+
+static void
+vl_api_ip_punt_redirect_t_handler (vl_api_ip_punt_redirect_t * mp,
+                                  vlib_main_t * vm)
+{
+  vl_api_ip_punt_redirect_reply_t *rmp;
+  int rv = 0;
+
+  if (mp->is_add)
+    {
+      ip46_address_t nh;
+
+      memset (&nh, 0, sizeof (nh));
+
+      if (mp->is_ip6)
+       {
+         memcpy (&nh.ip6, mp->nh, sizeof (nh.ip6));
+
+         ip6_punt_redirect_add (ntohl (mp->rx_sw_if_index),
+                                ntohl (mp->tx_sw_if_index), &nh);
+       }
+      else
+       {
+         memcpy (&nh.ip4, mp->nh, sizeof (nh.ip4));
+
+         ip4_punt_redirect_add (ntohl (mp->rx_sw_if_index),
+                                ntohl (mp->tx_sw_if_index), &nh);
+       }
+    }
+  else
+    {
+      if (mp->is_ip6)
+       {
+         ip6_punt_redirect_del (ntohl (mp->rx_sw_if_index));
+       }
+      else
+       {
+         ip4_punt_redirect_del (ntohl (mp->rx_sw_if_index));
+       }
+    }
+
+  REPLY_MACRO (VL_API_IP_PUNT_REDIRECT_REPLY);
+}
+
 static void
 vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
                                      vlib_main_t * vm)
diff --git a/src/vnet/ip/ip_punt_drop.h b/src/vnet/ip/ip_punt_drop.h
new file mode 100644 (file)
index 0000000..7ba65e1
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __IP_PUNT_DROP_H__
+#define __IP_PUNT_DROP_H__
+
+#include <vnet/ip/ip.h>
+#include <vnet/policer/policer.h>
+#include <vnet/policer/police_inlines.h>
+
+/**
+ * IP4 punt policer configuration
+ *   we police the punt rate to prevent overloading the host
+ */
+typedef struct ip_punt_policer_t_
+{
+  u32 policer_index;
+} ip_punt_policer_t;
+
+typedef enum ip_punt_policer_next_t_
+{
+  IP_PUNT_POLICER_NEXT_DROP,
+  IP_PUNT_POLICER_N_NEXT,
+} ip_punt_policer_next_t;
+
+typedef struct ip_punt_policer_trace_t_
+{
+  u32 policer_index;
+  u32 next;
+} ip_punt_policer_trace_t;
+
+#define foreach_ip_punt_policer_error          \
+_(DROP, "ip punt policer drop")
+
+typedef enum
+{
+#define _(sym,str) IP_PUNT_POLICER_ERROR_##sym,
+  foreach_ip_punt_policer_error
+#undef _
+    IP4_PUNT_POLICER_N_ERROR,
+} ip_punt_policer_error_t;
+
+extern u8 *format_ip_punt_policer_trace (u8 * s, va_list * args);
+
+/**
+ * IP punt policing node function
+ */
+always_inline uword
+ip_punt_policer (vlib_main_t * vm,
+                vlib_node_runtime_t * node,
+                vlib_frame_t * frame, u8 arc_index, u32 policer_index)
+{
+  u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
+  u64 time_in_policer_periods;
+  vnet_feature_main_t *fm = &feature_main;
+  vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
+
+  time_in_policer_periods =
+    clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         vlib_buffer_t *b0, *b1;
+         u32 next0, next1;
+         u8 act0, act1;
+         u32 bi0, bi1;
+
+         next0 = next1 = 0;
+         bi0 = to_next[0] = from[0];
+         bi1 = to_next[1] = from[1];
+
+         from += 2;
+         n_left_from -= 2;
+         to_next += 2;
+         n_left_to_next -= 2;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+
+         vnet_get_config_data (&cm->config_main,
+                               &b0->current_config_index, &next0, 0);
+         vnet_get_config_data (&cm->config_main,
+                               &b1->current_config_index, &next1, 0);
+
+         act0 = vnet_policer_police (vm, b0,
+                                     policer_index,
+                                     time_in_policer_periods,
+                                     POLICE_CONFORM);
+         act1 = vnet_policer_police (vm, b1,
+                                     policer_index,
+                                     time_in_policer_periods,
+                                     POLICE_CONFORM);
+
+         if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP))
+           {
+             next0 = IP_PUNT_POLICER_NEXT_DROP;
+             b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+           }
+         if (PREDICT_FALSE (act1 == SSE2_QOS_ACTION_DROP))
+           {
+             next1 = IP_PUNT_POLICER_NEXT_DROP;
+             b1->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+           }
+
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ip_punt_policer_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->next = next0;
+             t->policer_index = policer_index;
+           }
+         if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ip_punt_policer_trace_t *t =
+               vlib_add_trace (vm, node, b1, sizeof (*t));
+             t->next = next1;
+             t->policer_index = policer_index;
+           }
+         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;
+         u32 next0;
+         u32 bi0;
+         u8 act0;
+
+         next0 = 0;
+         bi0 = to_next[0] = from[0];
+
+         from += 1;
+         n_left_from -= 1;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         vnet_get_config_data (&cm->config_main,
+                               &b0->current_config_index, &next0, 0);
+
+         act0 = vnet_policer_police (vm, b0,
+                                     policer_index,
+                                     time_in_policer_periods,
+                                     POLICE_CONFORM);
+         if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP))
+           {
+             next0 = IP_PUNT_POLICER_NEXT_DROP;
+             b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+           }
+
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ip_punt_policer_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->next = next0;
+             t->policer_index = policer_index;
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  return frame->n_vectors;
+}
+
+/**
+ * IP4 punt redirect per-rx interface configuration
+ *   redirect punted traffic to another location.
+ */
+typedef struct ip_punt_redirect_rx_t_
+{
+  /**
+   * The next-hop to send redirected packets to
+   */
+  ip46_address_t nh;
+
+  /**
+   * the TX interface to send redirected packets
+   */
+  u32 tx_sw_if_index;
+
+  /**
+   * redirect forwarding adjacency
+   */
+  adj_index_t adj_index;
+} ip_punt_redirect_rx_t;
+
+/**
+ * IP punt redirect configuration
+ */
+typedef struct ip_punt_redirect_t_
+{
+    /**
+     * any RX interface redirect
+     */
+  ip_punt_redirect_rx_t any_rx_sw_if_index;
+
+    /**
+    * per-RX interface configuration
+    */
+  ip_punt_redirect_rx_t *redirect_by_rx_sw_if_index;
+} ip_punt_redirect_t;
+
+/**
+ * IP punt redirect next nodes
+ */
+typedef enum ip_punt_redirect_next_t_
+{
+  IP_PUNT_REDIRECT_NEXT_DROP,
+  IP_PUNT_REDIRECT_NEXT_TX,
+  IP_PUNT_REDIRECT_NEXT_ARP,
+  IP_PUNT_REDIRECT_N_NEXT,
+} ip_punt_redirect_next_t;
+
+/**
+ * IP Punt redirect trace
+ */
+typedef struct ip4_punt_redirect_trace_t_
+{
+  ip_punt_redirect_rx_t redirect;
+  u32 next;
+} ip_punt_redirect_trace_t;
+
+/**
+ * Add a punt redirect entry
+ */
+extern void ip_punt_redirect_add (ip_punt_redirect_t * cfg,
+                                 u32 rx_sw_if_index,
+                                 ip_punt_redirect_rx_t * redirect,
+                                 fib_protocol_t fproto, vnet_link_t linkt);
+extern void ip_punt_redirect_del (ip_punt_redirect_t * cfg,
+                                 u32 rx_sw_if_index);
+extern u8 *format_ip_punt_redirect (u8 * s, va_list * args);
+
+extern u8 *format_ip_punt_redirect_trace (u8 * s, va_list * args);
+
+always_inline u32
+ip_punt_redirect_tx_via_adj (vlib_buffer_t * b0, adj_index_t ai)
+{
+  ip_adjacency_t *adj = adj_get (ai);
+  u32 next0;
+
+  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
+
+  switch (adj->lookup_next_index)
+    {
+    case IP_LOOKUP_NEXT_ARP:
+      next0 = IP_PUNT_REDIRECT_NEXT_ARP;
+      break;
+    case IP_LOOKUP_NEXT_REWRITE:
+      next0 = IP_PUNT_REDIRECT_NEXT_TX;
+      break;
+    default:
+      next0 = IP_PUNT_REDIRECT_NEXT_DROP;
+      break;
+    }
+
+  return (next0);
+}
+
+always_inline uword
+ip_punt_redirect (vlib_main_t * vm,
+                 vlib_node_runtime_t * node,
+                 vlib_frame_t * frame,
+                 u8 arc_index, ip_punt_redirect_t * redirect)
+{
+  u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
+  vnet_feature_main_t *fm = &feature_main;
+  vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 rx_sw_if_index0;
+         ip_punt_redirect_rx_t *rrx0;
+         vlib_buffer_t *b0;
+         u32 next0;
+         u32 bi0;
+
+         rrx0 = NULL;
+         next0 = 0;
+         bi0 = to_next[0] = from[0];
+
+         from += 1;
+         n_left_from -= 1;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         vnet_get_config_data (&cm->config_main,
+                               &b0->current_config_index, &next0, 0);
+
+         rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+         if (vec_len (redirect->redirect_by_rx_sw_if_index) >
+             rx_sw_if_index0)
+           {
+             rrx0 = &redirect->redirect_by_rx_sw_if_index[rx_sw_if_index0];
+             if (~0 != rrx0->tx_sw_if_index)
+               {
+                 next0 = ip_punt_redirect_tx_via_adj (b0, rrx0->adj_index);
+               }
+             else if (~0 != redirect->any_rx_sw_if_index.tx_sw_if_index)
+               {
+                 rrx0 = &redirect->any_rx_sw_if_index;
+                 next0 = ip_punt_redirect_tx_via_adj (b0, rrx0->adj_index);
+               }
+           }
+         else if (~0 != redirect->any_rx_sw_if_index.tx_sw_if_index)
+           {
+             rrx0 = &redirect->any_rx_sw_if_index;
+             next0 = ip_punt_redirect_tx_via_adj (b0, rrx0->adj_index);
+           }
+
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             ip_punt_redirect_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->next = next0;
+             if (rrx0)
+               t->redirect = *rrx0;
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  return frame->n_vectors;
+}
+
+always_inline uword
+ip_drop_or_punt (vlib_main_t * vm,
+                vlib_node_runtime_t * node,
+                vlib_frame_t * frame, u8 arc_index)
+{
+  u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from >= 8 && n_left_to_next >= 4)
+       {
+         vlib_buffer_t *b0, *b1, *b2, *b3;
+         u32 next0, next1, next2, next3;
+         u32 bi0, bi1, bi2, bi3;
+
+         next0 = next1 = next2 = next3 = 0;
+
+         /* Prefetch next iteration. */
+         {
+           vlib_buffer_t *p4, *p5, *p6, *p7;
+
+           p4 = vlib_get_buffer (vm, from[4]);
+           p5 = vlib_get_buffer (vm, from[5]);
+           p6 = vlib_get_buffer (vm, from[6]);
+           p7 = vlib_get_buffer (vm, from[7]);
+
+           vlib_prefetch_buffer_header (p4, LOAD);
+           vlib_prefetch_buffer_header (p5, LOAD);
+           vlib_prefetch_buffer_header (p6, LOAD);
+           vlib_prefetch_buffer_header (p7, LOAD);
+         }
+
+         bi0 = to_next[0] = from[0];
+         bi1 = to_next[1] = from[1];
+         bi2 = to_next[2] = from[2];
+         bi3 = to_next[3] = from[3];
+
+         from += 4;
+         n_left_from -= 4;
+         to_next += 4;
+         n_left_to_next -= 4;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+         b2 = vlib_get_buffer (vm, bi2);
+         b3 = vlib_get_buffer (vm, bi3);
+
+         /* punt and drop features are not associated with a given interface
+          * so the special index 0 is used */
+         vnet_feature_arc_start (arc_index, 0, &next0, b0);
+         vnet_feature_arc_start (arc_index, 0, &next1, b1);
+         vnet_feature_arc_start (arc_index, 0, &next2, b2);
+         vnet_feature_arc_start (arc_index, 0, &next3, b3);
+
+         vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, bi1, bi2, bi3,
+                                          next0, next1, next2, next3);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         u32 next0;
+         u32 bi0;
+
+         next0 = 0;
+         bi0 = to_next[0] = from[0];
+
+         from += 1;
+         n_left_from -= 1;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         vnet_feature_arc_start (arc_index, 0, &next0, b0);
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  return frame->n_vectors;
+}
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index fd031d0..25cb420 100644 (file)
 #include <vlib/vlib.h>
 #include <vnet/vnet.h>
 #include <vnet/policer/policer.h>
+#include <vnet/policer/police_inlines.h>
 #include <vnet/ip/ip.h>
 #include <vnet/classify/policer_classify.h>
 #include <vnet/classify/vnet_classify.h>
 
-#define IP4_NON_DSCP_BITS 0x03
-#define IP4_DSCP_SHIFT    2
-#define IP6_NON_DSCP_BITS 0xf03fffff
-#define IP6_DSCP_SHIFT    22
 
 /* Dispatch functions meant to be instantiated elsewhere */
 
@@ -67,60 +64,6 @@ static char *vnet_policer_error_strings[] = {
 #undef _
 };
 
-static_always_inline void
-vnet_policer_mark (vlib_buffer_t * b, u8 dscp)
-{
-  ethernet_header_t *eh;
-  ip4_header_t *ip4h;
-  ip6_header_t *ip6h;
-  u16 type;
-
-  eh = (ethernet_header_t *) b->data;
-  type = clib_net_to_host_u16 (eh->type);
-
-  if (PREDICT_TRUE (type == ETHERNET_TYPE_IP4))
-    {
-      ip4h = (ip4_header_t *) & (b->data[sizeof (ethernet_header_t)]);;
-      ip4h->tos &= IP4_NON_DSCP_BITS;
-      ip4h->tos |= dscp << IP4_DSCP_SHIFT;
-      ip4h->checksum = ip4_header_checksum (ip4h);
-    }
-  else
-    {
-      if (PREDICT_TRUE (type == ETHERNET_TYPE_IP6))
-       {
-         ip6h = (ip6_header_t *) & (b->data[sizeof (ethernet_header_t)]);
-         ip6h->ip_version_traffic_class_and_flow_label &=
-           clib_host_to_net_u32 (IP6_NON_DSCP_BITS);
-         ip6h->ip_version_traffic_class_and_flow_label |=
-           clib_host_to_net_u32 (dscp << IP6_DSCP_SHIFT);
-       }
-    }
-}
-
-static_always_inline
-  u8 vnet_policer_police (vlib_main_t * vm,
-                         vlib_buffer_t * b,
-                         u32 policer_index,
-                         u64 time_in_policer_periods,
-                         policer_result_e packet_color)
-{
-  u8 act;
-  u32 len;
-  u32 col;
-  policer_read_response_type_st *pol;
-  vnet_policer_main_t *pm = &vnet_policer_main;
-
-  len = vlib_buffer_length_in_chain (vm, b);
-  pol = &pm->policers[policer_index];
-  col = vnet_police_packet (pol, len, packet_color, time_in_policer_periods);
-  act = pol->action[col];
-  if (PREDICT_TRUE (act == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
-    vnet_policer_mark (b, pol->mark_dscp[col]);
-
-  return act;
-}
-
 static inline uword
 vnet_policer_inline (vlib_main_t * vm,
                     vlib_node_runtime_t * node,
diff --git a/src/vnet/policer/police_inlines.h b/src/vnet/policer/police_inlines.h
new file mode 100644 (file)
index 0000000..64386e6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __POLICE_INLINES_H__
+#define __POLICE_INLINES_H__
+
+#include <vnet/policer/police.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+
+#define IP4_NON_DSCP_BITS 0x03
+#define IP4_DSCP_SHIFT    2
+#define IP6_NON_DSCP_BITS 0xf03fffff
+#define IP6_DSCP_SHIFT    22
+
+static_always_inline void
+vnet_policer_mark (vlib_buffer_t * b, u8 dscp)
+{
+  ethernet_header_t *eh;
+  ip4_header_t *ip4h;
+  ip6_header_t *ip6h;
+  u16 type;
+
+  eh = (ethernet_header_t *) b->data;
+  type = clib_net_to_host_u16 (eh->type);
+
+  if (PREDICT_TRUE (type == ETHERNET_TYPE_IP4))
+    {
+      ip4h = (ip4_header_t *) & (b->data[sizeof (ethernet_header_t)]);;
+      ip4h->tos &= IP4_NON_DSCP_BITS;
+      ip4h->tos |= dscp << IP4_DSCP_SHIFT;
+      ip4h->checksum = ip4_header_checksum (ip4h);
+    }
+  else
+    {
+      if (PREDICT_TRUE (type == ETHERNET_TYPE_IP6))
+       {
+         ip6h = (ip6_header_t *) & (b->data[sizeof (ethernet_header_t)]);
+         ip6h->ip_version_traffic_class_and_flow_label &=
+           clib_host_to_net_u32 (IP6_NON_DSCP_BITS);
+         ip6h->ip_version_traffic_class_and_flow_label |=
+           clib_host_to_net_u32 (dscp << IP6_DSCP_SHIFT);
+       }
+    }
+}
+
+static_always_inline u8
+vnet_policer_police (vlib_main_t * vm,
+                    vlib_buffer_t * b,
+                    u32 policer_index,
+                    u64 time_in_policer_periods,
+                    policer_result_e packet_color)
+{
+  u8 act;
+  u32 len;
+  u32 col;
+  policer_read_response_type_st *pol;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+
+  len = vlib_buffer_length_in_chain (vm, b);
+  pol = &pm->policers[policer_index];
+  col = vnet_police_packet (pol, len, packet_color, time_in_policer_periods);
+  act = pol->action[col];
+  if (PREDICT_TRUE (act == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
+    vnet_policer_mark (b, pol->mark_dscp[col]);
+
+  return act;
+}
+
+#endif // __POLICE_INLINES_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 67fb9a4..3dc2cdd 100644 (file)
@@ -63,10 +63,10 @@ vl_api_policer_add_del_t_handler (vl_api_policer_add_del_t * mp)
   cfg.rfc = mp->type;
   cfg.rnd_type = mp->round_type;
   cfg.rate_type = mp->rate_type;
-  cfg.rb.kbps.cir_kbps = mp->cir;
-  cfg.rb.kbps.eir_kbps = mp->eir;
-  cfg.rb.kbps.cb_bytes = mp->cb;
-  cfg.rb.kbps.eb_bytes = mp->eb;
+  cfg.rb.kbps.cir_kbps = ntohl (mp->cir);
+  cfg.rb.kbps.eir_kbps = ntohl (mp->eir);
+  cfg.rb.kbps.cb_bytes = clib_net_to_host_u64 (mp->cb);
+  cfg.rb.kbps.eb_bytes = clib_net_to_host_u64 (mp->eb);
   cfg.conform_action.action_type = mp->conform_action_type;
   cfg.conform_action.dscp = mp->conform_dscp;
   cfg.exceed_action.action_type = mp->exceed_action_type;
index 55d1673..5bd50ce 100644 (file)
@@ -11,7 +11,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, Dot1Q, ARP
-from scapy.layers.inet import IP, UDP, ICMP, icmptypes, icmpcodes
+from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
 from util import ppp
 from scapy.contrib.mpls import MPLS
 
@@ -1009,5 +1009,115 @@ class TestIPVlan0(VppTestCase):
         self.send_and_expect(self.pg0, pkts, self.pg1)
 
 
+class TestIPPunt(VppTestCase):
+    """ IPv4 Punt Police/Redirect """
+
+    def setUp(self):
+        super(TestIPPunt, self).setUp()
+
+        self.create_pg_interfaces(range(2))
+
+        for i in self.pg_interfaces:
+            i.admin_up()
+            i.config_ip4()
+            i.resolve_arp()
+
+    def tearDown(self):
+        super(TestIPPunt, self).tearDown()
+        for i in self.pg_interfaces:
+            i.unconfig_ip4()
+            i.admin_down()
+
+    def send_and_expect(self, input, pkts, output):
+        self.vapi.cli("clear trace")
+        input.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = output.get_capture(len(pkts))
+        return rx
+
+    def send_and_assert_no_replies(self, intf, pkts, remark):
+        self.vapi.cli("clear trace")
+        intf.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        for i in self.pg_interfaces:
+            i.get_capture(0)
+            i.assert_nothing_captured(remark=remark)
+
+    def test_ip_punt(self):
+        """ IP punt police and redirect """
+
+        p = (Ether(src=self.pg0.remote_mac,
+                   dst=self.pg0.local_mac) /
+             IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
+             TCP(sport=1234, dport=1234) /
+             Raw('\xa5' * 100))
+
+        pkts = p * 1025
+
+        #
+        # Configure a punt redirect via pg1.
+        #
+        nh_addr = socket.inet_pton(socket.AF_INET,
+                                   self.pg1.remote_ip4)
+        self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
+                                   self.pg1.sw_if_index,
+                                   nh_addr)
+
+        self.send_and_expect(self.pg0, pkts, self.pg1)
+
+        #
+        # add a policer
+        #
+        policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
+                                            rate_type=1)
+        self.vapi.ip_punt_police(policer.policer_index)
+
+        self.vapi.cli("clear trace")
+        self.pg0.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        #
+        # the number of packet recieved should be greater than 0,
+        # but not equal to the number sent, since some were policed
+        #
+        rx = self.pg1._get_capture(1)
+        self.assertTrue(len(rx) > 0)
+        self.assertTrue(len(rx) < len(pkts))
+
+        #
+        # remove the poilcer. back to full rx
+        #
+        self.vapi.ip_punt_police(policer.policer_index, is_add=0)
+        self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
+                                  rate_type=1, is_add=0)
+        self.send_and_expect(self.pg0, pkts, self.pg1)
+
+        #
+        # remove the redirect. expect full drop.
+        #
+        self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
+                                   self.pg1.sw_if_index,
+                                   nh_addr,
+                                   is_add=0)
+        self.send_and_assert_no_replies(self.pg0, pkts,
+                                        "IP no punt config")
+
+        #
+        # Add a redirect that is not input port selective
+        #
+        self.vapi.ip_punt_redirect(0xffffffff,
+                                   self.pg1.sw_if_index,
+                                   nh_addr)
+        self.send_and_expect(self.pg0, pkts, self.pg1)
+
+        self.vapi.ip_punt_redirect(0xffffffff,
+                                   self.pg1.sw_if_index,
+                                   nh_addr,
+                                   is_add=0)
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index aad3713..dbe8746 100644 (file)
@@ -13,7 +13,7 @@ from vpp_neighbor import find_nbr, VppNeighbor
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, Dot1Q
-from scapy.layers.inet6 import IPv6, UDP, ICMPv6ND_NS, ICMPv6ND_RS, \
+from scapy.layers.inet6 import IPv6, UDP, TCP, ICMPv6ND_NS, ICMPv6ND_RS, \
     ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation, \
     ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo, \
     ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types
@@ -1506,5 +1506,117 @@ class TestIP6LoadBalance(VppTestCase):
         self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
 
 
+class TestIP6Punt(VppTestCase):
+    """ IPv6 Punt Police/Redirect """
+
+    def setUp(self):
+        super(TestIP6Punt, self).setUp()
+
+        self.create_pg_interfaces(range(2))
+
+        for i in self.pg_interfaces:
+            i.admin_up()
+            i.config_ip6()
+            i.resolve_ndp()
+
+    def tearDown(self):
+        super(TestIP6Punt, self).tearDown()
+        for i in self.pg_interfaces:
+            i.unconfig_ip6()
+            i.admin_down()
+
+    def send_and_expect(self, input, pkts, output):
+        input.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = output.get_capture(len(pkts))
+        return rx
+
+    def send_and_assert_no_replies(self, intf, pkts, remark):
+        self.vapi.cli("clear trace")
+        intf.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        for i in self.pg_interfaces:
+            i.get_capture(0)
+            i.assert_nothing_captured(remark=remark)
+
+    def test_ip_punt(self):
+        """ IP6 punt police and redirect """
+
+        p = (Ether(src=self.pg0.remote_mac,
+                   dst=self.pg0.local_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
+             TCP(sport=1234, dport=1234) /
+             Raw('\xa5' * 100))
+
+        pkts = p * 1025
+
+        #
+        # Configure a punt redirect via pg1.
+        #
+        nh_addr = inet_pton(AF_INET6,
+                            self.pg1.remote_ip6)
+        self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
+                                   self.pg1.sw_if_index,
+                                   nh_addr,
+                                   is_ip6=1)
+
+        self.send_and_expect(self.pg0, pkts, self.pg1)
+
+        #
+        # add a policer
+        #
+        policer = self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0,
+                                            rate_type=1)
+        self.vapi.ip_punt_police(policer.policer_index, is_ip6=1)
+
+        self.vapi.cli("clear trace")
+        self.pg0.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        #
+        # the number of packet recieved should be greater than 0,
+        # but not equal to the number sent, since some were policed
+        #
+        rx = self.pg1._get_capture(1)
+        self.assertTrue(len(rx) > 0)
+        self.assertTrue(len(rx) < len(pkts))
+
+        #
+        # remove the poilcer. back to full rx
+        #
+        self.vapi.ip_punt_police(policer.policer_index, is_add=0, is_ip6=1)
+        self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0,
+                                  rate_type=1, is_add=0)
+        self.send_and_expect(self.pg0, pkts, self.pg1)
+
+        #
+        # remove the redirect. expect full drop.
+        #
+        self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
+                                   self.pg1.sw_if_index,
+                                   nh_addr,
+                                   is_add=0,
+                                   is_ip6=1)
+        self.send_and_assert_no_replies(self.pg0, pkts,
+                                        "IP no punt config")
+
+        #
+        # Add a redirect that is not input port selective
+        #
+        self.vapi.ip_punt_redirect(0xffffffff,
+                                   self.pg1.sw_if_index,
+                                   nh_addr,
+                                   is_ip6=1)
+        self.send_and_expect(self.pg0, pkts, self.pg1)
+
+        self.vapi.ip_punt_redirect(0xffffffff,
+                                   self.pg1.sw_if_index,
+                                   nh_addr,
+                                   is_add=0,
+                                   is_ip6=1)
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index c3127f8..3d6a318 100644 (file)
@@ -2422,3 +2422,60 @@ class VppPapiProvider(object):
 
         return self.api(
             self.papi.macip_acl_dump, {'acl_index': acl_index})
+
+    def policer_add_del(self,
+                        name,
+                        cir,
+                        eir,
+                        cb,
+                        eb,
+                        is_add=1,
+                        rate_type=0,
+                        round_type=0,
+                        ptype=0,
+                        color_aware=0,
+                        conform_action_type=1,
+                        conform_dscp=0,
+                        exceed_action_type=0,
+                        exceed_dscp=0,
+                        violate_action_type=0,
+                        violate_dscp=0):
+        return self.api(self.papi.policer_add_del,
+                        {'name': name,
+                         'cir': cir,
+                         'eir': eir,
+                         'cb': cb,
+                         'eb': eb,
+                         'is_add': is_add,
+                         'rate_type': rate_type,
+                         'round_type': round_type,
+                         'type': ptype,
+                         'color_aware': color_aware,
+                         'conform_action_type': conform_action_type,
+                         'conform_dscp': conform_dscp,
+                         'exceed_action_type': exceed_action_type,
+                         'exceed_dscp': exceed_dscp,
+                         'violate_action_type': violate_action_type,
+                         'violate_dscp': violate_dscp})
+
+    def ip_punt_police(self,
+                       policer_index,
+                       is_ip6=0,
+                       is_add=1):
+        return self.api(self.papi.ip_punt_police,
+                        {'policer_index': policer_index,
+                         'is_add': is_add,
+                         'is_ip6': is_ip6})
+
+    def ip_punt_redirect(self,
+                         rx_sw_if_index,
+                         tx_sw_if_index,
+                         nh,
+                         is_ip6=0,
+                         is_add=1):
+        return self.api(self.papi.ip_punt_redirect,
+                        {'rx_sw_if_index': rx_sw_if_index,
+                         'tx_sw_if_index': tx_sw_if_index,
+                         'nh': nh,
+                         'is_add': is_add,
+                         'is_ip6': is_ip6})