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
2017-07-31 02:30:50 -07:00
committed by Damjan Marion
parent 268e64e312
commit d91c1dbdb3
19 changed files with 1882 additions and 215 deletions

View File

@ -18349,10 +18349,10 @@ api_policer_add_del (vat_main_t * vam)
clib_memcpy (mp->name, name, vec_len (name));
vec_free (name);
mp->is_add = is_add;
mp->cir = cir;
mp->eir = eir;
mp->cb = cb;
mp->eb = eb;
mp->cir = ntohl (cir);
mp->eir = ntohl (eir);
mp->cb = clib_net_to_host_u64 (cb);
mp->eb = clib_net_to_host_u64 (eb);
mp->rate_type = rate_type;
mp->round_type = round_type;
mp->type = type;

View File

@ -333,6 +333,7 @@ libvnet_la_SOURCES += \
vnet/ip/ip46_cli.c \
vnet/ip/ip4_format.c \
vnet/ip/ip4_forward.c \
vnet/ip/ip4_punt_drop.c \
vnet/ip/ip4_input.c \
vnet/ip/ip4_mtrie.c \
vnet/ip/ip4_pg.c \
@ -340,6 +341,7 @@ libvnet_la_SOURCES += \
vnet/ip/ip4_source_check.c \
vnet/ip/ip6_format.c \
vnet/ip/ip6_forward.c \
vnet/ip/ip6_punt_drop.c \
vnet/ip/ip6_hop_by_hop.c \
vnet/ip/ip6_input.c \
vnet/ip/ip6_neighbor.c \

View File

@ -547,6 +547,42 @@ define mfib_signal_details
u8 ip_packet_data[256];
};
/** \brief IP punt policer
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_add - 1 to add neighbor, 0 to delete
@param is_ipv6 - 1 for IPv6 neighbor, 0 for IPv4
@param policer_index - Index of policer to use
*/
autoreply define ip_punt_police
{
u32 client_index;
u32 context;
u32 policer_index;
u8 is_add;
u8 is_ip6;
};
/** \brief IP punt redirect
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_add - 1 to add neighbor, 0 to delete
@param is_ipv6 - 1 for IPv6 neighbor, 0 for IPv4
@param tx_sw_if_index - the TX interface to which traffic shoulde be
redirected.
@param nh - The next-hop to redirect the traffic to.
*/
autoreply define ip_punt_redirect
{
u32 client_index;
u32 context;
u32 rx_sw_if_index;
u32 tx_sw_if_index;
u8 is_add;
u8 is_ip6;
u8 nh[16];
};
/*
* Local Variables:
* eval: (c-set-style "gnu")

View File

@ -281,6 +281,12 @@ int vnet_set_ip4_flow_hash (u32 table_id,
int vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
u32 table_index);
void ip4_punt_policer_add_del (u8 is_add, u32 policer_index);
void ip4_punt_redirect_add (u32 rx_sw_if_index,
u32 tx_sw_if_index, ip46_address_t * nh);
void ip4_punt_redirect_del (u32 rx_sw_if_index);
/* Compute flow hash. We'll use it to select which adjacency to use for this
flow. And other things. */
always_inline u32

View File

@ -57,8 +57,8 @@
_ (MTU_EXCEEDED, "ip4 MTU exceeded and DF set") \
_ (DST_LOOKUP_MISS, "ip4 destination lookup miss") \
_ (SRC_LOOKUP_MISS, "ip4 source lookup miss") \
_ (ADJACENCY_DROP, "ip4 adjacency drop") \
_ (ADJACENCY_PUNT, "ip4 adjacency punt") \
_ (DROP, "ip4 drop") \
_ (PUNT, "ip4 punt") \
\
/* Errors signalled by ip4-local. */ \
_ (UNKNOWN_PROTOCOL, "unknown ip protocol") \

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -230,6 +230,11 @@ extern vlib_node_registration_t ip6_discover_neighbor_node;
extern vlib_node_registration_t ip6_glean_node;
extern vlib_node_registration_t ip6_midchain_node;
extern void ip6_forward_next_trace (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame,
vlib_rx_or_tx_t which_adj_index);
always_inline uword
ip6_destination_matches_route (const ip6_main_t * im,
const ip6_address_t * key,
@ -394,6 +399,11 @@ u8 *format_ip6_forward_next_trace (u8 * s, va_list * args);
u32 ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0);
void ip6_punt_policer_add_del (u8 is_add, u32 policer_index);
void ip6_punt_redirect_add (u32 rx_sw_if_index,
u32 tx_sw_if_index, ip46_address_t * nh);
void ip6_punt_redirect_del (u32 rx_sw_if_index);
int vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
u32 table_index);
extern vlib_node_registration_t ip6_lookup_node;

