FD.io VPP  v16.06
Vector Packet Processing
ip4_map.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * Defines used for testing various optimisation schemes
17  */
18 #define MAP_ENCAP_DUAL 0
19 
20 #include "map.h"
21 #include "../ip/ip_frag.h"
22 
24 
27 #ifdef MAP_SKIP_IP6_LOOKUP
29 #endif
36 };
37 
43 };
44 
45 typedef struct {
50 
51 u8 *
52 format_ip4_map_reass_trace (u8 *s, va_list *args)
53 {
54  CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *);
55  CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *);
57  return format(s, "MAP domain index: %d L4 port: %u Status: %s", t->map_domain_index,
58  t->port, t->cached?"cached":"forwarded");
59 }
60 
61 /*
62  * ip4_map_get_port
63  */
64 u16
66 {
67  /* Find port information */
68  if (PREDICT_TRUE((ip->protocol == IP_PROTOCOL_TCP) ||
69  (ip->protocol == IP_PROTOCOL_UDP))) {
70  udp_header_t *udp = (void *)(ip + 1);
71  return (dir == MAP_SENDER ? udp->src_port : udp->dst_port);
72  } else if (ip->protocol == IP_PROTOCOL_ICMP) {
73  /*
74  * 1) ICMP Echo request or Echo reply
75  * 2) ICMP Error with inner packet being UDP or TCP
76  * 3) ICMP Error with inner packet being ICMP Echo request or Echo reply
77  */
78  icmp46_header_t *icmp = (void *)(ip + 1);
79  if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply) {
80  return *((u16 *)(icmp + 1));
81  } else if (clib_net_to_host_u16(ip->length) >= 56) { // IP + ICMP + IP + L4 header
82  ip4_header_t *icmp_ip = (ip4_header_t *)(icmp + 2);
83  if (PREDICT_TRUE((icmp_ip->protocol == IP_PROTOCOL_TCP) ||
84  (icmp_ip->protocol == IP_PROTOCOL_UDP))) {
85  udp_header_t *udp = (void *)(icmp_ip + 1);
86  return (dir == MAP_SENDER ? udp->dst_port : udp->src_port);
87  } else if (icmp_ip->protocol == IP_PROTOCOL_ICMP) {
88  icmp46_header_t *inner_icmp = (void *)(icmp_ip + 1);
89  if (inner_icmp->type == ICMP4_echo_request || inner_icmp->type == ICMP4_echo_reply)
90  return (*((u16 *)(inner_icmp + 1)));
91  }
92  }
93  }
94  return (0);
95 }
96 
99 {
100  u16 port = 0;
101 
102  if (d->psid_length > 0) {
103  if (ip4_get_fragment_offset(ip) == 0) {
104  if (PREDICT_FALSE((ip->ip_version_and_header_length != 0x45) || clib_host_to_net_u16(ip->length) < 28)) {
105  return 0;
106  }
107  port = ip4_map_get_port(ip, MAP_RECEIVER);
108  if (port) {
109  /* Verify that port is not among the well-known ports */
110  if ((d->psid_offset > 0) && (clib_net_to_host_u16(port) < (0x1 << (16 - d->psid_offset)))) {
111  *error = MAP_ERROR_ENCAP_SEC_CHECK;
112  } else {
113  if (ip4_get_fragment_more(ip)) *next = IP4_MAP_NEXT_REASS;
114  return (port);
115  }
116  } else {
117  *error = MAP_ERROR_BAD_PROTOCOL;
118  }
119  } else {
120  *next = IP4_MAP_NEXT_REASS;
121  }
122  }
123  return (0);
124 }
125 
126 /*
127  * ip4_map_vtcfl
128  */
131 {
132  map_main_t *mm = &map_main;
133  u8 tc = mm->tc_copy ? ip4->tos : mm->tc;
134  u32 vtcfl = 0x6 << 28;
135  vtcfl |= tc << 20;
136  vtcfl |= vnet_buffer(p)->ip.flow_hash & 0x000fffff;
137 
138  return (clib_host_to_net_u32(vtcfl));
139 }
140 
143 {
144 #ifdef MAP_SKIP_IP6_LOOKUP
145  map_main_t *mm = &map_main;
146  u32 adj_index0 = mm->adj6_index;
147  if (adj_index0 > 0) {
149  ip_adjacency_t *adj = ip_get_adjacency(lm6, mm->adj6_index);
150  if (adj->n_adj > 1) {
152  adj_index0 += (hash_c0 & (adj->n_adj - 1));
153  }
154  vnet_buffer(p0)->ip.adj_index[VLIB_TX] = adj_index0;
155  return (true);
156  }
157 #endif
158  return (false);
159 }
160 
161 /*
162  * ip4_map_ttl
163  */
164 static inline void
166 {
167  i32 ttl = ip->ttl;
168 
169  /* Input node should have reject packets with ttl 0. */
170  ASSERT (ip->ttl > 0);
171 
172  u32 checksum = ip->checksum + clib_host_to_net_u16(0x0100);
173  checksum += checksum >= 0xffff;
174  ip->checksum = checksum;
175  ttl -= 1;
176  ip->ttl = ttl;
177  *error = ttl <= 0 ? IP4_ERROR_TIME_EXPIRED : *error;
178 
179  /* Verify checksum. */
180  ASSERT (ip->checksum == ip4_header_checksum(ip));
181 }
182 
183 static u32
184 ip4_map_fragment (vlib_buffer_t *b, u16 mtu, bool df, u8 *error)
185 {
186  map_main_t *mm = &map_main;
187 
188  if (mm->frag_inner) {
190  return (IP4_MAP_NEXT_IP4_FRAGMENT);
191  } else {
192  if (df && !mm->frag_ignore_df) {
193  icmp4_error_set_vnet_buffer(b, ICMP4_destination_unreachable,
194  ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set, mtu);
195  vlib_buffer_advance(b, sizeof(ip6_header_t));
196  *error = MAP_ERROR_DF_SET;
197  return (IP4_MAP_NEXT_ICMP_ERROR);
198  }
200  return (IP4_MAP_NEXT_IP6_FRAGMENT);
201  }
202 }
203 
204 /*
205  * ip4_map
206  */
207 static uword
209  vlib_node_runtime_t *node,
210  vlib_frame_t *frame)
211 {
212  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
213  vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip4_map_node.index);
214  from = vlib_frame_vector_args(frame);
215  n_left_from = frame->n_vectors;
216  next_index = node->cached_next_index;
217  map_main_t *mm = &map_main;
219  u32 cpu_index = os_get_cpu_number();
220 
221  while (n_left_from > 0) {
222  vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
223 
224  /* Dual loop */
225  while (n_left_from >= 4 && n_left_to_next >= 2) {
226  u32 pi0, pi1;
227  vlib_buffer_t *p0, *p1;
228  map_domain_t *d0, *d1;
229  u8 error0 = MAP_ERROR_NONE, error1 = MAP_ERROR_NONE;
230  ip4_header_t *ip40, *ip41;
231  u16 port0 = 0, port1 = 0;
232  ip6_header_t *ip6h0, *ip6h1;
233  u32 map_domain_index0 = ~0, map_domain_index1 = ~0;
235 
236  /* Prefetch next iteration. */
237  {
238  vlib_buffer_t *p2, *p3;
239 
240  p2 = vlib_get_buffer(vm, from[2]);
241  p3 = vlib_get_buffer(vm, from[3]);
242 
243  vlib_prefetch_buffer_header(p2, STORE);
244  vlib_prefetch_buffer_header(p3, STORE);
245  /* IPv4 + 8 = 28. possibly plus -40 */
246  CLIB_PREFETCH (p2->data-40, 68, STORE);
247  CLIB_PREFETCH (p3->data-40, 68, STORE);
248  }
249 
250  pi0 = to_next[0] = from[0];
251  pi1 = to_next[1] = from[1];
252  from += 2;
253  n_left_from -= 2;
254  to_next +=2;
255  n_left_to_next -= 2;
256 
257  p0 = vlib_get_buffer(vm, pi0);
258  p1 = vlib_get_buffer(vm, pi1);
259  ip40 = vlib_buffer_get_current(p0);
260  ip41 = vlib_buffer_get_current(p1);
261  d0 = ip4_map_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &map_domain_index0);
262  d1 = ip4_map_get_domain(vnet_buffer(p1)->ip.adj_index[VLIB_TX], &map_domain_index1);
263  ASSERT(d0);
264  ASSERT(d1);
265 
266  /*
267  * Shared IPv4 address
268  */
269  port0 = ip4_map_port_and_security_check(d0, ip40, &next0, &error0);
270  port1 = ip4_map_port_and_security_check(d1, ip41, &next1, &error1);
271 
272  /* Decrement IPv4 TTL */
273  ip4_map_decrement_ttl(ip40, &error0);
274  ip4_map_decrement_ttl(ip41, &error1);
275  bool df0 = ip40->flags_and_fragment_offset & clib_host_to_net_u16(IP4_HEADER_FLAG_DONT_FRAGMENT);
276  bool df1 = ip41->flags_and_fragment_offset & clib_host_to_net_u16(IP4_HEADER_FLAG_DONT_FRAGMENT);
277 
278  /* MAP calc */
279  u32 da40 = clib_net_to_host_u32(ip40->dst_address.as_u32);
280  u32 da41 = clib_net_to_host_u32(ip41->dst_address.as_u32);
281  u16 dp40 = clib_net_to_host_u16(port0);
282  u16 dp41 = clib_net_to_host_u16(port1);
283  u64 dal60 = map_get_pfx(d0, da40, dp40);
284  u64 dal61 = map_get_pfx(d1, da41, dp41);
285  u64 dar60 = map_get_sfx(d0, da40, dp40);
286  u64 dar61 = map_get_sfx(d1, da41, dp41);
287  if (dal60 == 0 && dar60 == 0 && error0 == MAP_ERROR_NONE && next0 != IP4_MAP_NEXT_REASS)
288  error0 = MAP_ERROR_NO_BINDING;
289  if (dal61 == 0 && dar61 == 0 && error1 == MAP_ERROR_NONE && next1 != IP4_MAP_NEXT_REASS)
290  error0 = MAP_ERROR_NO_BINDING;
291 
292  /* construct ipv6 header */
293  vlib_buffer_advance(p0, - sizeof(ip6_header_t));
294  vlib_buffer_advance(p1, - sizeof(ip6_header_t));
295  ip6h0 = vlib_buffer_get_current(p0);
296  ip6h1 = vlib_buffer_get_current(p1);
297  vnet_buffer(p0)->sw_if_index[VLIB_TX] = (u32)~0;
298  vnet_buffer(p1)->sw_if_index[VLIB_TX] = (u32)~0;
299 
302  ip6h0->payload_length = ip40->length;
303  ip6h1->payload_length = ip41->length;
304  ip6h0->protocol = IP_PROTOCOL_IP_IN_IP;
305  ip6h1->protocol = IP_PROTOCOL_IP_IN_IP;
306  ip6h0->hop_limit = 0x40;
307  ip6h1->hop_limit = 0x40;
308  ip6h0->src_address = d0->ip6_src;
309  ip6h1->src_address = d1->ip6_src;
310  ip6h0->dst_address.as_u64[0] = clib_host_to_net_u64(dal60);
311  ip6h0->dst_address.as_u64[1] = clib_host_to_net_u64(dar60);
312  ip6h1->dst_address.as_u64[0] = clib_host_to_net_u64(dal61);
313  ip6h1->dst_address.as_u64[1] = clib_host_to_net_u64(dar61);
314 
315  /*
316  * Determine next node. Can be one of:
317  * ip6-lookup, ip6-rewrite, ip4-fragment, ip4-virtreass, error-drop
318  */
319  if (PREDICT_TRUE(error0 == MAP_ERROR_NONE)) {
320  if (PREDICT_FALSE(d0->mtu && (clib_net_to_host_u16(ip6h0->payload_length) + sizeof(*ip6h0) > d0->mtu))) {
321  next0 = ip4_map_fragment(p0, d0->mtu, df0, &error0);
322  } else {
323  next0 = ip4_map_ip6_lookup_bypass(p0, ip40) ? IP4_MAP_NEXT_IP6_REWRITE : next0;
324  vlib_increment_combined_counter(cm + MAP_DOMAIN_COUNTER_TX, cpu_index, map_domain_index0, 1,
325  clib_net_to_host_u16(ip6h0->payload_length) + 40);
326  }
327  } else {
328  next0 = IP4_MAP_NEXT_DROP;
329  }
330 
331  /*
332  * Determine next node. Can be one of:
333  * ip6-lookup, ip6-rewrite, ip4-fragment, ip4-virtreass, error-drop
334  */
335  if (PREDICT_TRUE(error1 == MAP_ERROR_NONE)) {
336  if (PREDICT_FALSE(d1->mtu && (clib_net_to_host_u16(ip6h1->payload_length) + sizeof(*ip6h1) > d1->mtu))) {
337  next1 = ip4_map_fragment(p1, d1->mtu, df1, &error1);
338  } else {
339  next1 = ip4_map_ip6_lookup_bypass(p1, ip41) ? IP4_MAP_NEXT_IP6_REWRITE : next1;
340  vlib_increment_combined_counter(cm + MAP_DOMAIN_COUNTER_TX, cpu_index, map_domain_index1, 1,
341  clib_net_to_host_u16(ip6h1->payload_length) + 40);
342  }
343  } else {
344  next1 = IP4_MAP_NEXT_DROP;
345  }
346 
348  map_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr));
349  tr->map_domain_index = map_domain_index0;
350  tr->port = port0;
351  }
353  map_trace_t *tr = vlib_add_trace(vm, node, p1, sizeof(*tr));
354  tr->map_domain_index = map_domain_index1;
355  tr->port = port1;
356  }
357 
358  p0->error = error_node->errors[error0];
359  p1->error = error_node->errors[error1];
360 
361  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, pi0, pi1, next0, next1);
362  }
363 
364  while (n_left_from > 0 && n_left_to_next > 0) {
365  u32 pi0;
366  vlib_buffer_t *p0;
367  map_domain_t *d0;
368  u8 error0 = MAP_ERROR_NONE;
369  ip4_header_t *ip40;
370  u16 port0 = 0;
371  ip6_header_t *ip6h0;
373  u32 map_domain_index0 = ~0;
374 
375  pi0 = to_next[0] = from[0];
376  from += 1;
377  n_left_from -= 1;
378  to_next +=1;
379  n_left_to_next -= 1;
380 
381  p0 = vlib_get_buffer(vm, pi0);
382  ip40 = vlib_buffer_get_current(p0);
383  d0 = ip4_map_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &map_domain_index0);
384  ASSERT(d0);
385 
386  /*
387  * Shared IPv4 address
388  */
389  port0 = ip4_map_port_and_security_check(d0, ip40, &next0, &error0);
390 
391  /* Decrement IPv4 TTL */
392  ip4_map_decrement_ttl(ip40, &error0);
393  bool df0 = ip40->flags_and_fragment_offset & clib_host_to_net_u16(IP4_HEADER_FLAG_DONT_FRAGMENT);
394 
395  /* MAP calc */
396  u32 da40 = clib_net_to_host_u32(ip40->dst_address.as_u32);
397  u16 dp40 = clib_net_to_host_u16(port0);
398  u64 dal60 = map_get_pfx(d0, da40, dp40);
399  u64 dar60 = map_get_sfx(d0, da40, dp40);
400  if (dal60 == 0 && dar60 == 0 && error0 == MAP_ERROR_NONE && next0 != IP4_MAP_NEXT_REASS)
401  error0 = MAP_ERROR_NO_BINDING;
402 
403  /* construct ipv6 header */
404  vlib_buffer_advance(p0, - (sizeof(ip6_header_t)));
405  ip6h0 = vlib_buffer_get_current(p0);
406  vnet_buffer(p0)->sw_if_index[VLIB_TX] = (u32)~0;
407 
409  ip6h0->payload_length = ip40->length;
410  ip6h0->protocol = IP_PROTOCOL_IP_IN_IP;
411  ip6h0->hop_limit = 0x40;
412  ip6h0->src_address = d0->ip6_src;
413  ip6h0->dst_address.as_u64[0] = clib_host_to_net_u64(dal60);
414  ip6h0->dst_address.as_u64[1] = clib_host_to_net_u64(dar60);
415 
416  /*
417  * Determine next node. Can be one of:
418  * ip6-lookup, ip6-rewrite, ip4-fragment, ip4-virtreass, error-drop
419  */
420  if (PREDICT_TRUE(error0 == MAP_ERROR_NONE)) {
421  if (PREDICT_FALSE(d0->mtu && (clib_net_to_host_u16(ip6h0->payload_length) + sizeof(*ip6h0) > d0->mtu))) {
422  next0 = ip4_map_fragment(p0, d0->mtu, df0, &error0);
423  } else {
424  next0 = ip4_map_ip6_lookup_bypass(p0, ip40) ? IP4_MAP_NEXT_IP6_REWRITE : next0;
425  vlib_increment_combined_counter(cm + MAP_DOMAIN_COUNTER_TX, cpu_index, map_domain_index0, 1,
426  clib_net_to_host_u16(ip6h0->payload_length) + 40);
427  }
428  } else {
429  next0 = IP4_MAP_NEXT_DROP;
430  }
431 
433  map_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr));
434  tr->map_domain_index = map_domain_index0;
435  tr->port = port0;
436  }
437 
438  p0->error = error_node->errors[error0];
439  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0);
440  }
441  vlib_put_next_frame(vm, node, next_index, n_left_to_next);
442  }
443 
444  return frame->n_vectors;
445 }
446 
447 /*
448  * ip4_map_reass
449  */
450 static uword
452  vlib_node_runtime_t *node,
453  vlib_frame_t *frame)
454 {
455  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
457  from = vlib_frame_vector_args(frame);
458  n_left_from = frame->n_vectors;
459  next_index = node->cached_next_index;
460  map_main_t *mm = &map_main;
462  u32 cpu_index = os_get_cpu_number();
463  u32 *fragments_to_drop = NULL;
464  u32 *fragments_to_loopback = NULL;
465 
466  while (n_left_from > 0) {
467  vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
468 
469  while (n_left_from > 0 && n_left_to_next > 0) {
470  u32 pi0;
471  vlib_buffer_t *p0;
472  map_domain_t *d0;
473  u8 error0 = MAP_ERROR_NONE;
474  ip4_header_t *ip40;
475  i32 port0 = 0;
476  ip6_header_t *ip60;
478  u32 map_domain_index0;
479  u8 cached = 0;
480 
481  pi0 = to_next[0] = from[0];
482  from += 1;
483  n_left_from -= 1;
484  to_next +=1;
485  n_left_to_next -= 1;
486 
487  p0 = vlib_get_buffer(vm, pi0);
488  ip60 = vlib_buffer_get_current(p0);
489  ip40 = (ip4_header_t *)(ip60 + 1);
490  d0 = ip4_map_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &map_domain_index0);
491 
494  ip40->fragment_id, ip40->protocol, &fragments_to_drop);
495  if (PREDICT_FALSE(!r)) {
496  // Could not create a caching entry
497  error0 = MAP_ERROR_FRAGMENT_MEMORY;
498  } else if (PREDICT_TRUE(ip4_get_fragment_offset(ip40))) {
499  if (r->port >= 0) {
500  // We know the port already
501  port0 = r->port;
502  } else if (map_ip4_reass_add_fragment(r, pi0)) {
503  // Not enough space for caching
504  error0 = MAP_ERROR_FRAGMENT_MEMORY;
505  map_ip4_reass_free(r, &fragments_to_drop);
506  } else {
507  cached = 1;
508  }
509  } else if ((port0 = ip4_get_port(ip40, MAP_RECEIVER, p0->current_length)) < 0) {
510  // Could not find port. We'll free the reassembly.
511  error0 = MAP_ERROR_BAD_PROTOCOL;
512  port0 = 0;
513  map_ip4_reass_free(r, &fragments_to_drop);
514  } else {
515  r->port = port0;
516  map_ip4_reass_get_fragments(r, &fragments_to_loopback);
517  }
518 
519 #ifdef MAP_IP4_REASS_COUNT_BYTES
520  if (!cached && r) {
521  r->forwarded += clib_host_to_net_u16(ip40->length) - 20;
522  if (!ip4_get_fragment_more(ip40))
523  r->expected_total = ip4_get_fragment_offset(ip40) * 8 + clib_host_to_net_u16(ip40->length) - 20;
524  if(r->forwarded >= r->expected_total)
525  map_ip4_reass_free(r, &fragments_to_drop);
526  }
527 #endif
528 
530 
531  // NOTE: Most operations have already been performed by ip4_map
532  // All we need is the right destination address
533  ip60->dst_address.as_u64[0] = map_get_pfx_net(d0, ip40->dst_address.as_u32, port0);
534  ip60->dst_address.as_u64[1] = map_get_sfx_net(d0, ip40->dst_address.as_u32, port0);
535 
536  if (PREDICT_FALSE(d0->mtu && (clib_net_to_host_u16(ip60->payload_length) + sizeof(*ip60) > d0->mtu))) {
537  vnet_buffer(p0)->ip_frag.header_offset = sizeof(*ip60);
538  vnet_buffer(p0)->ip_frag.next_index = IP4_FRAG_NEXT_IP6_LOOKUP;
539  vnet_buffer(p0)->ip_frag.mtu = d0->mtu;
540  vnet_buffer(p0)->ip_frag.flags = IP_FRAG_FLAG_IP6_HEADER;
542  }
543 
545  map_ip4_map_reass_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr));
546  tr->map_domain_index = map_domain_index0;
547  tr->port = port0;
548  tr->cached = cached;
549  }
550 
551  if(cached) {
552  //Dequeue the packet
553  n_left_to_next++;
554  to_next--;
555  } else {
556  if (error0 == MAP_ERROR_NONE)
557  vlib_increment_combined_counter(cm + MAP_DOMAIN_COUNTER_TX, cpu_index, map_domain_index0, 1,
558  clib_net_to_host_u16(ip60->payload_length) + 40);
559  next0 = (error0 == MAP_ERROR_NONE) ? next0 : IP4_MAP_REASS_NEXT_DROP;
560  p0->error = error_node->errors[error0];
561  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0);
562  }
563 
564  //Loopback when we reach the end of the inpu vector
565  if(n_left_from == 0 && vec_len(fragments_to_loopback)) {
566  from = vlib_frame_vector_args(frame);
567  u32 len = vec_len(fragments_to_loopback);
568  if(len <= VLIB_FRAME_SIZE) {
569  clib_memcpy(from, fragments_to_loopback, sizeof(u32)*len);
570  n_left_from = len;
571  vec_reset_length(fragments_to_loopback);
572  } else {
573  clib_memcpy(from, fragments_to_loopback + (len - VLIB_FRAME_SIZE), sizeof(u32)*VLIB_FRAME_SIZE);
574  n_left_from = VLIB_FRAME_SIZE;
575  _vec_len(fragments_to_loopback) = len - VLIB_FRAME_SIZE;
576  }
577  }
578  }
579  vlib_put_next_frame(vm, node, next_index, n_left_to_next);
580  }
581 
582  map_send_all_to_node(vm, fragments_to_drop, node,
583  &error_node->errors[MAP_ERROR_FRAGMENT_DROPPED],
585 
586  vec_free(fragments_to_drop);
587  vec_free(fragments_to_loopback);
588  return frame->n_vectors;
589 }
590 
591 static char *map_error_strings[] = {
592 #define _(sym,string) string,
594 #undef _
595 };
596 
598  .function = ip4_map,
599  .name = "ip4-map",
600  .vector_size = sizeof(u32),
601  .format_trace = format_map_trace,
603 
604  .n_errors = MAP_N_ERROR,
605  .error_strings = map_error_strings,
606 
607  .n_next_nodes = IP4_MAP_N_NEXT,
608  .next_nodes = {
609  [IP4_MAP_NEXT_IP6_LOOKUP] = "ip6-lookup",
610 #ifdef MAP_SKIP_IP6_LOOKUP
611  [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-rewrite",
612 #endif
613  [IP4_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag",
614  [IP4_MAP_NEXT_IP6_FRAGMENT] = "ip6-frag",
615  [IP4_MAP_NEXT_REASS] = "ip4-map-reass",
616  [IP4_MAP_NEXT_ICMP_ERROR] = "ip4-icmp-error",
617  [IP4_MAP_NEXT_DROP] = "error-drop",
618  },
619 };
620 
622  .function = ip4_map_reass,
623  .name = "ip4-map-reass",
624  .vector_size = sizeof(u32),
625  .format_trace = format_ip4_map_reass_trace,
627 
628  .n_errors = MAP_N_ERROR,
629  .error_strings = map_error_strings,
630 
631  .n_next_nodes = IP4_MAP_REASS_N_NEXT,
632  .next_nodes = {
633  [IP4_MAP_REASS_NEXT_IP6_LOOKUP] = "ip6-lookup",
634  [IP4_MAP_REASS_NEXT_IP4_FRAGMENT] = "ip4-frag",
635  [IP4_MAP_REASS_NEXT_DROP] = "error-drop",
636  },
637 };
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Definition: main.c:459
#define map_ip4_reass_lock()
Definition: map.h:433
u8 psid_length
Definition: map.h:94
#define CLIB_UNUSED(x)
Definition: clib.h:79
u8 * format_ip4_map_reass_trace(u8 *s, va_list *args)
Definition: ip4_map.c:52
static_always_inline u64 map_get_pfx(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:316
ip4_address_t src_address
Definition: ip4_packet.h:138
void ip_frag_set_vnet_buffer(vlib_buffer_t *b, u16 offset, u16 mtu, u8 next_index, u8 flags)
Definition: ip_frag.c:149
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
#define PREDICT_TRUE(x)
Definition: clib.h:98
always_inline int ip4_get_fragment_offset(ip4_header_t *i)
Definition: ip4_packet.h:162
u64 as_u64[2]
Definition: ip6_packet.h:50
#define NULL
Definition: clib.h:55
u8 tc
Definition: map.h:201
struct _vlib_node_registration vlib_node_registration_t
vlib_node_registration_t ip4_map_node
(constructor) VLIB_REGISTER_NODE (ip4_map_node)
Definition: ip4_map.c:597
u16 flags_and_fragment_offset
Definition: ip4_packet.h:121
vlib_error_t * errors
Definition: node.h:378
ip6_address_t src_address
Definition: ip6_packet.h:293
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
always_inline int ip4_get_fragment_more(ip4_header_t *i)
Definition: ip4_packet.h:166
u16 port
Definition: map.h:294
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
bool tc_copy
Definition: map.h:202
#define static_always_inline
Definition: clib.h:85
ip4_address_t dst_address
Definition: ip4_packet.h:138
vlib_combined_counter_main_t * domain_counters
Definition: map.h:190
always_inline void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Definition: counter.h:210
int i32
Definition: types.h:81
static_always_inline void map_send_all_to_node(vlib_main_t *vm, u32 *pi_vector, vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
Definition: map.h:544
int map_ip4_reass_add_fragment(map_ip4_reass_t *r, u32 pi)
Definition: map.c:1239
unsigned long u64
Definition: types.h:89
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
static u32 ip4_map_fragment(vlib_buffer_t *b, u16 mtu, bool df, u8 *error)
Definition: ip4_map.c:184
static uword ip4_map_reass(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip4_map.c:451
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
bool frag_ignore_df
Definition: map.h:237
static_always_inline u64 map_get_pfx_net(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:330
ip4_map_reass_next_t
Definition: ip4_map.c:38
ip4_map_next_e
Definition: ip4_map.c:25
uword os_get_cpu_number(void)
Definition: unix-misc.c:206
static_always_inline u64 map_get_sfx_net(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:359
map_ip4_reass_t * map_ip4_reass_get(u32 src, u32 dst, u16 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1168
#define PREDICT_FALSE(x)
Definition: clib.h:97
static_always_inline u32 ip4_map_vtcfl(ip4_header_t *ip4, vlib_buffer_t *p)
Definition: ip4_map.c:130
#define VLIB_FRAME_SIZE
Definition: node.h:292
map_main_t map_main
Definition: map.h:297
i32 ip4_get_port(ip4_header_t *ip, map_dir_e dir, u16 buffer_len)
Definition: map.c:66
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Definition: buffer_node.h:43
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Definition: buffer_node.h:83
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Definition: node_funcs.h:265
u16 expected_total
Definition: map.h:125
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:129
always_inline u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
vlib_node_registration_t ip4_map_reass_node
(constructor) VLIB_REGISTER_NODE (ip4_map_reass_node)
Definition: ip4_map.c:23
u16 ip4_map_get_port(ip4_header_t *ip, map_dir_e dir)
Definition: ip4_map.c:65
void map_ip4_reass_free(map_ip4_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1134
static uword ip4_map(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip4_map.c:208
static_always_inline bool ip4_map_ip6_lookup_bypass(vlib_buffer_t *p0, ip4_header_t *ip)
Definition: ip4_map.c:142
map_dir_e
Definition: map.h:23
u16 n_vectors
Definition: node.h:307
static_always_inline void map_ip4_reass_get_fragments(map_ip4_reass_t *r, u32 **pi)
Definition: map.h:437
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:416
u8 psid_offset
Definition: map.h:93
u16 forwarded
Definition: map.h:126
#define clib_memcpy(a, b, c)
Definition: string.h:63
static void ip4_map_decrement_ttl(ip4_header_t *ip, u8 *error)
Definition: ip4_map.c:165
#define foreach_map_error
Definition: map.h:264
ip6_address_t ip6_src
Definition: map.h:82
static char * map_error_strings[]
Definition: ip4_map.c:591
#define IP_FRAG_FLAG_IP6_HEADER
Definition: ip_frag.h:41
u16 cached_next_index
Definition: node.h:422
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:300
ip6_main_t ip6_main
Definition: ip6_forward.c:2490
ip_lookup_main_t lookup_main
Definition: ip6.h:135
bool frag_inner
Definition: map.h:236
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
#define map_ip4_reass_unlock()
Definition: map.h:434
u8 * format_map_trace(u8 *s, va_list *args)
Definition: map.c:1101
#define IP_FLOW_HASH_DEFAULT
Definition: lookup.h:136
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:91
always_inline ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:423
u64 uword
Definition: types.h:112
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:280
Definition: defs.h:46
unsigned short u16
Definition: types.h:57
u16 mtu
Definition: map.h:88
u16 payload_length
Definition: ip6_packet.h:284
static_always_inline map_domain_t * ip4_map_get_domain(u32 adj_index, u32 *map_domain_index)
Definition: map.h:375
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
always_inline void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:197
unsigned char u8
Definition: types.h:56
u32 adj6_index
Definition: map.h:195
always_inline u32 ip4_compute_flow_hash(ip4_header_t *ip, u32 flow_hash_config)
Definition: ip4.h:397
i32 port
Definition: map.h:128
always_inline void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:162
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
always_inline vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:61
u8 data[0]
Packet data.
Definition: buffer.h:150
#define IP4_HEADER_FLAG_DONT_FRAGMENT
Definition: ip4_packet.h:123
static_always_inline u64 map_get_sfx(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:340
u32 map_domain_index
Definition: map.h:293
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
Definition: map.h:24
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
static_always_inline u16 ip4_map_port_and_security_check(map_domain_t *d, ip4_header_t *ip, u32 *next, u8 *error)
Definition: ip4_map.c:98
ip6_address_t dst_address
Definition: ip6_packet.h:293