aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-07-31 02:30:50 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2017-10-10 16:42:39 +0000
commitd91c1dbdb31f80db7d967f2f57c43d0a81d65297 (patch)
treec7d323cd6980b6fc7c5d96157607a07e51efa468
parent268e64e312257b0ab36e0d5b9124cc3f2a1841a7 (diff)
punt and drop features:
- 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>
-rw-r--r--src/vat/api_format.c8
-rw-r--r--src/vnet.am2
-rw-r--r--src/vnet/ip/ip.api36
-rw-r--r--src/vnet/ip/ip4.h6
-rw-r--r--src/vnet/ip/ip4_error.h4
-rwxr-xr-xsrc/vnet/ip/ip4_forward.c77
-rw-r--r--src/vnet/ip/ip4_punt_drop.c515
-rw-r--r--src/vnet/ip/ip6.h10
-rw-r--r--src/vnet/ip/ip6_error.h4
-rw-r--r--src/vnet/ip/ip6_forward.c73
-rw-r--r--src/vnet/ip/ip6_punt_drop.c396
-rw-r--r--src/vnet/ip/ip_api.c60
-rw-r--r--src/vnet/ip/ip_punt_drop.h467
-rw-r--r--src/vnet/policer/node_funcs.c59
-rw-r--r--src/vnet/policer/police_inlines.h89
-rw-r--r--src/vnet/policer/policer_api.c8
-rw-r--r--test/test_ip4.py112
-rw-r--r--test/test_ip6.py114
-rw-r--r--test/vpp_papi_provider.py57
19 files changed, 1882 insertions, 215 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index ba1a791afec..7cd4b22df9a 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -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;
diff --git a/src/vnet.am b/src/vnet.am
index 15b3467c772..ab0978074b6 100644
--- a/src/vnet.am
+++ b/src/vnet.am
@@ -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 \
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api
index 69ab7011943..e302b1e7a44 100644
--- a/src/vnet/ip/ip.api
+++ b/src/vnet/ip/ip.api
@@ -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")
diff --git a/src/vnet/ip/ip4.h b/src/vnet/ip/ip4.h
index af0e6b9a8a5..4c5cc054c4a 100644
--- a/src/vnet/ip/ip4.h
+++ b/src/vnet/ip/ip4.h
@@ -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
diff --git a/src/vnet/ip/ip4_error.h b/src/vnet/ip/ip4_error.h
index 95d12ec22d5..d2775636539 100644
--- a/src/vnet/ip/ip4_error.h
+++ b/src/vnet/ip/ip4_error.h
@@ -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") \
diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c
index 3aebb181fce..daffae410cc 100755
--- a/src/vnet/ip/ip4_forward.c
+++ b/src/vnet/ip/ip4_forward.c
@@ -60,12 +60,6 @@
* 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
index 00000000000..72f36f33560
--- /dev/null
+++ b/src/vnet/ip/ip4_punt_drop.c
@@ -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:
+ */
diff --git a/src/vnet/ip/ip6.h b/src/vnet/ip/ip6.h
index 8aef53a9dcb..033ecfc43b8 100644
--- a/src/vnet/ip/ip6.h
+++ b/src/vnet/ip/ip6.h
@@ -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;
diff --git a/src/vnet/ip/ip6_error.h b/src/vnet/ip/ip6_error.h
index a2807169123..7bb4b77b5a3 100644
--- a/src/vnet/ip/ip6_error.h
+++ b/src/vnet/ip/ip6_error.h
@@ -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") \
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index 4f9ad85432f..f54b433485f 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -61,11 +61,6 @@
* 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
index 00000000000..a1f0ebe6901
--- /dev/null
+++ b/src/vnet/ip/ip6_punt_drop.c
@@ -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:
+ */
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index 4d4daac8536..d9ec4b47998 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -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) \
@@ -648,6 +650,64 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
}
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
index 00000000000..7ba65e1a6e4
--- /dev/null
+++ b/src/vnet/ip/ip_punt_drop.h
@@ -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:
+ */
diff --git a/src/vnet/policer/node_funcs.c b/src/vnet/policer/node_funcs.c
index fd031d02eea..25cb4201674 100644
--- a/src/vnet/policer/node_funcs.c
+++ b/src/vnet/policer/node_funcs.c
@@ -18,14 +18,11 @@
#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
index 00000000000..64386e6f1bf
--- /dev/null
+++ b/src/vnet/policer/police_inlines.h
@@ -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:
+ */
diff --git a/src/vnet/policer/policer_api.c b/src/vnet/policer/policer_api.c
index 67fb9a4e2b9..3dc2cdd6a0a 100644
--- a/src/vnet/policer/policer_api.c
+++ b/src/vnet/policer/policer_api.c
@@ -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;
diff --git a/test/test_ip4.py b/test/test_ip4.py
index 55d16735a01..5bd50ce3ea4 100644
--- a/test/test_ip4.py
+++ b/test/test_ip4.py
@@ -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)
diff --git a/test/test_ip6.py b/test/test_ip6.py
index aad3713c4c0..dbe87465f7b 100644
--- a/test/test_ip6.py
+++ b/test/test_ip6.py
@@ -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)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index c3127f84022..3d6a3184bb8 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -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})