View File

@ -54,8 +54,8 @@
_ (MTU_EXCEEDED, "ip6 MTU exceeded") \
_ (DST_LOOKUP_MISS, "ip6 destination lookup miss") \
_ (SRC_LOOKUP_MISS, "ip6 source lookup miss") \
_ (ADJACENCY_DROP, "ip6 adjacency drop") \
_ (ADJACENCY_PUNT, "ip6 adjacency punt") \
_ (DROP, "ip6 drop") \
_ (PUNT, "ip6 punt") \
\
/* Errors signalled by ip6-local. */ \
_ (UNKNOWN_PROTOCOL, "unknown ip protocol") \

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,8 @@ _(IP_DUMP, ip_dump) \
_(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del) \
_(IP_ADD_DEL_ROUTE, ip_add_del_route) \
_(IP_TABLE_ADD_DEL, ip_table_add_del) \
_(IP_PUNT_POLICE, ip_punt_police) \
_(IP_PUNT_REDIRECT, ip_punt_redirect) \
_(SET_IP_FLOW_HASH,set_ip_flow_hash) \
_(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config) \
_(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix) \
@ -647,6 +649,64 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
vec_free (api_rpaths);
}
static void
vl_api_ip_punt_police_t_handler (vl_api_ip_punt_police_t * mp,
vlib_main_t * vm)
{
vl_api_ip_punt_police_reply_t *rmp;
int rv = 0;
if (mp->is_ip6)
ip6_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
else
ip4_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
REPLY_MACRO (VL_API_IP_PUNT_POLICE_REPLY);
}
static void
vl_api_ip_punt_redirect_t_handler (vl_api_ip_punt_redirect_t * mp,
vlib_main_t * vm)
{
vl_api_ip_punt_redirect_reply_t *rmp;
int rv = 0;
if (mp->is_add)
{
ip46_address_t nh;
memset (&nh, 0, sizeof (nh));
if (mp->is_ip6)
{
memcpy (&nh.ip6, mp->nh, sizeof (nh.ip6));
ip6_punt_redirect_add (ntohl (mp->rx_sw_if_index),
ntohl (mp->tx_sw_if_index), &nh);
}
else
{
memcpy (&nh.ip4, mp->nh, sizeof (nh.ip4));
ip4_punt_redirect_add (ntohl (mp->rx_sw_if_index),
ntohl (mp->tx_sw_if_index), &nh);
}
}
else
{
if (mp->is_ip6)
{
ip6_punt_redirect_del (ntohl (mp->rx_sw_if_index));
}
else
{
ip4_punt_redirect_del (ntohl (mp->rx_sw_if_index));
}
}
REPLY_MACRO (VL_API_IP_PUNT_REDIRECT_REPLY);
}
static void
vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
vlib_main_t * vm)

467
src/vnet/ip/ip_punt_drop.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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,

View 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:
*/

View File

@ -63,10 +63,10 @@ vl_api_policer_add_del_t_handler (vl_api_policer_add_del_t * mp)
cfg.rfc = mp->type;
cfg.rnd_type = mp->round_type;
cfg.rate_type = mp->rate_type;
cfg.rb.kbps.cir_kbps = mp->cir;
cfg.rb.kbps.eir_kbps = mp->eir;
cfg.rb.kbps.cb_bytes = mp->cb;
cfg.rb.kbps.eb_bytes = mp->eb;
cfg.rb.kbps.cir_kbps = ntohl (mp->cir);
cfg.rb.kbps.eir_kbps = ntohl (mp->eir);
cfg.rb.kbps.cb_bytes = clib_net_to_host_u64 (mp->cb);
cfg.rb.kbps.eb_bytes = clib_net_to_host_u64 (mp->eb);
cfg.conform_action.action_type = mp->conform_action_type;
cfg.conform_action.dscp = mp->conform_dscp;
cfg.exceed_action.action_type = mp->exceed_action_type;

