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>
This commit is contained in:
Neale Ranns
committed by
Damjan Marion
parent
268e64e312
commit
d91c1dbdb3
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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") \
|
||||
|
@ -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",
|
||||
},
|
||||
|
515
src/vnet/ip/ip4_punt_drop.c
Normal file
515
src/vnet/ip/ip4_punt_drop.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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") \
|
||||
|
@ -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",
|
||||
},
|
||||
|
396
src/vnet/ip/ip6_punt_drop.c
Normal file
396
src/vnet/ip/ip6_punt_drop.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
467
src/vnet/ip/ip_punt_drop.h
Normal file
467
src/vnet/ip/ip_punt_drop.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
89
src/vnet/policer/police_inlines.h
Normal file
89
src/vnet/policer/police_inlines.h
Normal file
@ -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:
|
||||
*/
|
@ -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;
|
||||
|
112
test/test_ip4.py
112
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)
|
||||
|
114
test/test_ip6.py
114
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)
|
||||
|
@ -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})
|
||||
|
Reference in New Issue
Block a user