FD.io VPP  v16.09
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 
26 {
28 #ifdef MAP_SKIP_IP6_LOOKUP
30 #endif
37 };
38 
40 {
45 };
46 
47 typedef struct
48 {
53 
54 u8 *
55 format_ip4_map_reass_trace (u8 * s, va_list * args)
56 {
57  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
58  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60  return format (s, "MAP domain index: %d L4 port: %u Status: %s",
61  t->map_domain_index, t->port,
62  t->cached ? "cached" : "forwarded");
63 }
64 
65 /*
66  * ip4_map_get_port
67  */
68 u16
70 {
71  /* Find port information */
72  if (PREDICT_TRUE ((ip->protocol == IP_PROTOCOL_TCP) ||
73  (ip->protocol == IP_PROTOCOL_UDP)))
74  {
75  udp_header_t *udp = (void *) (ip + 1);
76  return (dir == MAP_SENDER ? udp->src_port : udp->dst_port);
77  }
78  else if (ip->protocol == IP_PROTOCOL_ICMP)
79  {
80  /*
81  * 1) ICMP Echo request or Echo reply
82  * 2) ICMP Error with inner packet being UDP or TCP
83  * 3) ICMP Error with inner packet being ICMP Echo request or Echo reply
84  */
85  icmp46_header_t *icmp = (void *) (ip + 1);
86  if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
87  {
88  return *((u16 *) (icmp + 1));
89  }
90  else if (clib_net_to_host_u16 (ip->length) >= 56)
91  { // IP + ICMP + IP + L4 header
92  ip4_header_t *icmp_ip = (ip4_header_t *) (icmp + 2);
93  if (PREDICT_TRUE ((icmp_ip->protocol == IP_PROTOCOL_TCP) ||
94  (icmp_ip->protocol == IP_PROTOCOL_UDP)))
95  {
96  udp_header_t *udp = (void *) (icmp_ip + 1);
97  return (dir == MAP_SENDER ? udp->dst_port : udp->src_port);
98  }
99  else if (icmp_ip->protocol == IP_PROTOCOL_ICMP)
100  {
101  icmp46_header_t *inner_icmp = (void *) (icmp_ip + 1);
102  if (inner_icmp->type == ICMP4_echo_request
103  || inner_icmp->type == ICMP4_echo_reply)
104  return (*((u16 *) (inner_icmp + 1)));
105  }
106  }
107  }
108  return (0);
109 }
110 
113  u32 * next, u8 * error)
114 {
115  u16 port = 0;
116 
117  if (d->psid_length > 0)
118  {
119  if (ip4_get_fragment_offset (ip) == 0)
120  {
121  if (PREDICT_FALSE
122  ((ip->ip_version_and_header_length != 0x45)
123  || clib_host_to_net_u16 (ip->length) < 28))
124  {
125  return 0;
126  }
127  port = ip4_map_get_port (ip, MAP_RECEIVER);
128  if (port)
129  {
130  /* Verify that port is not among the well-known ports */
131  if ((d->psid_offset > 0)
132  && (clib_net_to_host_u16 (port) <
133  (0x1 << (16 - d->psid_offset))))
134  {
135  *error = MAP_ERROR_ENCAP_SEC_CHECK;
136  }
137  else
138  {
139  if (ip4_get_fragment_more (ip))
140  *next = IP4_MAP_NEXT_REASS;
141  return (port);
142  }
143  }
144  else
145  {
146  *error = MAP_ERROR_BAD_PROTOCOL;
147  }
148  }
149  else
150  {
151  *next = IP4_MAP_NEXT_REASS;
152  }
153  }
154  return (0);
155 }
156 
157 /*
158  * ip4_map_vtcfl
159  */
162 {
163  map_main_t *mm = &map_main;
164  u8 tc = mm->tc_copy ? ip4->tos : mm->tc;
165  u32 vtcfl = 0x6 << 28;
166  vtcfl |= tc << 20;
167  vtcfl |= vnet_buffer (p)->ip.flow_hash & 0x000fffff;
168 
169  return (clib_host_to_net_u32 (vtcfl));
170 }
171 
174 {
175 #ifdef MAP_SKIP_IP6_LOOKUP
176  map_main_t *mm = &map_main;
177  u32 adj_index0 = mm->adj6_index;
178  if (adj_index0 > 0)
179  {
181  ip_adjacency_t *adj = ip_get_adjacency (lm6, mm->adj6_index);
182  if (adj->n_adj > 1)
183  {
185  adj_index0 += (hash_c0 & (adj->n_adj - 1));
186  }
187  vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
188  return (true);
189  }
190 #endif
191  return (false);
192 }
193 
194 /*
195  * ip4_map_ttl
196  */
197 static inline void
199 {
200  i32 ttl = ip->ttl;
201 
202  /* Input node should have reject packets with ttl 0. */
203  ASSERT (ip->ttl > 0);
204 
205  u32 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
206  checksum += checksum >= 0xffff;
207  ip->checksum = checksum;
208  ttl -= 1;
209  ip->ttl = ttl;
210  *error = ttl <= 0 ? IP4_ERROR_TIME_EXPIRED : *error;
211 
212  /* Verify checksum. */
213  ASSERT (ip->checksum == ip4_header_checksum (ip));
214 }
215 
216 static u32
217 ip4_map_fragment (vlib_buffer_t * b, u16 mtu, bool df, u8 * error)
218 {
219  map_main_t *mm = &map_main;
220 
221  if (mm->frag_inner)
222  {
223  ip_frag_set_vnet_buffer (b, sizeof (ip6_header_t), mtu,
226  return (IP4_MAP_NEXT_IP4_FRAGMENT);
227  }
228  else
229  {
230  if (df && !mm->frag_ignore_df)
231  {
232  icmp4_error_set_vnet_buffer (b, ICMP4_destination_unreachable,
233  ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
234  mtu);
235  vlib_buffer_advance (b, sizeof (ip6_header_t));
236  *error = MAP_ERROR_DF_SET;
237  return (IP4_MAP_NEXT_ICMP_ERROR);
238  }
241  return (IP4_MAP_NEXT_IP6_FRAGMENT);
242  }
243 }
244 
245 /*
246  * ip4_map
247  */
248 static uword
250 {
251  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
252  vlib_node_runtime_t *error_node =
254  from = vlib_frame_vector_args (frame);
255  n_left_from = frame->n_vectors;
256  next_index = node->cached_next_index;
257  map_main_t *mm = &map_main;
259  u32 cpu_index = os_get_cpu_number ();
260 
261  while (n_left_from > 0)
262  {
263  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
264 
265  /* Dual loop */
266  while (n_left_from >= 4 && n_left_to_next >= 2)
267  {
268  u32 pi0, pi1;
269  vlib_buffer_t *p0, *p1;
270  map_domain_t *d0, *d1;
271  u8 error0 = MAP_ERROR_NONE, error1 = MAP_ERROR_NONE;
272  ip4_header_t *ip40, *ip41;
273  u16 port0 = 0, port1 = 0;
274  ip6_header_t *ip6h0, *ip6h1;
275  u32 map_domain_index0 = ~0, map_domain_index1 = ~0;
276  u32 next0 = IP4_MAP_NEXT_IP6_LOOKUP, next1 =
278 
279  /* Prefetch next iteration. */
280  {
281  vlib_buffer_t *p2, *p3;
282 
283  p2 = vlib_get_buffer (vm, from[2]);
284  p3 = vlib_get_buffer (vm, from[3]);
285 
286  vlib_prefetch_buffer_header (p2, STORE);
287  vlib_prefetch_buffer_header (p3, STORE);
288  /* IPv4 + 8 = 28. possibly plus -40 */
289  CLIB_PREFETCH (p2->data - 40, 68, STORE);
290  CLIB_PREFETCH (p3->data - 40, 68, STORE);
291  }
292 
293  pi0 = to_next[0] = from[0];
294  pi1 = to_next[1] = from[1];
295  from += 2;
296  n_left_from -= 2;
297  to_next += 2;
298  n_left_to_next -= 2;
299 
300  p0 = vlib_get_buffer (vm, pi0);
301  p1 = vlib_get_buffer (vm, pi1);
302  ip40 = vlib_buffer_get_current (p0);
303  ip41 = vlib_buffer_get_current (p1);
304  d0 =
305  ip4_map_get_domain (vnet_buffer (p0)->ip.adj_index[VLIB_TX],
306  &map_domain_index0);
307  d1 =
308  ip4_map_get_domain (vnet_buffer (p1)->ip.adj_index[VLIB_TX],
309  &map_domain_index1);
310  ASSERT (d0);
311  ASSERT (d1);
312 
313  /*
314  * Shared IPv4 address
315  */
316  port0 = ip4_map_port_and_security_check (d0, ip40, &next0, &error0);
317  port1 = ip4_map_port_and_security_check (d1, ip41, &next1, &error1);
318 
319  /* Decrement IPv4 TTL */
320  ip4_map_decrement_ttl (ip40, &error0);
321  ip4_map_decrement_ttl (ip41, &error1);
322  bool df0 =
324  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
325  bool df1 =
327  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
328 
329  /* MAP calc */
330  u32 da40 = clib_net_to_host_u32 (ip40->dst_address.as_u32);
331  u32 da41 = clib_net_to_host_u32 (ip41->dst_address.as_u32);
332  u16 dp40 = clib_net_to_host_u16 (port0);
333  u16 dp41 = clib_net_to_host_u16 (port1);
334  u64 dal60 = map_get_pfx (d0, da40, dp40);
335  u64 dal61 = map_get_pfx (d1, da41, dp41);
336  u64 dar60 = map_get_sfx (d0, da40, dp40);
337  u64 dar61 = map_get_sfx (d1, da41, dp41);
338  if (dal60 == 0 && dar60 == 0 && error0 == MAP_ERROR_NONE
339  && next0 != IP4_MAP_NEXT_REASS)
340  error0 = MAP_ERROR_NO_BINDING;
341  if (dal61 == 0 && dar61 == 0 && error1 == MAP_ERROR_NONE
342  && next1 != IP4_MAP_NEXT_REASS)
343  error1 = MAP_ERROR_NO_BINDING;
344 
345  /* construct ipv6 header */
346  vlib_buffer_advance (p0, -sizeof (ip6_header_t));
347  vlib_buffer_advance (p1, -sizeof (ip6_header_t));
348  ip6h0 = vlib_buffer_get_current (p0);
349  ip6h1 = vlib_buffer_get_current (p1);
350  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
351  vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
352 
354  ip4_map_vtcfl (ip40, p0);
356  ip4_map_vtcfl (ip41, p1);
357  ip6h0->payload_length = ip40->length;
358  ip6h1->payload_length = ip41->length;
359  ip6h0->protocol = IP_PROTOCOL_IP_IN_IP;
360  ip6h1->protocol = IP_PROTOCOL_IP_IN_IP;
361  ip6h0->hop_limit = 0x40;
362  ip6h1->hop_limit = 0x40;
363  ip6h0->src_address = d0->ip6_src;
364  ip6h1->src_address = d1->ip6_src;
365  ip6h0->dst_address.as_u64[0] = clib_host_to_net_u64 (dal60);
366  ip6h0->dst_address.as_u64[1] = clib_host_to_net_u64 (dar60);
367  ip6h1->dst_address.as_u64[0] = clib_host_to_net_u64 (dal61);
368  ip6h1->dst_address.as_u64[1] = clib_host_to_net_u64 (dar61);
369 
370  /*
371  * Determine next node. Can be one of:
372  * ip6-lookup, ip6-rewrite, ip4-fragment, ip4-virtreass, error-drop
373  */
374  if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
375  {
376  if (PREDICT_FALSE
377  (d0->mtu
378  && (clib_net_to_host_u16 (ip6h0->payload_length) +
379  sizeof (*ip6h0) > d0->mtu)))
380  {
381  next0 = ip4_map_fragment (p0, d0->mtu, df0, &error0);
382  }
383  else
384  {
385  next0 =
387  ip40) ?
388  IP4_MAP_NEXT_IP6_REWRITE : next0;
390  cpu_index,
391  map_domain_index0, 1,
392  clib_net_to_host_u16
393  (ip6h0->payload_length) +
394  40);
395  }
396  }
397  else
398  {
399  next0 = IP4_MAP_NEXT_DROP;
400  }
401 
402  /*
403  * Determine next node. Can be one of:
404  * ip6-lookup, ip6-rewrite, ip4-fragment, ip4-virtreass, error-drop
405  */
406  if (PREDICT_TRUE (error1 == MAP_ERROR_NONE))
407  {
408  if (PREDICT_FALSE
409  (d1->mtu
410  && (clib_net_to_host_u16 (ip6h1->payload_length) +
411  sizeof (*ip6h1) > d1->mtu)))
412  {
413  next1 = ip4_map_fragment (p1, d1->mtu, df1, &error1);
414  }
415  else
416  {
417  next1 =
419  ip41) ?
420  IP4_MAP_NEXT_IP6_REWRITE : next1;
422  cpu_index,
423  map_domain_index1, 1,
424  clib_net_to_host_u16
425  (ip6h1->payload_length) +
426  40);
427  }
428  }
429  else
430  {
431  next1 = IP4_MAP_NEXT_DROP;
432  }
433 
435  {
436  map_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr));
437  tr->map_domain_index = map_domain_index0;
438  tr->port = port0;
439  }
441  {
442  map_trace_t *tr = vlib_add_trace (vm, node, p1, sizeof (*tr));
443  tr->map_domain_index = map_domain_index1;
444  tr->port = port1;
445  }
446 
447  p0->error = error_node->errors[error0];
448  p1->error = error_node->errors[error1];
449 
450  vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
451  n_left_to_next, pi0, pi1, next0,
452  next1);
453  }
454 
455  while (n_left_from > 0 && n_left_to_next > 0)
456  {
457  u32 pi0;
458  vlib_buffer_t *p0;
459  map_domain_t *d0;
460  u8 error0 = MAP_ERROR_NONE;
461  ip4_header_t *ip40;
462  u16 port0 = 0;
463  ip6_header_t *ip6h0;
465  u32 map_domain_index0 = ~0;
466 
467  pi0 = to_next[0] = from[0];
468  from += 1;
469  n_left_from -= 1;
470  to_next += 1;
471  n_left_to_next -= 1;
472 
473  p0 = vlib_get_buffer (vm, pi0);
474  ip40 = vlib_buffer_get_current (p0);
475  d0 =
476  ip4_map_get_domain (vnet_buffer (p0)->ip.adj_index[VLIB_TX],
477  &map_domain_index0);
478  ASSERT (d0);
479 
480  /*
481  * Shared IPv4 address
482  */
483  port0 = ip4_map_port_and_security_check (d0, ip40, &next0, &error0);
484 
485  /* Decrement IPv4 TTL */
486  ip4_map_decrement_ttl (ip40, &error0);
487  bool df0 =
489  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
490 
491  /* MAP calc */
492  u32 da40 = clib_net_to_host_u32 (ip40->dst_address.as_u32);
493  u16 dp40 = clib_net_to_host_u16 (port0);
494  u64 dal60 = map_get_pfx (d0, da40, dp40);
495  u64 dar60 = map_get_sfx (d0, da40, dp40);
496  if (dal60 == 0 && dar60 == 0 && error0 == MAP_ERROR_NONE
497  && next0 != IP4_MAP_NEXT_REASS)
498  error0 = MAP_ERROR_NO_BINDING;
499 
500  /* construct ipv6 header */
501  vlib_buffer_advance (p0, -(sizeof (ip6_header_t)));
502  ip6h0 = vlib_buffer_get_current (p0);
503  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
504 
506  ip4_map_vtcfl (ip40, p0);
507  ip6h0->payload_length = ip40->length;
508  ip6h0->protocol = IP_PROTOCOL_IP_IN_IP;
509  ip6h0->hop_limit = 0x40;
510  ip6h0->src_address = d0->ip6_src;
511  ip6h0->dst_address.as_u64[0] = clib_host_to_net_u64 (dal60);
512  ip6h0->dst_address.as_u64[1] = clib_host_to_net_u64 (dar60);
513 
514  /*
515  * Determine next node. Can be one of:
516  * ip6-lookup, ip6-rewrite, ip4-fragment, ip4-virtreass, error-drop
517  */
518  if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
519  {
520  if (PREDICT_FALSE
521  (d0->mtu
522  && (clib_net_to_host_u16 (ip6h0->payload_length) +
523  sizeof (*ip6h0) > d0->mtu)))
524  {
525  next0 = ip4_map_fragment (p0, d0->mtu, df0, &error0);
526  }
527  else
528  {
529  next0 =
531  ip40) ?
532  IP4_MAP_NEXT_IP6_REWRITE : next0;
534  cpu_index,
535  map_domain_index0, 1,
536  clib_net_to_host_u16
537  (ip6h0->payload_length) +
538  40);
539  }
540  }
541  else
542  {
543  next0 = IP4_MAP_NEXT_DROP;
544  }
545 
547  {
548  map_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr));
549  tr->map_domain_index = map_domain_index0;
550  tr->port = port0;
551  }
552 
553  p0->error = error_node->errors[error0];
554  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
555  n_left_to_next, pi0, next0);
556  }
557  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
558  }
559 
560  return frame->n_vectors;
561 }
562 
563 /*
564  * ip4_map_reass
565  */
566 static uword
568  vlib_node_runtime_t * node, vlib_frame_t * frame)
569 {
570  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
571  vlib_node_runtime_t *error_node =
573  from = vlib_frame_vector_args (frame);
574  n_left_from = frame->n_vectors;
575  next_index = node->cached_next_index;
576  map_main_t *mm = &map_main;
578  u32 cpu_index = os_get_cpu_number ();
579  u32 *fragments_to_drop = NULL;
580  u32 *fragments_to_loopback = NULL;
581 
582  while (n_left_from > 0)
583  {
584  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
585 
586  while (n_left_from > 0 && n_left_to_next > 0)
587  {
588  u32 pi0;
589  vlib_buffer_t *p0;
590  map_domain_t *d0;
591  u8 error0 = MAP_ERROR_NONE;
592  ip4_header_t *ip40;
593  i32 port0 = 0;
594  ip6_header_t *ip60;
596  u32 map_domain_index0;
597  u8 cached = 0;
598 
599  pi0 = to_next[0] = from[0];
600  from += 1;
601  n_left_from -= 1;
602  to_next += 1;
603  n_left_to_next -= 1;
604 
605  p0 = vlib_get_buffer (vm, pi0);
606  ip60 = vlib_buffer_get_current (p0);
607  ip40 = (ip4_header_t *) (ip60 + 1);
608  d0 =
609  ip4_map_get_domain (vnet_buffer (p0)->ip.adj_index[VLIB_TX],
610  &map_domain_index0);
611 
614  ip40->dst_address.as_u32,
615  ip40->fragment_id,
616  ip40->protocol,
617  &fragments_to_drop);
618  if (PREDICT_FALSE (!r))
619  {
620  // Could not create a caching entry
621  error0 = MAP_ERROR_FRAGMENT_MEMORY;
622  }
623  else if (PREDICT_TRUE (ip4_get_fragment_offset (ip40)))
624  {
625  if (r->port >= 0)
626  {
627  // We know the port already
628  port0 = r->port;
629  }
630  else if (map_ip4_reass_add_fragment (r, pi0))
631  {
632  // Not enough space for caching
633  error0 = MAP_ERROR_FRAGMENT_MEMORY;
634  map_ip4_reass_free (r, &fragments_to_drop);
635  }
636  else
637  {
638  cached = 1;
639  }
640  }
641  else
642  if ((port0 =
643  ip4_get_port (ip40, MAP_RECEIVER, p0->current_length)) < 0)
644  {
645  // Could not find port. We'll free the reassembly.
646  error0 = MAP_ERROR_BAD_PROTOCOL;
647  port0 = 0;
648  map_ip4_reass_free (r, &fragments_to_drop);
649  }
650  else
651  {
652  r->port = port0;
653  map_ip4_reass_get_fragments (r, &fragments_to_loopback);
654  }
655 
656 #ifdef MAP_IP4_REASS_COUNT_BYTES
657  if (!cached && r)
658  {
659  r->forwarded += clib_host_to_net_u16 (ip40->length) - 20;
660  if (!ip4_get_fragment_more (ip40))
661  r->expected_total =
662  ip4_get_fragment_offset (ip40) * 8 +
663  clib_host_to_net_u16 (ip40->length) - 20;
664  if (r->forwarded >= r->expected_total)
665  map_ip4_reass_free (r, &fragments_to_drop);
666  }
667 #endif
668 
670 
671  // NOTE: Most operations have already been performed by ip4_map
672  // All we need is the right destination address
673  ip60->dst_address.as_u64[0] =
674  map_get_pfx_net (d0, ip40->dst_address.as_u32, port0);
675  ip60->dst_address.as_u64[1] =
676  map_get_sfx_net (d0, ip40->dst_address.as_u32, port0);
677 
678  if (PREDICT_FALSE
679  (d0->mtu
680  && (clib_net_to_host_u16 (ip60->payload_length) +
681  sizeof (*ip60) > d0->mtu)))
682  {
683  vnet_buffer (p0)->ip_frag.header_offset = sizeof (*ip60);
684  vnet_buffer (p0)->ip_frag.next_index = IP4_FRAG_NEXT_IP6_LOOKUP;
685  vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
686  vnet_buffer (p0)->ip_frag.flags = IP_FRAG_FLAG_IP6_HEADER;
688  }
689 
691  {
693  vlib_add_trace (vm, node, p0, sizeof (*tr));
694  tr->map_domain_index = map_domain_index0;
695  tr->port = port0;
696  tr->cached = cached;
697  }
698 
699  if (cached)
700  {
701  //Dequeue the packet
702  n_left_to_next++;
703  to_next--;
704  }
705  else
706  {
707  if (error0 == MAP_ERROR_NONE)
709  cpu_index, map_domain_index0,
710  1,
711  clib_net_to_host_u16
712  (ip60->payload_length) + 40);
713  next0 =
714  (error0 == MAP_ERROR_NONE) ? next0 : IP4_MAP_REASS_NEXT_DROP;
715  p0->error = error_node->errors[error0];
716  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
717  n_left_to_next, pi0, next0);
718  }
719 
720  //Loopback when we reach the end of the inpu vector
721  if (n_left_from == 0 && vec_len (fragments_to_loopback))
722  {
723  from = vlib_frame_vector_args (frame);
724  u32 len = vec_len (fragments_to_loopback);
725  if (len <= VLIB_FRAME_SIZE)
726  {
727  clib_memcpy (from, fragments_to_loopback,
728  sizeof (u32) * len);
729  n_left_from = len;
730  vec_reset_length (fragments_to_loopback);
731  }
732  else
733  {
734  clib_memcpy (from,
735  fragments_to_loopback + (len -
737  sizeof (u32) * VLIB_FRAME_SIZE);
738  n_left_from = VLIB_FRAME_SIZE;
739  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
740  }
741  }
742  }
743  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
744  }
745 
746  map_send_all_to_node (vm, fragments_to_drop, node,
747  &error_node->errors[MAP_ERROR_FRAGMENT_DROPPED],
749 
750  vec_free (fragments_to_drop);
751  vec_free (fragments_to_loopback);
752  return frame->n_vectors;
753 }
754 
755 static char *map_error_strings[] = {
756 #define _(sym,string) string,
758 #undef _
759 };
760 
761 /* *INDENT-OFF* */
763  .function = ip4_map,
764  .name = "ip4-map",
765  .vector_size = sizeof(u32),
766  .format_trace = format_map_trace,
768 
769  .n_errors = MAP_N_ERROR,
770  .error_strings = map_error_strings,
771 
772  .n_next_nodes = IP4_MAP_N_NEXT,
773  .next_nodes = {
774  [IP4_MAP_NEXT_IP6_LOOKUP] = "ip6-lookup",
775 #ifdef MAP_SKIP_IP6_LOOKUP
776  [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-rewrite",
777 #endif
778  [IP4_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag",
779  [IP4_MAP_NEXT_IP6_FRAGMENT] = "ip6-frag",
780  [IP4_MAP_NEXT_REASS] = "ip4-map-reass",
781  [IP4_MAP_NEXT_ICMP_ERROR] = "ip4-icmp-error",
782  [IP4_MAP_NEXT_DROP] = "error-drop",
783  },
784 };
785 /* *INDENT-ON* */
786 
787 /* *INDENT-OFF* */
789  .function = ip4_map_reass,
790  .name = "ip4-map-reass",
791  .vector_size = sizeof(u32),
792  .format_trace = format_ip4_map_reass_trace,
794 
795  .n_errors = MAP_N_ERROR,
796  .error_strings = map_error_strings,
797 
798  .n_next_nodes = IP4_MAP_REASS_N_NEXT,
799  .next_nodes = {
800  [IP4_MAP_REASS_NEXT_IP6_LOOKUP] = "ip6-lookup",
801  [IP4_MAP_REASS_NEXT_IP4_FRAGMENT] = "ip4-frag",
802  [IP4_MAP_REASS_NEXT_DROP] = "error-drop",
803  },
804 };
805 /* *INDENT-ON* */
806 
807 /*
808  * fd.io coding-style-patch-verification: ON
809  *
810  * Local Variables:
811  * eval: (c-set-style "gnu")
812  * End:
813  */
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:457
#define map_ip4_reass_lock()
Definition: map.h:442
u8 psid_length
Definition: map.h:97
#define CLIB_UNUSED(x)
Definition: clib.h:79
u8 * format_ip4_map_reass_trace(u8 *s, va_list *args)
Definition: ip4_map.c:55
static_always_inline u64 map_get_pfx(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:325
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
u16 n_adj
Number of adjecencies in block.
Definition: lookup.h:176
#define PREDICT_TRUE(x)
Definition: clib.h:98
u64 as_u64[2]
Definition: ip6_packet.h:50
IP unicast adjacency.
Definition: lookup.h:164
#define NULL
Definition: clib.h:55
u8 tc
Definition: map.h:210
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:762
u16 flags_and_fragment_offset
Definition: ip4_packet.h:121
vlib_error_t * errors
Definition: node.h:418
ip6_address_t src_address
Definition: ip6_packet.h:298
u16 port
Definition: map.h:303
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
bool tc_copy
Definition: map.h:211
#define static_always_inline
Definition: clib.h:85
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:187
ip4_address_t dst_address
Definition: ip4_packet.h:138
vlib_combined_counter_main_t * domain_counters
Definition: map.h:199
static int ip4_get_fragment_offset(ip4_header_t *i)
Definition: ip4_packet.h:162
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:553
int map_ip4_reass_add_fragment(map_ip4_reass_t *r, u32 pi)
Definition: map.c:1431
unsigned long u64
Definition: types.h:89
static u32 ip4_map_fragment(vlib_buffer_t *b, u16 mtu, bool df, u8 *error)
Definition: ip4_map.c:217
static uword ip4_map_reass(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip4_map.c:567
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
bool frag_ignore_df
Definition: map.h:246
static_always_inline u64 map_get_pfx_net(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:339
ip4_map_reass_next_t
Definition: ip4_map.c:39
ip4_map_next_e
Definition: ip4_map.c:25
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
static_always_inline u64 map_get_sfx_net(map_domain_t *d, u32 addr, u16 port)
Definition: map.h:368
map_ip4_reass_t * map_ip4_reass_get(u32 src, u32 dst, u16 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1352
#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:161
#define VLIB_FRAME_SIZE
Definition: node.h:328
map_main_t map_main
Definition: map.h:306
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)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:130
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:348
u16 expected_total
Definition: map.h:131
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:118
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:69
void map_ip4_reass_free(map_ip4_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1309
static uword ip4_map(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip4_map.c:249
static_always_inline bool ip4_map_ip6_lookup_bypass(vlib_buffer_t *p0, ip4_header_t *ip)
Definition: ip4_map.c:173
map_dir_e
Definition: map.h:23
u16 n_vectors
Definition: node.h:344
static_always_inline void map_ip4_reass_get_fragments(map_ip4_reass_t *r, u32 **pi)
Definition: map.h:446
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
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:96
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:88
u16 forwarded
Definition: map.h:132
#define clib_memcpy(a, b, c)
Definition: string.h:63
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:200
static void ip4_map_decrement_ttl(ip4_header_t *ip, u8 *error)
Definition: ip4_map.c:198
#define foreach_map_error
Definition: map.h:273
ip6_address_t ip6_src
Definition: map.h:85
static char * map_error_strings[]
Definition: ip4_map.c:755
#define IP_FRAG_FLAG_IP6_HEADER
Definition: ip_frag.h:41
u16 cached_next_index
Definition: node.h:462
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Increment a combined counter.
Definition: counter.h:241
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:335
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
bool frag_inner
Definition: map.h:245
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
#define map_ip4_reass_unlock()
Definition: map.h:443
u8 * format_map_trace(u8 *s, va_list *args)
Definition: map.c:1272
#define IP_FLOW_HASH_DEFAULT
Default: 5-tuple without the "reverse" bit.
Definition: lookup.h:150
static int ip4_get_fragment_more(ip4_header_t *i)
Definition: ip4_packet.h:166
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
u64 uword
Definition: types.h:112
static 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
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:285
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
u16 mtu
Definition: map.h:91
u16 payload_length
Definition: ip6_packet.h:289
static_always_inline map_domain_t * ip4_map_get_domain(u32 adj_index, u32 *map_domain_index)
Definition: map.h:384
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u32 adj6_index
Definition: map.h:204
i32 port
Definition: map.h:134
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
A collection of combined counters.
Definition: counter.h:212
static u32 ip4_compute_flow_hash(ip4_header_t *ip, u32 flow_hash_config)
Definition: ip4.h:452
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:163
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:151
#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:349
u32 map_domain_index
Definition: map.h:302
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
Definition: map.h:25
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
static 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 u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
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:112
ip6_address_t dst_address
Definition: ip6_packet.h:298
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480