View File

@ -11,7 +11,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
from scapy.packet import Raw
from scapy.layers.l2 import Ether, Dot1Q, ARP
from scapy.layers.inet import IP, UDP, ICMP, icmptypes, icmpcodes
from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
from util import ppp
from scapy.contrib.mpls import MPLS
@ -1009,5 +1009,115 @@ class TestIPVlan0(VppTestCase):
self.send_and_expect(self.pg0, pkts, self.pg1)
class TestIPPunt(VppTestCase):
""" IPv4 Punt Police/Redirect """
def setUp(self):
super(TestIPPunt, self).setUp()
self.create_pg_interfaces(range(2))
for i in self.pg_interfaces:
i.admin_up()
i.config_ip4()
i.resolve_arp()
def tearDown(self):
super(TestIPPunt, self).tearDown()
for i in self.pg_interfaces:
i.unconfig_ip4()
i.admin_down()
def send_and_expect(self, input, pkts, output):
self.vapi.cli("clear trace")
input.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = output.get_capture(len(pkts))
return rx
def send_and_assert_no_replies(self, intf, pkts, remark):
self.vapi.cli("clear trace")
intf.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
for i in self.pg_interfaces:
i.get_capture(0)
i.assert_nothing_captured(remark=remark)
def test_ip_punt(self):
""" IP punt police and redirect """
p = (Ether(src=self.pg0.remote_mac,
dst=self.pg0.local_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
TCP(sport=1234, dport=1234) /
Raw('\xa5' * 100))
pkts = p * 1025
#
# Configure a punt redirect via pg1.
#
nh_addr = socket.inet_pton(socket.AF_INET,
self.pg1.remote_ip4)
self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
self.pg1.sw_if_index,
nh_addr)
self.send_and_expect(self.pg0, pkts, self.pg1)
#
# add a policer
#
policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
rate_type=1)
self.vapi.ip_punt_police(policer.policer_index)
self.vapi.cli("clear trace")
self.pg0.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
#
# the number of packet recieved should be greater than 0,
# but not equal to the number sent, since some were policed
#
rx = self.pg1._get_capture(1)
self.assertTrue(len(rx) > 0)
self.assertTrue(len(rx) < len(pkts))
#
# remove the poilcer. back to full rx
#
self.vapi.ip_punt_police(policer.policer_index, is_add=0)
self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
rate_type=1, is_add=0)
self.send_and_expect(self.pg0, pkts, self.pg1)
#
# remove the redirect. expect full drop.
#
self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
self.pg1.sw_if_index,
nh_addr,
is_add=0)
self.send_and_assert_no_replies(self.pg0, pkts,
"IP no punt config")
#
# Add a redirect that is not input port selective
#
self.vapi.ip_punt_redirect(0xffffffff,
self.pg1.sw_if_index,
nh_addr)
self.send_and_expect(self.pg0, pkts, self.pg1)
self.vapi.ip_punt_redirect(0xffffffff,
self.pg1.sw_if_index,
nh_addr,
is_add=0)
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)

View File

