-static_always_inline map_ip4_reass_t *
-map_ip4_reass_lookup (map_ip4_reass_key_t * k, u32 bucket, f64 now)
-{
- map_main_t *mm = &map_main;
- u32 ri = mm->ip4_reass_hash_table[bucket];
- while (ri != MAP_REASS_INDEX_NONE)
- {
- map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
- if (r->key.as_u64[0] == k->as_u64[0] &&
- r->key.as_u64[1] == k->as_u64[1] &&
- now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
- {
- return r;
- }
- ri = r->bucket_next;
- }
- return NULL;
-}
-
-#define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
-
-void
-map_ip4_reass_free (map_ip4_reass_t * r, u32 ** pi_to_drop)
-{
- map_main_t *mm = &map_main;
- map_ip4_reass_get_fragments (r, pi_to_drop);
-
- // Unlink in hash bucket
- map_ip4_reass_t *r2 = NULL;
- u32 r2i = mm->ip4_reass_hash_table[r->bucket];
- while (r2i != map_ip4_reass_pool_index (r))
- {
- ASSERT (r2i != MAP_REASS_INDEX_NONE);
- r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
- r2i = r2->bucket_next;
- }
- if (r2)
- {
- r2->bucket_next = r->bucket_next;
- }
- else
- {
- mm->ip4_reass_hash_table[r->bucket] = r->bucket_next;
- }
-
- // Unlink in list
- if (r->fifo_next == map_ip4_reass_pool_index (r))
- {
- mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
- }
- else
- {
- if (mm->ip4_reass_fifo_last == map_ip4_reass_pool_index (r))
- mm->ip4_reass_fifo_last = r->fifo_prev;
- pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
- r->fifo_next;
- pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
- r->fifo_prev;
- }
-
- pool_put (mm->ip4_reass_pool, r);
- mm->ip4_reass_allocated--;
-}
-
-map_ip4_reass_t *
-map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
- u8 protocol, u32 ** pi_to_drop)
-{
- map_ip4_reass_t *r;
- map_main_t *mm = &map_main;
- map_ip4_reass_key_t k = {.src.data_u32 = src,
- .dst.data_u32 = dst,
- .fragment_id = fragment_id,
- .protocol = protocol
- };
-
- u32 h = 0;
-#ifdef clib_crc32c_uses_intrinsics
- h = clib_crc32c ((u8 *) k.as_u32, 16);
-#else
- u64 tmp = k.as_u32[0] ^ k.as_u32[1] ^ k.as_u32[2] ^ k.as_u32[3];
- h = clib_xxhash (tmp);
-#endif
- h = h >> (32 - mm->ip4_reass_ht_log2len);
-
- f64 now = vlib_time_now (mm->vlib_main);
-
- //Cache garbage collection
- while (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
- {
- map_ip4_reass_t *last =
- pool_elt_at_index (mm->ip4_reass_pool, mm->ip4_reass_fifo_last);
- if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
- map_ip4_reass_free (last, pi_to_drop);
- else
- break;
- }
-
- if ((r = map_ip4_reass_lookup (&k, h, now)))
- return r;
-
- if (mm->ip4_reass_allocated >= mm->ip4_reass_conf_pool_size)
- return NULL;
-
- pool_get (mm->ip4_reass_pool, r);
- mm->ip4_reass_allocated++;
- int i;
- for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- r->fragments[i] = ~0;
-
- u32 ri = map_ip4_reass_pool_index (r);
-
- //Link in new bucket
- r->bucket = h;
- r->bucket_next = mm->ip4_reass_hash_table[h];
- mm->ip4_reass_hash_table[h] = ri;
-
- //Link in fifo
- if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
- {
- r->fifo_next =
- pool_elt_at_index (mm->ip4_reass_pool,
- mm->ip4_reass_fifo_last)->fifo_next;
- r->fifo_prev = mm->ip4_reass_fifo_last;
- pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
- pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
- }
- else
- {
- r->fifo_next = r->fifo_prev = ri;
- mm->ip4_reass_fifo_last = ri;
- }
-
- //Set other fields
- r->ts = now;
- r->key = k;
- r->port = -1;
-#ifdef MAP_IP4_REASS_COUNT_BYTES
- r->expected_total = 0xffff;
- r->forwarded = 0;
-#endif
-
- return r;
-}
-
-int
-map_ip4_reass_add_fragment (map_ip4_reass_t * r, u32 pi)
-{
- if (map_main.ip4_reass_buffered_counter >= map_main.ip4_reass_conf_buffers)
- return -1;
-
- int i;
- for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- if (r->fragments[i] == ~0)
- {
- r->fragments[i] = pi;
- map_main.ip4_reass_buffered_counter++;
- return 0;
- }
- return -1;
-}
-
-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;
-}
-
-void
-map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
-{
- map_main_t *mm = &map_main;
- int i;
-
- if (dropped_packets)
- *dropped_packets = mm->ip4_reass_buffered_counter;
- if (trashed_reass)
- *trashed_reass = mm->ip4_reass_allocated;
- if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
- {
- u16 ri = mm->ip4_reass_fifo_last;
- do
- {
- map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
- for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
- if (r->fragments[i] != ~0)
- map_ip4_drop_pi (r->fragments[i]);
-
- ri = r->fifo_next;
- pool_put (mm->ip4_reass_pool, r);
- }
- while (ri != mm->ip4_reass_fifo_last);
- }
-
- vec_free (mm->ip4_reass_hash_table);
- vec_resize (mm->ip4_reass_hash_table, 1 << mm->ip4_reass_ht_log2len);
- for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
- mm->ip4_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
- pool_free (mm->ip4_reass_pool);
- pool_alloc (mm->ip4_reass_pool, mm->ip4_reass_conf_pool_size);
-
- mm->ip4_reass_allocated = 0;
- mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
- mm->ip4_reass_buffered_counter = 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;
-}
-
-int
-map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
- u32 * dropped_packets)
-{
- map_main_t *mm = &map_main;
- if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
- return -1;
-
- map_ip4_reass_lock ();
- mm->ip4_reass_conf_ht_ratio = ht_ratio;
- mm->ip4_reass_ht_log2len =
- map_get_ht_log2len (ht_ratio, mm->ip4_reass_conf_pool_size);
- map_ip4_reass_reinit (trashed_reass, dropped_packets);
- map_ip4_reass_unlock ();
- return 0;
-}
-
-int
-map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
- u32 * dropped_packets)
-{
- map_main_t *mm = &map_main;
- if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
- return -1;
-
- map_ip4_reass_lock ();
- mm->ip4_reass_conf_pool_size = pool_size;
- map_ip4_reass_reinit (trashed_reass, dropped_packets);
- map_ip4_reass_unlock ();
- return 0;
-}
-
-int
-map_ip4_reass_conf_lifetime (u16 lifetime_ms)
-{
- map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
- return 0;
-}
-
-int
-map_ip4_reass_conf_buffers (u32 buffers)
-{
- map_main.ip4_reass_conf_buffers = buffers;
- return 0;
-}
-
-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->ip4_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;
-}
-