Refactor IP input checks for re-use at MPLS disposition
Change-Id: I7aafdecd6f370411138e6ab67b2ff72cda6e0666 Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
Neale Ranns
committed by
Damjan Marion
parent
b3d1b20357
commit
4c7c8e55b0
@ -13,7 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ip/ip4_input.h>
|
||||
#include <vnet/ip/ip6_input.h>
|
||||
#include <vnet/dpo/mpls_disposition.h>
|
||||
#include <vnet/mpls/mpls.h>
|
||||
|
||||
@ -115,6 +116,9 @@ typedef struct mpls_label_disposition_trace_t_
|
||||
index_t mdd;
|
||||
} mpls_label_disposition_trace_t;
|
||||
|
||||
extern vlib_node_registration_t ip4_mpls_label_disposition_node;
|
||||
extern vlib_node_registration_t ip6_mpls_label_disposition_node;
|
||||
|
||||
always_inline uword
|
||||
mpls_label_disposition_inline (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * node,
|
||||
@ -123,6 +127,12 @@ mpls_label_disposition_inline (vlib_main_t * vm,
|
||||
u8 payload_is_ip6)
|
||||
{
|
||||
u32 n_left_from, next_index, * from, * to_next;
|
||||
vlib_node_runtime_t *error_node;
|
||||
|
||||
if (payload_is_ip4)
|
||||
error_node = vlib_node_get_runtime (vm, ip4_mpls_label_disposition_node.index);
|
||||
else
|
||||
error_node = vlib_node_get_runtime (vm, ip6_mpls_label_disposition_node.index);
|
||||
|
||||
from = vlib_frame_vector_args (from_frame);
|
||||
n_left_from = from_frame->n_vectors;
|
||||
@ -173,21 +183,39 @@ mpls_label_disposition_inline (vlib_main_t * vm,
|
||||
mdd0 = mpls_disp_dpo_get(mddi0);
|
||||
mdd1 = mpls_disp_dpo_get(mddi1);
|
||||
|
||||
next0 = mdd0->mdd_dpo.dpoi_next_node;
|
||||
next1 = mdd1->mdd_dpo.dpoi_next_node;
|
||||
|
||||
if (payload_is_ip4)
|
||||
{
|
||||
ip4_header_t *ip0, *ip1;
|
||||
|
||||
ip0 = vlib_buffer_get_current (b0);
|
||||
ip1 = vlib_buffer_get_current (b1);
|
||||
|
||||
/*
|
||||
* decrement the TTL on ingress to the LSP
|
||||
* IPv4 input checks on the exposed IP header
|
||||
* including checksum
|
||||
*/
|
||||
ip4_input_check_x2 (vm, error_node,
|
||||
b0, b1, ip0, ip1,
|
||||
&next0, &next1, 1);
|
||||
}
|
||||
else if (payload_is_ip6)
|
||||
{
|
||||
ip6_header_t *ip0, *ip1;
|
||||
|
||||
ip0 = vlib_buffer_get_current (b0);
|
||||
ip1 = vlib_buffer_get_current (b1);
|
||||
|
||||
/*
|
||||
* decrement the TTL on ingress to the LSP
|
||||
* IPv6 input checks on the exposed IP header
|
||||
*/
|
||||
ip6_input_check_x2 (vm, error_node,
|
||||
b0, b1, ip0, ip1,
|
||||
&next0, &next1);
|
||||
}
|
||||
|
||||
next0 = mdd0->mdd_dpo.dpoi_next_node;
|
||||
next1 = mdd1->mdd_dpo.dpoi_next_node;
|
||||
|
||||
vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
|
||||
vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mdd1->mdd_dpo.dpoi_index;
|
||||
vnet_buffer(b0)->ip.rpf_id = mdd0->mdd_rpf_id;
|
||||
@ -231,24 +259,32 @@ mpls_label_disposition_inline (vlib_main_t * vm,
|
||||
/* dst lookup was done by ip4 lookup */
|
||||
mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
|
||||
mdd0 = mpls_disp_dpo_get(mddi0);
|
||||
next0 = mdd0->mdd_dpo.dpoi_next_node;
|
||||
|
||||
if (payload_is_ip4)
|
||||
{
|
||||
ip4_header_t *ip0;
|
||||
|
||||
ip0 = vlib_buffer_get_current (b0);
|
||||
|
||||
/*
|
||||
* decrement the TTL on ingress to the LSP
|
||||
* IPv4 input checks on the exposed IP header
|
||||
* including checksum
|
||||
*/
|
||||
ip4_input_check_x1 (vm, error_node, b0, ip0, &next0, 1);
|
||||
}
|
||||
else if (payload_is_ip6)
|
||||
{
|
||||
ip6_header_t *ip0;
|
||||
|
||||
ip0 = vlib_buffer_get_current (b0);
|
||||
|
||||
/*
|
||||
* decrement the TTL on ingress to the LSP
|
||||
* IPv6 input checks on the exposed IP header
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
ip6_input_check_x1 (vm, error_node, b0, ip0, &next0);
|
||||
}
|
||||
|
||||
next0 = mdd0->mdd_dpo.dpoi_next_node;
|
||||
vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
|
||||
vnet_buffer(b0)->ip.rpf_id = mdd0->mdd_rpf_id;
|
||||
|
||||
@ -294,10 +330,9 @@ VLIB_REGISTER_NODE (ip4_mpls_label_disposition_node) = {
|
||||
.vector_size = sizeof (u32),
|
||||
|
||||
.format_trace = format_mpls_label_disposition_trace,
|
||||
.n_next_nodes = 1,
|
||||
.next_nodes = {
|
||||
[0] = "ip4-drop",
|
||||
}
|
||||
.sibling_of = "ip4-input",
|
||||
.n_errors = IP4_N_ERROR,
|
||||
.error_strings = ip4_error_strings,
|
||||
};
|
||||
VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_disposition_node,
|
||||
ip4_mpls_label_disposition)
|
||||
@ -316,10 +351,9 @@ VLIB_REGISTER_NODE (ip6_mpls_label_disposition_node) = {
|
||||
.vector_size = sizeof (u32),
|
||||
|
||||
.format_trace = format_mpls_label_disposition_trace,
|
||||
.n_next_nodes = 1,
|
||||
.next_nodes = {
|
||||
[0] = "ip6-drop",
|
||||
}
|
||||
.sibling_of = "ip6-input",
|
||||
.n_errors = IP6_N_ERROR,
|
||||
.error_strings = ip6_error_strings,
|
||||
};
|
||||
VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_disposition_node,
|
||||
ip6_mpls_label_disposition)
|
||||
|
@ -37,7 +37,7 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ip/ip4_input.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
#include <vnet/ppp/ppp.h>
|
||||
#include <vnet/hdlc/hdlc.h>
|
||||
@ -60,16 +60,6 @@ format_ip4_input_trace (u8 * s, va_list * va)
|
||||
return s;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IP4_INPUT_NEXT_DROP,
|
||||
IP4_INPUT_NEXT_PUNT,
|
||||
IP4_INPUT_NEXT_LOOKUP,
|
||||
IP4_INPUT_NEXT_LOOKUP_MULTICAST,
|
||||
IP4_INPUT_NEXT_ICMP_ERROR,
|
||||
IP4_INPUT_N_NEXT,
|
||||
} ip4_input_next_t;
|
||||
|
||||
/* Validate IP v4 packets and pass them either to forwarding code
|
||||
or drop/punt exception packets. */
|
||||
always_inline uword
|
||||
@ -109,10 +99,9 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
vlib_buffer_t *p0, *p1;
|
||||
ip4_header_t *ip0, *ip1;
|
||||
u32 sw_if_index0, pi0, ip_len0, cur_len0, next0;
|
||||
u32 sw_if_index1, pi1, ip_len1, cur_len1, next1;
|
||||
i32 len_diff0, len_diff1;
|
||||
u8 error0, error1, arc0, arc1;
|
||||
u32 sw_if_index0, pi0, next0;
|
||||
u32 sw_if_index1, pi1, next1;
|
||||
u8 arc0, arc1;
|
||||
|
||||
/* Prefetch next iteration. */
|
||||
{
|
||||
@ -144,8 +133,6 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
|
||||
sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
|
||||
|
||||
error0 = error1 = IP4_ERROR_NONE;
|
||||
|
||||
if (PREDICT_FALSE (ip4_address_is_multicast (&ip0->dst_address)))
|
||||
{
|
||||
arc0 = lm->mcast_feature_arc_index;
|
||||
@ -155,8 +142,6 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
arc0 = lm->ucast_feature_arc_index;
|
||||
next0 = IP4_INPUT_NEXT_LOOKUP;
|
||||
if (PREDICT_FALSE (ip0->ttl < 1))
|
||||
error0 = IP4_ERROR_TIME_EXPIRED;
|
||||
}
|
||||
|
||||
if (PREDICT_FALSE (ip4_address_is_multicast (&ip1->dst_address)))
|
||||
@ -168,8 +153,6 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
arc1 = lm->ucast_feature_arc_index;
|
||||
next1 = IP4_INPUT_NEXT_LOOKUP;
|
||||
if (PREDICT_FALSE (ip1->ttl < 1))
|
||||
error1 = IP4_ERROR_TIME_EXPIRED;
|
||||
}
|
||||
|
||||
vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
|
||||
@ -180,82 +163,9 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
|
||||
vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
|
||||
vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
|
||||
|
||||
/* Punt packets with options or wrong version. */
|
||||
if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45))
|
||||
error0 = (ip0->ip_version_and_header_length & 0xf) != 5 ?
|
||||
IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
|
||||
|
||||
if (PREDICT_FALSE (ip1->ip_version_and_header_length != 0x45))
|
||||
error1 = (ip1->ip_version_and_header_length & 0xf) != 5 ?
|
||||
IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
|
||||
|
||||
/* Verify header checksum. */
|
||||
if (verify_checksum)
|
||||
{
|
||||
ip_csum_t sum0, sum1;
|
||||
|
||||
ip4_partial_header_checksum_x1 (ip0, sum0);
|
||||
ip4_partial_header_checksum_x1 (ip1, sum1);
|
||||
|
||||
error0 = 0xffff != ip_csum_fold (sum0) ?
|
||||
IP4_ERROR_BAD_CHECKSUM : error0;
|
||||
error1 = 0xffff != ip_csum_fold (sum1) ?
|
||||
IP4_ERROR_BAD_CHECKSUM : error1;
|
||||
}
|
||||
|
||||
/* Drop fragmentation offset 1 packets. */
|
||||
error0 = ip4_get_fragment_offset (ip0) == 1 ?
|
||||
IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
|
||||
error1 = ip4_get_fragment_offset (ip1) == 1 ?
|
||||
IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
|
||||
|
||||
/* Verify lengths. */
|
||||
ip_len0 = clib_net_to_host_u16 (ip0->length);
|
||||
ip_len1 = clib_net_to_host_u16 (ip1->length);
|
||||
|
||||
/* IP length must be at least minimal IP header. */
|
||||
error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
|
||||
error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
|
||||
|
||||
cur_len0 = vlib_buffer_length_in_chain (vm, p0);
|
||||
cur_len1 = vlib_buffer_length_in_chain (vm, p1);
|
||||
|
||||
len_diff0 = cur_len0 - ip_len0;
|
||||
len_diff1 = cur_len1 - ip_len1;
|
||||
|
||||
error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
|
||||
error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
|
||||
|
||||
p0->error = error_node->errors[error0];
|
||||
p1->error = error_node->errors[error1];
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP4_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
|
||||
ICMP4_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
next0 = IP4_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
next0 = error0 != IP4_ERROR_OPTIONS ?
|
||||
IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_PUNT;
|
||||
}
|
||||
if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
|
||||
{
|
||||
if (error1 == IP4_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
|
||||
ICMP4_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
next1 = IP4_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
next1 = error1 != IP4_ERROR_OPTIONS ?
|
||||
IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_PUNT;
|
||||
}
|
||||
ip4_input_check_x2 (vm, error_node,
|
||||
p0, p1, ip0, ip1,
|
||||
&next0, &next1, verify_checksum);
|
||||
|
||||
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
|
||||
to_next, n_left_to_next,
|
||||
@ -265,9 +175,8 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
vlib_buffer_t *p0;
|
||||
ip4_header_t *ip0;
|
||||
u32 sw_if_index0, pi0, ip_len0, cur_len0, next0;
|
||||
i32 len_diff0;
|
||||
u8 error0, arc0;
|
||||
u32 sw_if_index0, pi0, next0;
|
||||
u8 arc0;
|
||||
|
||||
pi0 = from[0];
|
||||
to_next[0] = pi0;
|
||||
@ -281,8 +190,6 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
|
||||
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
|
||||
|
||||
error0 = IP4_ERROR_NONE;
|
||||
|
||||
if (PREDICT_FALSE (ip4_address_is_multicast (&ip0->dst_address)))
|
||||
{
|
||||
arc0 = lm->mcast_feature_arc_index;
|
||||
@ -292,60 +199,14 @@ ip4_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
arc0 = lm->ucast_feature_arc_index;
|
||||
next0 = IP4_INPUT_NEXT_LOOKUP;
|
||||
if (PREDICT_FALSE (ip0->ttl < 1))
|
||||
error0 = IP4_ERROR_TIME_EXPIRED;
|
||||
}
|
||||
|
||||
vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
|
||||
vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
|
||||
|
||||
vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
|
||||
|
||||
/* Punt packets with options or wrong version. */
|
||||
if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45))
|
||||
error0 = (ip0->ip_version_and_header_length & 0xf) != 5 ?
|
||||
IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
|
||||
|
||||
/* Verify header checksum. */
|
||||
if (verify_checksum)
|
||||
{
|
||||
ip_csum_t sum0;
|
||||
|
||||
ip4_partial_header_checksum_x1 (ip0, sum0);
|
||||
error0 =
|
||||
0xffff !=
|
||||
ip_csum_fold (sum0) ? IP4_ERROR_BAD_CHECKSUM : error0;
|
||||
}
|
||||
|
||||
/* Drop fragmentation offset 1 packets. */
|
||||
error0 =
|
||||
ip4_get_fragment_offset (ip0) ==
|
||||
1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
|
||||
|
||||
/* Verify lengths. */
|
||||
ip_len0 = clib_net_to_host_u16 (ip0->length);
|
||||
|
||||
/* IP length must be at least minimal IP header. */
|
||||
error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
|
||||
|
||||
cur_len0 = vlib_buffer_length_in_chain (vm, p0);
|
||||
len_diff0 = cur_len0 - ip_len0;
|
||||
error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
|
||||
|
||||
p0->error = error_node->errors[error0];
|
||||
if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP4_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
|
||||
ICMP4_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
next0 = IP4_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
next0 = error0 != IP4_ERROR_OPTIONS ?
|
||||
IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_PUNT;
|
||||
}
|
||||
ip4_input_check_x1 (vm, error_node, p0, ip0, &next0,
|
||||
verify_checksum);
|
||||
|
||||
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
|
||||
to_next, n_left_to_next,
|
||||
@ -406,7 +267,7 @@ ip4_input_no_checksum (vlib_main_t * vm,
|
||||
return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
|
||||
}
|
||||
|
||||
static char *ip4_error_strings[] = {
|
||||
char *ip4_error_strings[] = {
|
||||
#define _(sym,string) string,
|
||||
foreach_ip4_error
|
||||
#undef _
|
||||
|
223
src/vnet/ip/ip4_input.h
Normal file
223
src/vnet/ip/ip4_input.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
/*
|
||||
* ip/ip4_input.c: IP v4 input node
|
||||
*
|
||||
* Copyright (c) 2008 Eliot Dresselhaus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef included_ip_input_h
|
||||
#define included_ip_input_h
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
|
||||
extern char *ip4_error_strings[];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IP4_INPUT_NEXT_DROP,
|
||||
IP4_INPUT_NEXT_PUNT,
|
||||
IP4_INPUT_NEXT_LOOKUP,
|
||||
IP4_INPUT_NEXT_LOOKUP_MULTICAST,
|
||||
IP4_INPUT_NEXT_ICMP_ERROR,
|
||||
IP4_INPUT_N_NEXT,
|
||||
} ip4_input_next_t;
|
||||
|
||||
always_inline void
|
||||
ip4_input_check_x2 (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * error_node,
|
||||
vlib_buffer_t * p0, vlib_buffer_t * p1,
|
||||
ip4_header_t * ip0, ip4_header_t * ip1,
|
||||
u32 * next0, u32 * next1, int verify_checksum)
|
||||
{
|
||||
u8 error0, error1;
|
||||
u32 ip_len0, cur_len0;
|
||||
u32 ip_len1, cur_len1;
|
||||
i32 len_diff0, len_diff1;
|
||||
|
||||
error0 = error1 = IP4_ERROR_NONE;
|
||||
|
||||
/* Punt packets with options or wrong version. */
|
||||
if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45))
|
||||
error0 = (ip0->ip_version_and_header_length & 0xf) != 5 ?
|
||||
IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
|
||||
|
||||
if (PREDICT_FALSE (ip1->ip_version_and_header_length != 0x45))
|
||||
error1 = (ip1->ip_version_and_header_length & 0xf) != 5 ?
|
||||
IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
|
||||
|
||||
if (PREDICT_FALSE (ip0->ttl < 1))
|
||||
error0 = IP4_ERROR_TIME_EXPIRED;
|
||||
if (PREDICT_FALSE (ip1->ttl < 1))
|
||||
error1 = IP4_ERROR_TIME_EXPIRED;
|
||||
|
||||
/* Verify header checksum. */
|
||||
if (verify_checksum)
|
||||
{
|
||||
ip_csum_t sum0, sum1;
|
||||
|
||||
ip4_partial_header_checksum_x1 (ip0, sum0);
|
||||
ip4_partial_header_checksum_x1 (ip1, sum1);
|
||||
|
||||
error0 = 0xffff != ip_csum_fold (sum0) ?
|
||||
IP4_ERROR_BAD_CHECKSUM : error0;
|
||||
error1 = 0xffff != ip_csum_fold (sum1) ?
|
||||
IP4_ERROR_BAD_CHECKSUM : error1;
|
||||
}
|
||||
|
||||
/* Drop fragmentation offset 1 packets. */
|
||||
error0 = ip4_get_fragment_offset (ip0) == 1 ?
|
||||
IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
|
||||
error1 = ip4_get_fragment_offset (ip1) == 1 ?
|
||||
IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
|
||||
|
||||
/* Verify lengths. */
|
||||
ip_len0 = clib_net_to_host_u16 (ip0->length);
|
||||
ip_len1 = clib_net_to_host_u16 (ip1->length);
|
||||
|
||||
/* IP length must be at least minimal IP header. */
|
||||
error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
|
||||
error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
|
||||
|
||||
cur_len0 = vlib_buffer_length_in_chain (vm, p0);
|
||||
cur_len1 = vlib_buffer_length_in_chain (vm, p1);
|
||||
|
||||
len_diff0 = cur_len0 - ip_len0;
|
||||
len_diff1 = cur_len1 - ip_len1;
|
||||
|
||||
error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
|
||||
error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP4_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
|
||||
ICMP4_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
*next0 = IP4_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
*next0 = error0 != IP4_ERROR_OPTIONS ?
|
||||
IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_PUNT;
|
||||
}
|
||||
if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
|
||||
{
|
||||
if (error1 == IP4_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
|
||||
ICMP4_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
*next1 = IP4_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
*next1 = error1 != IP4_ERROR_OPTIONS ?
|
||||
IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_PUNT;
|
||||
}
|
||||
|
||||
p0->error = error_node->errors[error0];
|
||||
p1->error = error_node->errors[error1];
|
||||
}
|
||||
|
||||
always_inline void
|
||||
ip4_input_check_x1 (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * error_node,
|
||||
vlib_buffer_t * p0,
|
||||
ip4_header_t * ip0, u32 * next0, int verify_checksum)
|
||||
{
|
||||
u32 ip_len0, cur_len0;
|
||||
i32 len_diff0;
|
||||
u8 error0;
|
||||
|
||||
error0 = IP4_ERROR_NONE;
|
||||
|
||||
/* Punt packets with options or wrong version. */
|
||||
if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45))
|
||||
error0 = (ip0->ip_version_and_header_length & 0xf) != 5 ?
|
||||
IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
|
||||
|
||||
/* Verify header checksum. */
|
||||
if (verify_checksum)
|
||||
{
|
||||
ip_csum_t sum0;
|
||||
|
||||
ip4_partial_header_checksum_x1 (ip0, sum0);
|
||||
|
||||
error0 = 0xffff != ip_csum_fold (sum0) ?
|
||||
IP4_ERROR_BAD_CHECKSUM : error0;
|
||||
}
|
||||
|
||||
/* Drop fragmentation offset 1 packets. */
|
||||
error0 = ip4_get_fragment_offset (ip0) == 1 ?
|
||||
IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
|
||||
|
||||
/* Verify lengths. */
|
||||
ip_len0 = clib_net_to_host_u16 (ip0->length);
|
||||
|
||||
/* IP length must be at least minimal IP header. */
|
||||
error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
|
||||
|
||||
cur_len0 = vlib_buffer_length_in_chain (vm, p0);
|
||||
|
||||
len_diff0 = cur_len0 - ip_len0;
|
||||
|
||||
error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP4_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
|
||||
ICMP4_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
*next0 = IP4_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
*next0 = error0 != IP4_ERROR_OPTIONS ?
|
||||
IP4_INPUT_NEXT_DROP : IP4_INPUT_NEXT_PUNT;
|
||||
}
|
||||
|
||||
p0->error = error_node->errors[error0];
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
|
||||
#endif
|
@ -37,7 +37,7 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ip/ip6_input.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
#include <vnet/ppp/ppp.h>
|
||||
#include <vnet/hdlc/hdlc.h>
|
||||
@ -60,15 +60,6 @@ format_ip6_input_trace (u8 * s, va_list * va)
|
||||
return s;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IP6_INPUT_NEXT_DROP,
|
||||
IP6_INPUT_NEXT_LOOKUP,
|
||||
IP6_INPUT_NEXT_LOOKUP_MULTICAST,
|
||||
IP6_INPUT_NEXT_ICMP_ERROR,
|
||||
IP6_INPUT_N_NEXT,
|
||||
} ip6_input_next_t;
|
||||
|
||||
/* Validate IP v6 packets and pass them either to forwarding code
|
||||
or drop exception packets. */
|
||||
static uword
|
||||
@ -108,7 +99,7 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
|
||||
ip6_header_t *ip0, *ip1;
|
||||
u32 pi0, sw_if_index0, next0 = 0;
|
||||
u32 pi1, sw_if_index1, next1 = 0;
|
||||
u8 error0, error1, arc0, arc1;
|
||||
u8 arc0, arc1;
|
||||
|
||||
/* Prefetch next iteration. */
|
||||
{
|
||||
@ -173,65 +164,8 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
|
||||
|
||||
vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
|
||||
vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
|
||||
|
||||
error0 = error1 = IP6_ERROR_NONE;
|
||||
|
||||
/* Version != 6? Drop it. */
|
||||
error0 =
|
||||
(clib_net_to_host_u32
|
||||
(ip0->ip_version_traffic_class_and_flow_label) >> 28) !=
|
||||
6 ? IP6_ERROR_VERSION : error0;
|
||||
error1 =
|
||||
(clib_net_to_host_u32
|
||||
(ip1->ip_version_traffic_class_and_flow_label) >> 28) !=
|
||||
6 ? IP6_ERROR_VERSION : error1;
|
||||
|
||||
/* hop limit < 1? Drop it. for link-local broadcast packets,
|
||||
* like dhcpv6 packets from client has hop-limit 1, which should not
|
||||
* be dropped.
|
||||
*/
|
||||
error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
|
||||
error1 = ip1->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error1;
|
||||
|
||||
/* L2 length must be at least minimal IP header. */
|
||||
error0 =
|
||||
p0->current_length <
|
||||
sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
|
||||
error1 =
|
||||
p1->current_length <
|
||||
sizeof (ip1[0]) ? IP6_ERROR_TOO_SHORT : error1;
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP6_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
|
||||
ICMP6_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
next0 = IP6_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
next0 = IP6_INPUT_NEXT_DROP;
|
||||
}
|
||||
}
|
||||
if (PREDICT_FALSE (error1 != IP6_ERROR_NONE))
|
||||
{
|
||||
if (error1 == IP6_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
|
||||
ICMP6_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
next1 = IP6_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
next1 = IP6_INPUT_NEXT_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
p0->error = error_node->errors[error0];
|
||||
p1->error = error_node->errors[error1];
|
||||
ip6_input_check_x2 (vm, error_node,
|
||||
p0, p1, ip0, ip1, &next0, &next1);
|
||||
|
||||
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
|
||||
to_next, n_left_to_next,
|
||||
@ -243,7 +177,7 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
|
||||
vlib_buffer_t *p0;
|
||||
ip6_header_t *ip0;
|
||||
u32 pi0, sw_if_index0, next0 = 0;
|
||||
u8 error0, arc0;
|
||||
u8 arc0;
|
||||
|
||||
pi0 = from[0];
|
||||
to_next[0] = pi0;
|
||||
@ -271,40 +205,7 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
|
||||
vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
|
||||
|
||||
vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
|
||||
error0 = IP6_ERROR_NONE;
|
||||
|
||||
/* Version != 6? Drop it. */
|
||||
error0 =
|
||||
(clib_net_to_host_u32
|
||||
(ip0->ip_version_traffic_class_and_flow_label) >> 28) !=
|
||||
6 ? IP6_ERROR_VERSION : error0;
|
||||
|
||||
/* hop limit < 1? Drop it. for link-local broadcast packets,
|
||||
* like dhcpv6 packets from client has hop-limit 1, which should not
|
||||
* be dropped.
|
||||
*/
|
||||
error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
|
||||
|
||||
/* L2 length must be at least minimal IP header. */
|
||||
error0 =
|
||||
p0->current_length <
|
||||
sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP6_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
|
||||
ICMP6_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
next0 = IP6_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
next0 = IP6_INPUT_NEXT_DROP;
|
||||
}
|
||||
}
|
||||
p0->error = error_node->errors[error0];
|
||||
ip6_input_check_x1 (vm, error_node, p0, ip0, &next0);
|
||||
|
||||
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
|
||||
to_next, n_left_to_next,
|
||||
@ -317,7 +218,7 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
|
||||
return frame->n_vectors;
|
||||
}
|
||||
|
||||
static char *ip6_error_strings[] = {
|
||||
char *ip6_error_strings[] = {
|
||||
#define _(sym,string) string,
|
||||
foreach_ip6_error
|
||||
#undef _
|
||||
|
169
src/vnet/ip/ip6_input.h
Normal file
169
src/vnet/ip/ip6_input.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
/*
|
||||
* ip/ip6_input.c: IP v6 input node
|
||||
*
|
||||
* Copyright (c) 2008 Eliot Dresselhaus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef included_ip6_input_h
|
||||
#define included_ip6_input_h
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
|
||||
extern char *ip6_error_strings[];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IP6_INPUT_NEXT_DROP,
|
||||
IP6_INPUT_NEXT_LOOKUP,
|
||||
IP6_INPUT_NEXT_LOOKUP_MULTICAST,
|
||||
IP6_INPUT_NEXT_ICMP_ERROR,
|
||||
IP6_INPUT_N_NEXT,
|
||||
} ip6_input_next_t;
|
||||
|
||||
always_inline void
|
||||
ip6_input_check_x2 (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * error_node,
|
||||
vlib_buffer_t * p0, vlib_buffer_t * p1,
|
||||
ip6_header_t * ip0, ip6_header_t * ip1,
|
||||
u32 * next0, u32 * next1)
|
||||
{
|
||||
u8 error0, error1;
|
||||
|
||||
error0 = error1 = IP6_ERROR_NONE;
|
||||
|
||||
/* Version != 6? Drop it. */
|
||||
error0 =
|
||||
(clib_net_to_host_u32
|
||||
(ip0->ip_version_traffic_class_and_flow_label) >> 28) !=
|
||||
6 ? IP6_ERROR_VERSION : error0;
|
||||
error1 =
|
||||
(clib_net_to_host_u32
|
||||
(ip1->ip_version_traffic_class_and_flow_label) >> 28) !=
|
||||
6 ? IP6_ERROR_VERSION : error1;
|
||||
|
||||
/* hop limit < 1? Drop it. for link-local broadcast packets,
|
||||
* like dhcpv6 packets from client has hop-limit 1, which should not
|
||||
* be dropped.
|
||||
*/
|
||||
error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
|
||||
error1 = ip1->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error1;
|
||||
|
||||
/* L2 length must be at least minimal IP header. */
|
||||
error0 =
|
||||
p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
|
||||
error1 =
|
||||
p1->current_length < sizeof (ip1[0]) ? IP6_ERROR_TOO_SHORT : error1;
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP6_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
|
||||
ICMP6_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
*next0 = IP6_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
*next0 = IP6_INPUT_NEXT_DROP;
|
||||
}
|
||||
}
|
||||
if (PREDICT_FALSE (error1 != IP6_ERROR_NONE))
|
||||
{
|
||||
if (error1 == IP6_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
|
||||
ICMP6_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
*next1 = IP6_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
*next1 = IP6_INPUT_NEXT_DROP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
always_inline void
|
||||
ip6_input_check_x1 (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * error_node,
|
||||
vlib_buffer_t * p0, ip6_header_t * ip0, u32 * next0)
|
||||
{
|
||||
u8 error0;
|
||||
|
||||
error0 = IP6_ERROR_NONE;
|
||||
|
||||
/* Version != 6? Drop it. */
|
||||
error0 =
|
||||
(clib_net_to_host_u32
|
||||
(ip0->ip_version_traffic_class_and_flow_label) >> 28) !=
|
||||
6 ? IP6_ERROR_VERSION : error0;
|
||||
|
||||
/* hop limit < 1? Drop it. for link-local broadcast packets,
|
||||
* like dhcpv6 packets from client has hop-limit 1, which should not
|
||||
* be dropped.
|
||||
*/
|
||||
error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
|
||||
|
||||
/* L2 length must be at least minimal IP header. */
|
||||
error0 =
|
||||
p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
|
||||
|
||||
if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
|
||||
{
|
||||
if (error0 == IP6_ERROR_TIME_EXPIRED)
|
||||
{
|
||||
icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
|
||||
ICMP6_time_exceeded_ttl_exceeded_in_transit,
|
||||
0);
|
||||
*next0 = IP6_INPUT_NEXT_ICMP_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
*next0 = IP6_INPUT_NEXT_DROP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
135
test/test_ip4.py
135
test/test_ip4.py
@ -1227,5 +1227,140 @@ class TestIPDeag(VppTestCase):
|
||||
self.send_and_expect(self.pg0, pkts_src, self.pg2)
|
||||
|
||||
|
||||
class TestIPInput(VppTestCase):
|
||||
""" IPv4 Input Exceptions """
|
||||
|
||||
def setUp(self):
|
||||
super(TestIPInput, 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(TestIPInput, 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_input(self):
|
||||
""" IP Input Exceptions """
|
||||
|
||||
# i can't find a way in scapy to construct an IP packet
|
||||
# with a length less than the IP header length
|
||||
|
||||
#
|
||||
# Packet too short - this is forwarded
|
||||
#
|
||||
p_short = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4,
|
||||
dst=self.pg1.remote_ip4,
|
||||
len=40) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
|
||||
|
||||
#
|
||||
# Packet too long - this is dropped
|
||||
#
|
||||
p_long = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4,
|
||||
dst=self.pg1.remote_ip4,
|
||||
len=400) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
|
||||
"too long")
|
||||
|
||||
#
|
||||
# bad chksum - this is dropped
|
||||
#
|
||||
p_chksum = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4,
|
||||
dst=self.pg1.remote_ip4,
|
||||
chksum=400) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
|
||||
"bad checksum")
|
||||
|
||||
#
|
||||
# bad version - this is dropped
|
||||
#
|
||||
p_ver = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4,
|
||||
dst=self.pg1.remote_ip4,
|
||||
version=3) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
|
||||
"funky version")
|
||||
|
||||
#
|
||||
# fragment offset 1 - this is dropped
|
||||
#
|
||||
p_frag = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4,
|
||||
dst=self.pg1.remote_ip4,
|
||||
frag=1) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
|
||||
"frag offset")
|
||||
|
||||
#
|
||||
# TTL expired packet
|
||||
#
|
||||
p_ttl = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4,
|
||||
dst=self.pg1.remote_ip4,
|
||||
ttl=1) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
|
||||
|
||||
rx = rx[0]
|
||||
icmp = rx[ICMP]
|
||||
|
||||
self.assertEqual(icmptypes[icmp.type], "time-exceeded")
|
||||
self.assertEqual(icmpcodes[icmp.type][icmp.code],
|
||||
"ttl-zero-during-transit")
|
||||
self.assertEqual(icmp.src, self.pg0.remote_ip4)
|
||||
self.assertEqual(icmp.dst, self.pg1.remote_ip4)
|
||||
|
||||
self.logger.error(self.vapi.cli("sh error"))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
|
@ -16,7 +16,8 @@ from scapy.layers.l2 import Ether, Dot1Q
|
||||
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
|
||||
ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types, \
|
||||
ICMPv6TimeExceeded
|
||||
|
||||
from util import ppp
|
||||
from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \
|
||||
@ -1618,5 +1619,80 @@ class TestIP6Punt(VppTestCase):
|
||||
is_add=0,
|
||||
is_ip6=1)
|
||||
|
||||
|
||||
class TestIP6Input(VppTestCase):
|
||||
""" IPv6 Input Exceptions """
|
||||
|
||||
def setUp(self):
|
||||
super(TestIP6Input, 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(TestIP6Input, self).tearDown()
|
||||
for i in self.pg_interfaces:
|
||||
i.unconfig_ip6()
|
||||
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_input(self):
|
||||
""" IP6 Input Exceptions """
|
||||
|
||||
#
|
||||
# bad version - this is dropped
|
||||
#
|
||||
p_version = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IPv6(src=self.pg0.remote_ip6,
|
||||
dst=self.pg1.remote_ip6,
|
||||
version=3) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
self.send_and_assert_no_replies(self.pg0, p_version * 65,
|
||||
"funky version")
|
||||
|
||||
#
|
||||
# hop limit - IMCP replies
|
||||
#
|
||||
p_version = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IPv6(src=self.pg0.remote_ip6,
|
||||
dst=self.pg1.remote_ip6,
|
||||
hlim=1) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rx = self.send_and_expect(self.pg0, p_version * 65, self.pg0)
|
||||
rx = rx[0]
|
||||
icmp = rx[ICMPv6TimeExceeded]
|
||||
self.assertEqual(icmp.type, 3)
|
||||
# 0: "hop limit exceeded in transit",
|
||||
self.assertEqual(icmp.code, 0)
|
||||
|
||||
self.logger.error(self.vapi.cli("sh error"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
|
@ -106,6 +106,7 @@ class TestMPLS(VppTestCase):
|
||||
ping=0,
|
||||
ip_itf=None,
|
||||
dst_ip=None,
|
||||
chksum=None,
|
||||
n=257):
|
||||
self.reset_packet_infos()
|
||||
pkts = []
|
||||
@ -133,6 +134,8 @@ class TestMPLS(VppTestCase):
|
||||
dst=ip_itf.local_ip4) /
|
||||
ICMP())
|
||||
|
||||
if chksum:
|
||||
p[IP].chksum = chksum
|
||||
info.data = p.copy()
|
||||
pkts.append(p)
|
||||
return pkts
|
||||
@ -152,7 +155,7 @@ class TestMPLS(VppTestCase):
|
||||
return pkts
|
||||
|
||||
def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl,
|
||||
dst_ip=None):
|
||||
dst_ip=None, hlim=64):
|
||||
if dst_ip is None:
|
||||
dst_ip = src_if.remote_ip6
|
||||
self.reset_packet_infos()
|
||||
@ -162,7 +165,7 @@ class TestMPLS(VppTestCase):
|
||||
payload = self.info_to_payload(info)
|
||||
p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
|
||||
MPLS(label=mpls_label, ttl=mpls_ttl) /
|
||||
IPv6(src=src_if.remote_ip6, dst=dst_ip) /
|
||||
IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw(payload))
|
||||
info.data = p.copy()
|
||||
@ -1025,6 +1028,14 @@ class TestMPLS(VppTestCase):
|
||||
rx = self.pg1.get_capture(257)
|
||||
self.verify_capture_ip4(self.pg1, rx, tx)
|
||||
|
||||
#
|
||||
# disposed packets have an invalid IPv4 checkusm
|
||||
#
|
||||
tx = self.create_stream_labelled_ip4(self.pg0, [34],
|
||||
dst_ip="232.1.1.1", n=65,
|
||||
chksum=1)
|
||||
self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
|
||||
|
||||
#
|
||||
# set the RPF-ID of the enrtry to not match the input packet's
|
||||
#
|
||||
@ -1032,6 +1043,7 @@ class TestMPLS(VppTestCase):
|
||||
tx = self.create_stream_labelled_ip4(self.pg0, [34],
|
||||
dst_ip="232.1.1.1")
|
||||
self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
|
||||
self.logger.error(self.vapi.cli("sh error"))
|
||||
|
||||
def test_mcast_ip6_tail(self):
|
||||
""" MPLS IPv6 Multicast Tail """
|
||||
@ -1091,6 +1103,13 @@ class TestMPLS(VppTestCase):
|
||||
rx = self.pg1.get_capture(257)
|
||||
self.verify_capture_ip6(self.pg1, rx, tx)
|
||||
|
||||
#
|
||||
# disposed packets have hop-limit = 1
|
||||
#
|
||||
tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
|
||||
dst_ip="ff01::1", hlim=1)
|
||||
self.send_and_assert_no_replies(self.pg0, tx, "Hop Limt Expired")
|
||||
|
||||
#
|
||||
# set the RPF-ID of the enrtry to not match the input packet's
|
||||
#
|
||||
|
Reference in New Issue
Block a user