@ -13,7 +13,7 @@ from vpp_neighbor import find_nbr, VppNeighbor
from scapy.packet import Raw
from scapy.layers.l2 import Ether, Dot1Q
from scapy.layers.inet6 import IPv6, UDP, ICMPv6ND_NS, ICMPv6ND_RS, \
from scapy.layers.inet6 import IPv6, UDP, TCP, ICMPv6ND_NS, ICMPv6ND_RS, \
ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation, \
ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo, \
ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types
@ -1506,5 +1506,117 @@ class TestIP6LoadBalance(VppTestCase):
self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
class TestIP6Punt(VppTestCase):
""" IPv6 Punt Police/Redirect """
def setUp(self):
super(TestIP6Punt, self).setUp()
self.create_pg_interfaces(range(2))
for i in self.pg_interfaces:
i.admin_up()
i.config_ip6()
i.resolve_ndp()
def tearDown(self):
super(TestIP6Punt, self).tearDown()
for i in self.pg_interfaces:
i.unconfig_ip6()
i.admin_down()
def send_and_expect(self, input, pkts, output):
input.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = output.get_capture(len(pkts))
return rx
def send_and_assert_no_replies(self, intf, pkts, remark):
self.vapi.cli("clear trace")
intf.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
for i in self.pg_interfaces:
i.get_capture(0)
i.assert_nothing_captured(remark=remark)
def test_ip_punt(self):
""" IP6 punt police and redirect """
p = (Ether(src=self.pg0.remote_mac,
dst=self.pg0.local_mac) /
IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
TCP(sport=1234, dport=1234) /
Raw('\xa5' * 100))
pkts = p * 1025
#
# Configure a punt redirect via pg1.
#
nh_addr = inet_pton(AF_INET6,
self.pg1.remote_ip6)
self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
self.pg1.sw_if_index,
nh_addr,
is_ip6=1)
self.send_and_expect(self.pg0, pkts, self.pg1)
#
# add a policer
#
policer = self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0,
rate_type=1)
self.vapi.ip_punt_police(policer.policer_index, is_ip6=1)
self.vapi.cli("clear trace")
self.pg0.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
#
# the number of packet recieved should be greater than 0,
# but not equal to the number sent, since some were policed
#
rx = self.pg1._get_capture(1)
self.assertTrue(len(rx) > 0)
self.assertTrue(len(rx) < len(pkts))
#
# remove the poilcer. back to full rx
#
self.vapi.ip_punt_police(policer.policer_index, is_add=0, is_ip6=1)
self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0,
rate_type=1, is_add=0)
self.send_and_expect(self.pg0, pkts, self.pg1)
#
# remove the redirect. expect full drop.
#
self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
self.pg1.sw_if_index,
nh_addr,
is_add=0,
is_ip6=1)
self.send_and_assert_no_replies(self.pg0, pkts,
"IP no punt config")
#
# Add a redirect that is not input port selective
#
self.vapi.ip_punt_redirect(0xffffffff,
self.pg1.sw_if_index,
nh_addr,
is_ip6=1)
self.send_and_expect(self.pg0, pkts, self.pg1)
self.vapi.ip_punt_redirect(0xffffffff,
self.pg1.sw_if_index,
nh_addr,
is_add=0,
is_ip6=1)
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)

View File

@ -2422,3 +2422,60 @@ class VppPapiProvider(object):
return self.api(
self.papi.macip_acl_dump, {'acl_index': acl_index})
def policer_add_del(self,
name,
cir,
eir,
cb,
eb,
is_add=1,
rate_type=0,
round_type=0,
ptype=0,
color_aware=0,
conform_action_type=1,
conform_dscp=0,
exceed_action_type=0,
exceed_dscp=0,
violate_action_type=0,
violate_dscp=0):
return self.api(self.papi.policer_add_del,
{'name': name,
'cir': cir,
'eir': eir,
'cb': cb,
'eb': eb,
'is_add': is_add,
'rate_type': rate_type,
'round_type': round_type,
'type': ptype,
'color_aware': color_aware,
'conform_action_type': conform_action_type,
'conform_dscp': conform_dscp,
'exceed_action_type': exceed_action_type,
'exceed_dscp': exceed_dscp,
'violate_action_type': violate_action_type,
'violate_dscp': violate_dscp})
def ip_punt_police(self,
policer_index,
is_ip6=0,
is_add=1):
return self.api(self.papi.ip_punt_police,
{'policer_index': policer_index,
'is_add': is_add,
'is_ip6': is_ip6})
def ip_punt_redirect(self,
rx_sw_if_index,
tx_sw_if_index,
nh,
is_ip6=0,
is_add=1):
return self.api(self.papi.ip_punt_redirect,
{'rx_sw_if_index': rx_sw_if_index,
'tx_sw_if_index': tx_sw_if_index,
'nh': nh,
'is_add': is_add,
'is_ip6': is_ip6})