summaryrefslogtreecommitdiffstats
path: root/src/plugins/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/map')
-rw-r--r--src/plugins/map/ip6_map.c266
-rw-r--r--src/plugins/map/map.api30
-rw-r--r--src/plugins/map/map.c484
-rw-r--r--src/plugins/map/map.h99
-rw-r--r--src/plugins/map/map_api.c104
-rw-r--r--src/plugins/map/test/test_map.py25
6 files changed, 30 insertions, 978 deletions
diff --git a/src/plugins/map/ip6_map.c b/src/plugins/map/ip6_map.c
index f14b880de3f..96f81efc1cb 100644
--- a/src/plugins/map/ip6_map.c
+++ b/src/plugins/map/ip6_map.c
@@ -25,7 +25,6 @@ enum ip6_map_next_e
#ifdef MAP_SKIP_IP6_LOOKUP
IP6_MAP_NEXT_IP4_REWRITE,
#endif
- IP6_MAP_NEXT_IP6_REASS,
IP6_MAP_NEXT_IP4_REASS,
IP6_MAP_NEXT_IP4_FRAGMENT,
IP6_MAP_NEXT_IP6_ICMP_RELAY,
@@ -267,7 +266,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
}
else if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
{
- next0 = IP6_MAP_NEXT_IP6_REASS;
+ error0 = MAP_ERROR_FRAGMENTED;
}
else
{
@@ -294,7 +293,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
}
else if (ip61->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
{
- next1 = IP6_MAP_NEXT_IP6_REASS;
+ error1 = MAP_ERROR_FRAGMENTED;
}
else
{
@@ -474,7 +473,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
(((ip6_frag_hdr_t *) (ip60 + 1))->next_hdr ==
IP_PROTOCOL_IP_IN_IP))
{
- next0 = IP6_MAP_NEXT_IP6_REASS;
+ error0 = MAP_ERROR_FRAGMENTED;
}
else
{
@@ -553,102 +552,6 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
}
-static_always_inline void
-ip6_map_ip6_reass_prepare (vlib_main_t * vm, vlib_node_runtime_t * node,
- map_ip6_reass_t * r, u32 ** fragments_ready,
- u32 ** fragments_to_drop)
-{
- ip4_header_t *ip40;
- ip6_header_t *ip60;
- ip6_frag_hdr_t *frag0;
- vlib_buffer_t *p0;
-
- if (!r->ip4_header.ip_version_and_header_length)
- return;
-
- //The IP header is here, we need to check for packets
- //that can be forwarded
- int i;
- for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- {
- if (r->fragments[i].pi == ~0 ||
- ((!r->fragments[i].next_data_len)
- && (r->fragments[i].next_data_offset != (0xffff))))
- continue;
-
- p0 = vlib_get_buffer (vm, r->fragments[i].pi);
- ip60 = vlib_buffer_get_current (p0);
- frag0 = (ip6_frag_hdr_t *) (ip60 + 1);
- ip40 = (ip4_header_t *) (frag0 + 1);
-
- if (ip6_frag_hdr_offset (frag0))
- {
- //Not first fragment, add the IPv4 header
- clib_memcpy_fast (ip40, &r->ip4_header, 20);
- }
-
-#ifdef MAP_IP6_REASS_COUNT_BYTES
- r->forwarded +=
- clib_net_to_host_u16 (ip60->payload_length) - sizeof (*frag0);
-#endif
-
- if (ip6_frag_hdr_more (frag0))
- {
- //Not last fragment, we copy end of next
- clib_memcpy_fast (u8_ptr_add (ip60, p0->current_length),
- r->fragments[i].next_data, 20);
- p0->current_length += 20;
- ip60->payload_length = u16_net_add (ip60->payload_length, 20);
- }
-
- if (!ip4_is_fragment (ip40))
- {
- ip40->fragment_id = frag_id_6to4 (frag0->identification);
- ip40->flags_and_fragment_offset =
- clib_host_to_net_u16 (ip6_frag_hdr_offset (frag0));
- }
- else
- {
- ip40->flags_and_fragment_offset =
- clib_host_to_net_u16 (ip4_get_fragment_offset (ip40) +
- ip6_frag_hdr_offset (frag0));
- }
-
- if (ip6_frag_hdr_more (frag0))
- ip40->flags_and_fragment_offset |=
- clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS);
-
- ip40->length =
- clib_host_to_net_u16 (p0->current_length - sizeof (*ip60) -
- sizeof (*frag0));
- ip40->checksum = ip4_header_checksum (ip40);
-
- if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
- {
- map_ip6_map_ip6_reass_trace_t *tr =
- vlib_add_trace (vm, node, p0, sizeof (*tr));
- tr->offset = ip4_get_fragment_offset (ip40);
- tr->frag_len = clib_net_to_host_u16 (ip40->length) - sizeof (*ip40);
- tr->out = 1;
- }
-
- vec_add1 (*fragments_ready, r->fragments[i].pi);
- r->fragments[i].pi = ~0;
- r->fragments[i].next_data_len = 0;
- r->fragments[i].next_data_offset = 0;
- map_main.ip6_reass_buffered_counter--;
-
- //TODO: Best solution would be that ip6_map handles extension headers
- // and ignores atomic fragment. But in the meantime, let's just copy the header.
-
- u8 protocol = frag0->next_hdr;
- memmove (u8_ptr_add (ip40, -sizeof (*ip60)), ip60, sizeof (*ip60));
- ((ip6_header_t *) u8_ptr_add (ip40, -sizeof (*ip60)))->protocol =
- protocol;
- vlib_buffer_advance (p0, sizeof (*frag0));
- }
-}
-
void
map_ip6_drop_pi (u32 pi)
{
@@ -659,150 +562,6 @@ map_ip6_drop_pi (u32 pi)
}
/*
- * ip6_reass
- * TODO: We should count the number of successfully
- * transmitted fragment bytes and compare that to the last fragment
- * offset such that we can free the reassembly structure when all fragments
- * have been forwarded.
- */
-static uword
-ip6_map_ip6_reass (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
- vlib_node_runtime_t *error_node =
- vlib_node_get_runtime (vm, ip6_map_ip6_reass_node.index);
- u32 *fragments_to_drop = NULL;
- u32 *fragments_ready = NULL;
-
- from = vlib_frame_vector_args (frame);
- n_left_from = frame->n_vectors;
- next_index = node->cached_next_index;
- while (n_left_from > 0)
- {
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- /* Single loop */
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- u32 pi0;
- vlib_buffer_t *p0;
- u8 error0 = MAP_ERROR_NONE;
- ip6_header_t *ip60;
- ip6_frag_hdr_t *frag0;
- u16 offset;
- u16 next_offset;
- u16 frag_len;
-
- pi0 = to_next[0] = from[0];
- from += 1;
- n_left_from -= 1;
- to_next += 1;
- n_left_to_next -= 1;
-
- p0 = vlib_get_buffer (vm, pi0);
- ip60 = vlib_buffer_get_current (p0);
- frag0 = (ip6_frag_hdr_t *) (ip60 + 1);
- offset =
- clib_host_to_net_u16 (frag0->fragment_offset_and_more) & (~7);
- frag_len =
- clib_net_to_host_u16 (ip60->payload_length) - sizeof (*frag0);
- next_offset =
- ip6_frag_hdr_more (frag0) ? (offset + frag_len) : (0xffff);
-
- //FIXME: Support other extension headers, maybe
-
- if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
- {
- map_ip6_map_ip6_reass_trace_t *tr =
- vlib_add_trace (vm, node, p0, sizeof (*tr));
- tr->offset = offset;
- tr->frag_len = frag_len;
- tr->out = 0;
- }
-
- map_ip6_reass_lock ();
- map_ip6_reass_t *r =
- map_ip6_reass_get (&ip60->src_address, &ip60->dst_address,
- frag0->identification, frag0->next_hdr,
- &fragments_to_drop);
- //FIXME: Use better error codes
- if (PREDICT_FALSE (!r))
- {
- // Could not create a caching entry
- error0 = MAP_ERROR_FRAGMENT_MEMORY;
- }
- else if (PREDICT_FALSE ((frag_len <= 20 &&
- (ip6_frag_hdr_more (frag0) || (!offset)))))
- {
- //Very small fragment are restricted to the last one and
- //can't be the first one
- error0 = MAP_ERROR_FRAGMENT_MALFORMED;
- }
- else
- if (map_ip6_reass_add_fragment
- (r, pi0, offset, next_offset, (u8 *) (frag0 + 1), frag_len))
- {
- map_ip6_reass_free (r, &fragments_to_drop);
- error0 = MAP_ERROR_FRAGMENT_MEMORY;
- }
- else
- {
-#ifdef MAP_IP6_REASS_COUNT_BYTES
- if (!ip6_frag_hdr_more (frag0))
- r->expected_total = offset + frag_len;
-#endif
- ip6_map_ip6_reass_prepare (vm, node, r, &fragments_ready,
- &fragments_to_drop);
-#ifdef MAP_IP6_REASS_COUNT_BYTES
- if (r->forwarded >= r->expected_total)
- map_ip6_reass_free (r, &fragments_to_drop);
-#endif
- }
- map_ip6_reass_unlock ();
-
- if (error0 == MAP_ERROR_NONE)
- {
- if (frag_len > 20)
- {
- //Dequeue the packet
- n_left_to_next++;
- to_next--;
- }
- else
- {
- //All data from that packet was copied no need to keep it, but this is not an error
- p0->error = error_node->errors[MAP_ERROR_NONE];
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- pi0,
- IP6_MAP_IP6_REASS_NEXT_DROP);
- }
- }
- else
- {
- p0->error = error_node->errors[error0];
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
- n_left_to_next, pi0,
- IP6_MAP_IP6_REASS_NEXT_DROP);
- }
- }
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
-
- map_send_all_to_node (vm, fragments_ready, node,
- &error_node->errors[MAP_ERROR_NONE],
- IP6_MAP_IP6_REASS_NEXT_IP6_MAP);
- map_send_all_to_node (vm, fragments_to_drop, node,
- &error_node->errors[MAP_ERROR_FRAGMENT_DROPPED],
- IP6_MAP_IP6_REASS_NEXT_DROP);
-
- vec_free (fragments_to_drop);
- vec_free (fragments_ready);
- return frame->n_vectors;
-}
-
-/*
* ip6_map_post_ip4_reass
*/
static uword
@@ -1070,6 +829,7 @@ VNET_FEATURE_INIT (ip6_map_feature, static) =
.arc_name = "ip6-unicast",
.node_name = "ip6-map",
.runs_before = VNET_FEATURES ("ip6-flow-classify"),
+ .runs_after = VNET_FEATURES ("ip6-full-reassembly-feature"),
};
VLIB_REGISTER_NODE(ip6_map_node) = {
@@ -1088,7 +848,6 @@ VLIB_REGISTER_NODE(ip6_map_node) = {
#ifdef MAP_SKIP_IP6_LOOKUP
[IP6_MAP_NEXT_IP4_REWRITE] = "ip4-load-balance",
#endif
- [IP6_MAP_NEXT_IP6_REASS] = "ip6-map-ip6-reass",
[IP6_MAP_NEXT_IP4_REASS] = "ip4-sv-reassembly-custom-next",
[IP6_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag",
[IP6_MAP_NEXT_IP6_ICMP_RELAY] = "ip6-map-icmp-relay",
@@ -1100,23 +859,6 @@ VLIB_REGISTER_NODE(ip6_map_node) = {
/* *INDENT-ON* */
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE(ip6_map_ip6_reass_node) = {
- .function = ip6_map_ip6_reass,
- .name = "ip6-map-ip6-reass",
- .vector_size = sizeof(u32),
- .format_trace = format_ip6_map_ip6_reass_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = MAP_N_ERROR,
- .error_strings = map_error_strings,
- .n_next_nodes = IP6_MAP_IP6_REASS_N_NEXT,
- .next_nodes = {
- [IP6_MAP_IP6_REASS_NEXT_IP6_MAP] = "ip6-map",
- [IP6_MAP_IP6_REASS_NEXT_DROP] = "error-drop",
- },
-};
-/* *INDENT-ON* */
-
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE(ip6_map_post_ip4_reass_node) = {
.function = ip6_map_post_ip4_reass,
.name = "ip6-map-post-ip4-reass",
diff --git a/src/plugins/map/map.api b/src/plugins/map/map.api
index f2a7f84de98..857a1c8fcb0 100644
--- a/src/plugins/map/map.api
+++ b/src/plugins/map/map.api
@@ -241,28 +241,6 @@ autoreply define map_param_add_del_pre_resolve
vl_api_ip6_address_t ip6_nh_address;
};
-
-/** \brief Set MAP reassembly parameters
- @param client_index - opaque cookie to identify the sender
- @param context - sender context, to match reply w/ request
- @param is_ip6 - 1 = params apply to IPv6, 0 = params apply to IPv4
- @param lifetime_ms - reassembly valid lifetime, or ~0
- @param pool_size - max number of reassemblies, or ~0
- @param buffers - max number of reassembly buffers, or ~0
- @param ht_ratio - hash-table size factor, or ~0
-*/
-autoreply define map_param_set_reassembly
-{
- u32 client_index;
- u32 context;
- bool is_ip6;
- u16 lifetime_ms;
- u16 pool_size;
- u32 buffers;
- f64 ht_ratio;
-};
-
-
/** \brief Set MAP security-check parameters
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -326,10 +304,6 @@ define map_param_get
@param icmp6_enable_unreachable - 1 = send ICMP unreachable err msgs
@param ip4_nh_address - direct IP4 next-hop address
@param ip6_nh_address - direct IP6 next-hop address
- @param ip6_lifetime_ms - max number of reassemblies, or ~0
- @param ip6_pool_size - max number of reassemblies, or ~0
- @param ip6_buffers - max number of reassembly buffers, or ~0
- @param ip6_ht_ratio - hash-table size factor, or ~0
@param sec_check_enable - 1=enable security check on first inbound packet
@param sec_check_fragments - 1=enable check on (subsequent) fragments too
@param tc_copy - 1 = copy packet class/TOS field, 0 = use class instead
@@ -349,10 +323,6 @@ define map_param_get_reply
u16 ip4_pool_size;
u32 ip4_buffers;
f64 ip4_ht_ratio;
- u16 ip6_lifetime_ms;
- u16 ip6_pool_size;
- u32 ip6_buffers;
- f64 ip6_ht_ratio;
bool sec_check_enable;
bool sec_check_fragments;
bool tc_copy;
diff --git a/src/plugins/map/map.c b/src/plugins/map/map.c
index 904f0e9fd5e..7225fc62f81 100644
--- a/src/plugins/map/map.c
+++ b/src/plugins/map/map.c
@@ -966,23 +966,6 @@ format_map_domain (u8 * s, va_list * args)
return s;
}
-static u8 *
-format_map_ip6_reass (u8 * s, va_list * args)
-{
- map_main_t *mm = &map_main;
- map_ip6_reass_t *r = va_arg (*args, map_ip6_reass_t *);
- map_ip6_reass_key_t *k = &r->key;
- f64 now = vlib_time_now (mm->vlib_main);
- f64 lifetime = (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000);
- f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
- s = format (s,
- "ip6-reass src=%U dst=%U protocol=%d identifier=%d lifetime=%.3lf\n",
- format_ip6_address, &k->src.as_u8, format_ip6_address,
- &k->dst.as_u8, k->protocol,
- clib_net_to_host_u32 (k->fragment_id), dt);
- return s;
-}
-
static clib_error_t *
show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
@@ -1041,19 +1024,6 @@ done:
return error;
}
-static clib_error_t *
-show_map_fragments_command_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- map_main_t *mm = &map_main;
- map_ip6_reass_t *f6;
-
- /* *INDENT-OFF* */
- pool_foreach(f6, mm->ip6_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip6_reass, f6);}));
- /* *INDENT-ON* */
- return (0);
-}
-
u64
map_error_counter_get (u32 node_index, map_error_t map_error)
{
@@ -1170,101 +1140,6 @@ show_map_stats_command_fn (vlib_main_t * vm, unformat_input_t * input,
}
static clib_error_t *
-map_params_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- u32 lifetime = ~0;
- f64 ht_ratio = (MAP_IP6_REASS_CONF_HT_RATIO_MAX + 1);
- u32 pool_size = ~0;
- u64 buffers = ~(0ull);
- u8 ip4 = 0, ip6 = 0;
-
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "lifetime %u", &lifetime))
- ;
- else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
- ;
- else if (unformat (line_input, "pool-size %u", &pool_size))
- ;
- else if (unformat (line_input, "buffers %llu", &buffers))
- ;
- else if (unformat (line_input, "ip4"))
- ip4 = 1;
- else if (unformat (line_input, "ip6"))
- ip6 = 1;
- else
- {
- unformat_free (line_input);
- return clib_error_return (0, "invalid input");
- }
- }
- unformat_free (line_input);
-
- if (!ip4 && !ip6)
- return clib_error_return (0, "must specify ip4 and/or ip6");
-
- if (ip4)
- {
- return clib_error_return (0,
- "ip4 reassembly no longer supported in map");
- }
-
- if (ip6)
- {
- if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
- return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
- MAP_IP6_REASS_CONF_POOL_SIZE_MAX);
- if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
- return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
- MAP_IP6_REASS_CONF_HT_RATIO_MAX);
- if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
- return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
- MAP_IP6_REASS_CONF_LIFETIME_MAX);
- if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
- return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
- MAP_IP6_REASS_CONF_BUFFERS_MAX);
- }
-
- int rv;
- u32 reass = 0, packets = 0;
- rv = map_param_set_reassembly (!ip4, lifetime, pool_size, buffers, ht_ratio,
- &reass, &packets);
-
- switch (rv)
- {
- case 0:
- vlib_cli_output (vm,
- "Note: destroyed-reassembly=%u , dropped-fragments=%u",
- reass, packets);
- break;
-
- case MAP_ERR_BAD_POOL_SIZE:
- return clib_error_return (0, "Could not set reass pool-size");
-
- case MAP_ERR_BAD_HT_RATIO:
- return clib_error_return (0, "Could not set reass ht-log2len");
-
- case MAP_ERR_BAD_LIFETIME:
- return clib_error_return (0, "Could not set ip6-reass lifetime");
-
- case MAP_ERR_BAD_BUFFERS:
- return clib_error_return (0, "Could not set ip6-reass buffers");
-
- case MAP_ERR_BAD_BUFFERS_TOO_LARGE:
- return clib_error_return (0,
- "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
- }
-
- return 0;
-}
-
-
-static clib_error_t *
map_if_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
@@ -1333,325 +1208,6 @@ format_map_trace (u8 * s, va_list * args)
return s;
}
-static_always_inline map_ip6_reass_t *
-map_ip6_reass_lookup (map_ip6_reass_key_t * k, u32 bucket, f64 now)
-{
- map_main_t *mm = &map_main;
- u32 ri = mm->ip6_reass_hash_table[bucket];
- while (ri != MAP_REASS_INDEX_NONE)
- {
- map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
- if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
- r->key.as_u64[0] == k->as_u64[0] &&
- r->key.as_u64[1] == k->as_u64[1] &&
- r->key.as_u64[2] == k->as_u64[2] &&
- r->key.as_u64[3] == k->as_u64[3] &&
- r->key.as_u64[4] == k->as_u64[4])
- return r;
- ri = r->bucket_next;
- }
- return NULL;
-}
-
-#define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
-
-void
-map_ip6_reass_free (map_ip6_reass_t * r, u32 ** pi_to_drop)
-{
- map_main_t *mm = &map_main;
- int i;
- for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- if (r->fragments[i].pi != ~0)
- {
- vec_add1 (*pi_to_drop, r->fragments[i].pi);
- r->fragments[i].pi = ~0;
- map_main.ip6_reass_buffered_counter--;
- }
-
- // Unlink in hash bucket
- map_ip6_reass_t *r2 = NULL;
- u32 r2i = mm->ip6_reass_hash_table[r->bucket];
- while (r2i != map_ip6_reass_pool_index (r))
- {
- ASSERT (r2i != MAP_REASS_INDEX_NONE);
- r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
- r2i = r2->bucket_next;
- }
- if (r2)
- {
- r2->bucket_next = r->bucket_next;
- }
- else
- {
- mm->ip6_reass_hash_table[r->bucket] = r->bucket_next;
- }
-
- // Unlink in list
- if (r->fifo_next == map_ip6_reass_pool_index (r))
- {
- //Single element in the list, list is now empty
- mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
- }
- else
- {
- if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r)) //First element
- mm->ip6_reass_fifo_last = r->fifo_prev;
- pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
- r->fifo_next;
- pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
- r->fifo_prev;
- }
-
- // Free from pool if necessary
- pool_put (mm->ip6_reass_pool, r);
- mm->ip6_reass_allocated--;
-}
-
-map_ip6_reass_t *
-map_ip6_reass_get (ip6_address_t * src, ip6_address_t * dst, u32 fragment_id,
- u8 protocol, u32 ** pi_to_drop)
-{
- map_ip6_reass_t *r;
- map_main_t *mm = &map_main;
- map_ip6_reass_key_t k = {
- .src = *src,
- .dst = *dst,
- .fragment_id = fragment_id,
- .protocol = protocol
- };
-
- u32 h = 0;
- int i;
-
-#ifdef clib_crc32c_uses_intrinsics
- h = clib_crc32c ((u8 *) k.as_u32, 40);
-#else
- u64 tmp =
- k.as_u64[0] ^ k.as_u64[1] ^ k.as_u64[2] ^ k.as_u64[3] ^ k.as_u64[4];
- h = clib_xxhash (tmp);
-#endif
-
- h = h >> (32 - mm->ip6_reass_ht_log2len);
-
- f64 now = vlib_time_now (mm->vlib_main);
-
- //Cache garbage collection
- while (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
- {
- map_ip6_reass_t *last =
- pool_elt_at_index (mm->ip6_reass_pool, mm->ip6_reass_fifo_last);
- if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
- map_ip6_reass_free (last, pi_to_drop);
- else
- break;
- }
-
- if ((r = map_ip6_reass_lookup (&k, h, now)))
- return r;
-
- if (mm->ip6_reass_allocated >= mm->ip6_reass_conf_pool_size)
- return NULL;
-
- pool_get (mm->ip6_reass_pool, r);
- mm->ip6_reass_allocated++;
- for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- {
- r->fragments[i].pi = ~0;
- r->fragments[i].next_data_len = 0;
- r->fragments[i].next_data_offset = 0;
- }
-
- u32 ri = map_ip6_reass_pool_index (r);
-
- //Link in new bucket
- r->bucket = h;
- r->bucket_next = mm->ip6_reass_hash_table[h];
- mm->ip6_reass_hash_table[h] = ri;
-
- //Link in fifo
- if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
- {
- r->fifo_next =
- pool_elt_at_index (mm->ip6_reass_pool,
- mm->ip6_reass_fifo_last)->fifo_next;
- r->fifo_prev = mm->ip6_reass_fifo_last;
- pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
- pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
- }
- else
- {
- r->fifo_next = r->fifo_prev = ri;
- mm->ip6_reass_fifo_last = ri;
- }
-
- //Set other fields
- r->ts = now;
- r->key = k;
- r->ip4_header.ip_version_and_header_length = 0;
-#ifdef MAP_IP6_REASS_COUNT_BYTES
- r->expected_total = 0xffff;
- r->forwarded = 0;
-#endif
- return r;
-}
-
-int
-map_ip6_reass_add_fragment (map_ip6_reass_t * r, u32 pi,
- u16 data_offset, u16 next_data_offset,
- u8 * data_start, u16 data_len)
-{
- map_ip6_fragment_t *f = NULL, *prev_f = NULL;
- u16 copied_len = (data_len > 20) ? 20 : data_len;
-
- if (map_main.ip6_reass_buffered_counter >= map_main.ip6_reass_conf_buffers)
- return -1;
-
- //Lookup for fragments for the current buffer
- //and the one before that
- int i;
- for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- {
- if (data_offset && r->fragments[i].next_data_offset == data_offset)
- {
- prev_f = &r->fragments[i]; // This is buffer for previous packet
- }
- else if (r->fragments[i].next_data_offset == next_data_offset)
- {
- f = &r->fragments[i]; // This is a buffer for the current packet
- }
- else if (r->fragments[i].next_data_offset == 0)
- { //Available
- if (f == NULL)
- f = &r->fragments[i];
- else if (prev_f == NULL)
- prev_f = &r->fragments[i];
- }
- }
-
- if (!f || f->pi != ~0)
- return -1;
-
- if (data_offset)
- {
- if (!prev_f)
- return -1;
-
- clib_memcpy_fast (prev_f->next_data, data_start, copied_len);
- prev_f->next_data_len = copied_len;
- prev_f->next_data_offset = data_offset;
- }
- else
- {
- if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
- return -1;
-
- if (r->ip4_header.ip_version_and_header_length == 0)
- clib_memcpy_fast (&r->ip4_header, data_start, sizeof (ip4_header_t));
- }
-
- if (data_len > 20)
- {
- f->next_data_offset = next_data_offset;
- f->pi = pi;
- map_main.ip6_reass_buffered_counter++;
- }
- return 0;
-}
-
-u8
-map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
-{
- u32 desired_size = (u32) (pool_size * ht_ratio);
- u8 i;
- for (i = 1; i < 31; i++)
- if ((1 << i) >= desired_size)
- return i;
- return 4;
-}
-
-void
-map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
-{
- map_main_t *mm = &map_main;
- if (dropped_packets)
- *dropped_packets = mm->ip6_reass_buffered_counter;
- if (trashed_reass)
- *trashed_reass = mm->ip6_reass_allocated;
- int i;
- if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
- {
- u16 ri = mm->ip6_reass_fifo_last;
- do
- {
- map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
- for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- if (r->fragments[i].pi != ~0)
- map_ip6_drop_pi (r->fragments[i].pi);
-
- ri = r->fifo_next;
- pool_put (mm->ip6_reass_pool, r);
- }
- while (ri != mm->ip6_reass_fifo_last);
- mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
- }
-
- vec_free (mm->ip6_reass_hash_table);
- vec_resize (mm->ip6_reass_hash_table, 1 << mm->ip6_reass_ht_log2len);
- for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
- mm->ip6_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
- pool_free (mm->ip6_reass_pool);
- pool_alloc (mm->ip6_reass_pool, mm->ip6_reass_conf_pool_size);
-
- mm->ip6_reass_allocated = 0;
- mm->ip6_reass_buffered_counter = 0;
-}
-
-int
-map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
- u32 * dropped_packets)
-{
- map_main_t *mm = &map_main;
- if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
- return -1;
-
- map_ip6_reass_lock ();
- mm->ip6_reass_conf_ht_ratio = ht_ratio;
- mm->ip6_reass_ht_log2len =
- map_get_ht_log2len (ht_ratio, mm->ip6_reass_conf_pool_size);
- map_ip6_reass_reinit (trashed_reass, dropped_packets);
- map_ip6_reass_unlock ();
- return 0;
-}
-
-int
-map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
- u32 * dropped_packets)
-{
- map_main_t *mm = &map_main;
- if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
- return -1;
-
- map_ip6_reass_lock ();
- mm->ip6_reass_conf_pool_size = pool_size;
- map_ip6_reass_reinit (trashed_reass, dropped_packets);
- map_ip6_reass_unlock ();
- return 0;
-}
-
-int
-map_ip6_reass_conf_lifetime (u16 lifetime_ms)
-{
- map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
- return 0;
-}
-
-int
-map_ip6_reass_conf_buffers (u32 buffers)
-{
- map_main.ip6_reass_conf_buffers = buffers;
- return 0;
-}
-
static clib_error_t *
map_tcp_mss_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -1694,21 +1250,6 @@ done:
/* *INDENT-OFF* */
/*?
- * Configure MAP reassembly behaviour
- *
- * @cliexpar
- * @cliexstart{map params reassembly}
- * @cliexend
- ?*/
-VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = {
- .path = "map params reassembly",
- .short_help = "map params reassembly [ip4 | ip6] [lifetime <lifetime-ms>] "
- "[pool-size <pool-size>] [buffers <buffers>] "
- "[ht-ratio <ht-ratio>]",
- .function = map_params_reass_command_fn,
-};
-
-/*?
* Set or copy the IP TOS/Traffic Class field
*
* @cliexpar
@@ -1907,19 +1448,6 @@ VLIB_CLI_COMMAND(show_map_stats_command, static) = {
};
/*?
- * Show MAP fragmentation information
- *
- * @cliexpar
- * @cliexstart{show map fragments}
- * @cliexend
- ?*/
-VLIB_CLI_COMMAND(show_map_fragments_command, static) = {
- .path = "show map fragments",
- .short_help = "show map fragments",
- .function = show_map_fragments_command_fn,
-};
-
-/*?
* Enable MAP processing on interface (input feature)
*
?*/
@@ -1983,18 +1511,6 @@ map_init (vlib_main_t * vm)
mm->icmp_relayed.stat_segment_name = "/map/icmp-relayed";
/* IP6 virtual reassembly */
- mm->ip6_reass_hash_table = 0;
- mm->ip6_reass_pool = 0;
- clib_spinlock_init (&mm->ip6_reass_lock);
- mm->ip6_reass_conf_ht_ratio = MAP_IP6_REASS_HT_RATIO_DEFAULT;
- mm->ip6_reass_conf_lifetime_ms = MAP_IP6_REASS_LIFETIME_DEFAULT;
- mm->ip6_reass_conf_pool_size = MAP_IP6_REASS_POOL_SIZE_DEFAULT;
- mm->ip6_reass_conf_buffers = MAP_IP6_REASS_BUFFERS_DEFAULT;
- mm->ip6_reass_ht_log2len =
- map_get_ht_log2len (mm->ip6_reass_conf_ht_ratio,
- mm->ip6_reass_conf_pool_size);
- mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
- map_ip6_reass_reinit (NULL, NULL);
#ifdef MAP_SKIP_IP6_LOOKUP
fib_node_register_type (FIB_NODE_TYPE_MAP_E, &map_vft);
diff --git a/src/plugins/map/map.h b/src/plugins/map/map.h
index 8098a798aee..9581bd50fac 100644
--- a/src/plugins/map/map.h
+++ b/src/plugins/map/map.h
@@ -50,9 +50,6 @@ int map_param_set_fragmentation (bool inner, bool ignore_df);
int map_param_set_icmp (ip4_address_t * ip4_err_relay_src);
int map_param_set_icmp6 (u8 enable_unreachable);
void map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6, bool is_del);
-int map_param_set_reassembly (bool is_ipv6, u16 lifetime_ms, u16 pool_size,
- u32 buffers, f64 ht_ratio, u32 * reass,
- u32 * packets);
int map_param_set_security_check (bool enable, bool fragments);
int map_param_set_traffic_class (bool copy, u8 tc);
int map_param_set_tcp (u16 tcp_mss);
@@ -65,15 +62,6 @@ typedef enum
MAP_DOMAIN_RFC6052 = 1 << 2,
} __attribute__ ((__packed__)) map_domain_flags_e;
-#define MAP_IP6_REASS_LIFETIME_DEFAULT (100) /* ms */
-#define MAP_IP6_REASS_HT_RATIO_DEFAULT (1.0)
-#define MAP_IP6_REASS_POOL_SIZE_DEFAULT 1024 // Number of reassembly structures
-#define MAP_IP6_REASS_BUFFERS_DEFAULT 2048
-
-#define MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY 5
-
-#define MAP_IP6_REASS_COUNT_BYTES
-
//#define IP6_MAP_T_OVERRIDE_TOS 0
/*
@@ -136,46 +124,6 @@ typedef enum
MAP_N_DOMAIN_COUNTER
} map_domain_counter_t;
-/*
- * main_main_t
- */
-/* *INDENT-OFF* */
-typedef union {
- CLIB_PACKED (struct {
- ip6_address_t src;
- ip6_address_t dst;
- u32 fragment_id;
- u8 protocol;
- });
- u64 as_u64[5];
- u32 as_u32[10];
-} map_ip6_reass_key_t;
-/* *INDENT-ON* */
-
-typedef struct
-{
- u32 pi; //Cached packet or ~0
- u16 next_data_offset; //The data offset of the additional 20 bytes or ~0
- u8 next_data_len; //Number of bytes ready to be copied (20 if not last fragment)
- u8 next_data[20]; //The 20 additional bytes
-} map_ip6_fragment_t;
-
-typedef struct
-{
- map_ip6_reass_key_t key;
- f64 ts;
-#ifdef MAP_IP6_REASS_COUNT_BYTES
- u16 expected_total;
- u16 forwarded;
-#endif
- u16 bucket; //What hash bucket this element is linked in
- u16 bucket_next;
- u16 fifo_prev;
- u16 fifo_next;
- ip4_header_t ip4_header;
- map_ip6_fragment_t fragments[MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY];
-} map_ip6_reass_t;
-
#ifdef MAP_SKIP_IP6_LOOKUP
/**
* A pre-resolved next-hop
@@ -245,26 +193,6 @@ typedef struct
bool frag_inner; /* Inner or outer fragmentation */
bool frag_ignore_df; /* Fragment (outer) packet even if DF is set */
- /*
- * IPv6 decap reassembly
- */
- /* Configuration */
- f32 ip6_reass_conf_ht_ratio; //Size of ht is 2^ceil(log2(ratio*pool_size))
- u16 ip6_reass_conf_pool_size; //Max number of allocated reass structures
- u16 ip6_reass_conf_lifetime_ms; //Time a reassembly struct is considered valid in ms
- u32 ip6_reass_conf_buffers; //Maximum number of buffers used by ip6 reassembly
-
- /* Runtime */
- map_ip6_reass_t *ip6_reass_pool;
- u8 ip6_reass_ht_log2len; //Hash table size is 2^log2len
- u16 ip6_reass_allocated;
- u16 *ip6_reass_hash_table;
- u16 ip6_reass_fifo_last;
- clib_spinlock_t ip6_reass_lock;
-
- /* Counters */
- u32 ip6_reass_buffered_counter;
-
/* Graph node state */
uword *bm_trans_enabled_by_sw_if;
uword *bm_encap_enabled_by_sw_if;
@@ -445,35 +373,8 @@ ip6_map_get_domain (ip6_address_t * addr, u32 * map_domain_index, u8 * error)
clib_error_t *map_plugin_api_hookup (vlib_main_t * vm);
-map_ip6_reass_t *map_ip6_reass_get (ip6_address_t * src, ip6_address_t * dst,
- u32 fragment_id, u8 protocol,
- u32 ** pi_to_drop);
-void map_ip6_reass_free (map_ip6_reass_t * r, u32 ** pi_to_drop);
-
-#define map_ip6_reass_lock() clib_spinlock_lock (&map_main.ip6_reass_lock)
-#define map_ip6_reass_unlock() clib_spinlock_unlock (&map_main.ip6_reass_lock)
-
-int
-map_ip6_reass_add_fragment (map_ip6_reass_t * r, u32 pi,
- u16 data_offset, u16 next_data_offset,
- u8 * data_start, u16 data_len);
-
-void map_ip4_drop_pi (u32 pi);
-
void map_ip6_drop_pi (u32 pi);
-
-int map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
- u32 * dropped_packets);
-#define MAP_IP6_REASS_CONF_HT_RATIO_MAX 100
-int map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
- u32 * dropped_packets);
-#define MAP_IP6_REASS_CONF_POOL_SIZE_MAX (0xfeff)
-int map_ip6_reass_conf_lifetime (u16 lifetime_ms);
-#define MAP_IP6_REASS_CONF_LIFETIME_MAX 0xffff
-int map_ip6_reass_conf_buffers (u32 buffers);
-#define MAP_IP6_REASS_CONF_BUFFERS_MAX (0xffffffff)
-
/*
* Supports prefix of 96 or 64 (with u-octet)
*/
diff --git a/src/plugins/map/map_api.c b/src/plugins/map/map_api.c
index ea3212a4960..418f6a02a36 100644
--- a/src/plugins/map/map_api.c
+++ b/src/plugins/map/map_api.c
@@ -24,6 +24,7 @@
#include <vnet/ip/ip.h>
#include <vnet/ip/reass/ip4_sv_reass.h>
#include <vnet/ip/reass/ip6_sv_reass.h>
+#include <vnet/ip/reass/ip6_full_reass.h>
#include <vnet/fib/fib_table.h>
#include <vlibmemory/api.h>
@@ -330,102 +331,6 @@ static void
REPLY_MACRO (VL_API_MAP_PARAM_ADD_DEL_PRE_RESOLVE_REPLY);
}
-
-int
-map_param_set_reassembly (bool is_ipv6,
- u16 lifetime_ms,
- u16 pool_size,
- u32 buffers,
- f64 ht_ratio, u32 * reass, u32 * packets)
-{
- u32 ps_reass = 0, ps_packets = 0;
- u32 ht_reass = 0, ht_packets = 0;
-
- if (is_ipv6)
- {
- if (pool_size != (u16) ~ 0)
- {
- if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
- return MAP_ERR_BAD_POOL_SIZE;
- if (map_ip6_reass_conf_pool_size
- (pool_size, &ps_reass, &ps_packets))
- return MAP_ERR_BAD_POOL_SIZE;
- }
-
- if (ht_ratio != (MAP_IP6_REASS_CONF_HT_RATIO_MAX + 1))
- {
- if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
- return MAP_ERR_BAD_HT_RATIO;
- if (map_ip6_reass_conf_ht_ratio (ht_ratio, &ht_reass, &ht_packets))
- return MAP_ERR_BAD_HT_RATIO;
- }
-
- if (lifetime_ms != (u16) ~ 0)
- {
- if (lifetime_ms > MAP_IP6_REASS_CONF_LIFETIME_MAX)
- return MAP_ERR_BAD_LIFETIME;
- if (map_ip6_reass_conf_lifetime (lifetime_ms))
- return MAP_ERR_BAD_LIFETIME;
- }
-
- if (buffers != ~0)
- {
- if (buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
- return MAP_ERR_BAD_BUFFERS;
- if (map_ip6_reass_conf_buffers (buffers))
- return MAP_ERR_BAD_BUFFERS;
- }
-
- if (map_main.ip6_reass_conf_buffers >
- map_main.ip6_reass_conf_pool_size *
- MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY)
- {
- return MAP_ERR_BAD_BUFFERS_TOO_LARGE;
- }
- }
- else
- {
- return MAP_ERR_UNSUPPORTED;
- }
-
- if (reass)
- *reass = ps_reass + ht_reass;
-
- if (packets)
- *packets = ps_packets + ht_packets;
-
- return 0;
-}
-
-
-static void
- vl_api_map_param_set_reassembly_t_handler
- (vl_api_map_param_set_reassembly_t * mp)
-{
- map_main_t *mm = &map_main;
- vl_api_map_param_set_reassembly_reply_t *rmp;
- u32 reass = 0, packets = 0;
- int rv;
- f64 ht_ratio;
-
- ht_ratio = (f64) clib_net_to_host_f64 (mp->ht_ratio);
- if (ht_ratio == ~0)
- ht_ratio = MAP_IP6_REASS_CONF_HT_RATIO_MAX + 1;
-
- rv = map_param_set_reassembly (mp->is_ip6,
- clib_net_to_host_u16 (mp->lifetime_ms),
- clib_net_to_host_u16 (mp->pool_size),
- clib_net_to_host_u32 (mp->buffers),
- ht_ratio, &reass, &packets);
-
- /*
- * FIXME: Should the lost reass and packet counts be returned in the API?
- */
-
- REPLY_MACRO (VL_API_MAP_PARAM_SET_REASSEMBLY_REPLY);
-}
-
-
int
map_param_set_security_check (bool enable, bool fragments)
{
@@ -530,12 +435,6 @@ vl_api_map_param_get_t_handler (vl_api_map_param_get_t * mp)
clib_memset (&rmp->ip4_nh_address, 0, sizeof (rmp->ip4_nh_address));
clib_memset (&rmp->ip6_nh_address, 0, sizeof (rmp->ip6_nh_address));
- rmp->ip6_lifetime_ms =
- clib_net_to_host_u16 (mm->ip6_reass_conf_lifetime_ms);
- rmp->ip6_pool_size = clib_net_to_host_u16 (mm->ip6_reass_conf_pool_size);
- rmp->ip6_buffers = clib_net_to_host_u32 (mm->ip6_reass_conf_buffers);
- rmp->ip6_ht_ratio = clib_net_to_host_f64 (mm->ip6_reass_conf_ht_ratio);
-
rmp->sec_check_enable = mm->sec_check;
rmp->sec_check_fragments = mm->sec_check_frag;
@@ -573,6 +472,7 @@ map_if_enable_disable (bool is_enable, u32 sw_if_index, bool is_translation)
if (is_translation == false)
{
ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, is_enable);
+ ip6_full_reass_enable_disable_with_refcnt (sw_if_index, is_enable);
vnet_feature_enable_disable ("ip4-unicast", "ip4-map", sw_if_index,
is_enable ? 1 : 0, 0, 0);
vnet_feature_enable_disable ("ip6-unicast", "ip6-map", sw_if_index,
diff --git a/src/plugins/map/test/test_map.py b/src/plugins/map/test/test_map.py
index 368cf51092d..5549d9f0751 100644
--- a/src/plugins/map/test/test_map.py
+++ b/src/plugins/map/test/test_map.py
@@ -7,7 +7,7 @@ from ipaddress import IPv6Network, IPv4Network
from framework import VppTestCase, VppTestRunner
from vpp_ip import DpoProto
from vpp_ip_route import VppIpRoute, VppRoutePath
-from util import fragment_rfc791
+from util import fragment_rfc791, fragment_rfc8200
import scapy.compat
from scapy.layers.l2 import Ether, Raw
@@ -232,6 +232,29 @@ class TestMAP(VppTestCase):
self.assertEqual(r[IP].src, p[IP].src)
self.assertEqual(r[IP].dst, p[IP].dst)
+ # Verify that fragments pass even if ipv6 layer is fragmented
+ stream = (IPv6(dst='3000::1', src=map_translated_addr) / x
+ for x in frags)
+
+ v6_stream = [
+ Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / x
+ for i in range(len(frags))
+ for x in fragment_rfc8200(
+ IPv6(dst='3000::1', src=map_translated_addr) / frags[i],
+ i, 200)]
+
+ self.pg1.add_stream(v6_stream)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg0.get_capture(len(frags))
+
+ for r in rx:
+ self.assertFalse(r.haslayer(IPv6))
+ self.assertEqual(r[IP].src, p[IP].src)
+ self.assertEqual(r[IP].dst, p[IP].dst)
+
#
# Pre-resolve. No API for this!!
#