1cb9cadadSEd Warnicke/*
2cb9cadadSEd Warnicke * Copyright (c) 2015 Cisco and/or its affiliates.
3cb9cadadSEd Warnicke * Licensed under the Apache License, Version 2.0 (the "License");
4cb9cadadSEd Warnicke * you may not use this file except in compliance with the License.
5cb9cadadSEd Warnicke * You may obtain a copy of the License at:
6cb9cadadSEd Warnicke *
7cb9cadadSEd Warnicke *     http://www.apache.org/licenses/LICENSE-2.0
8cb9cadadSEd Warnicke *
9cb9cadadSEd Warnicke * Unless required by applicable law or agreed to in writing, software
10cb9cadadSEd Warnicke * distributed under the License is distributed on an "AS IS" BASIS,
11cb9cadadSEd Warnicke * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb9cadadSEd Warnicke * See the License for the specific language governing permissions and
13cb9cadadSEd Warnicke * limitations under the License.
14cb9cadadSEd Warnicke */
15cb9cadadSEd Warnicke/*
16cb9cadadSEd Warnicke * Defines used for testing various optimisation schemes
17cb9cadadSEd Warnicke */
18cb9cadadSEd Warnicke
19cb9cadadSEd Warnicke#include "map.h"
20381e9a90SOle Troan#include <vnet/ip/ip_frag.h>
21a774b536SMatus Fabian#include <vnet/ip/ip4_to_ip6.h>
22cb9cadadSEd Warnicke
2306e3d075SKeith Burns (alagalah)enum ip4_map_next_e
2406e3d075SKeith Burns (alagalah){
25cb9cadadSEd Warnicke  IP4_MAP_NEXT_IP6_LOOKUP,
26cb9cadadSEd Warnicke#ifdef MAP_SKIP_IP6_LOOKUP
27cb9cadadSEd Warnicke  IP4_MAP_NEXT_IP6_REWRITE,
28cb9cadadSEd Warnicke#endif
299fb87553SOle Troan  IP4_MAP_NEXT_ICMP_ERROR,
30cb9cadadSEd Warnicke  IP4_MAP_NEXT_DROP,
31cb9cadadSEd Warnicke  IP4_MAP_N_NEXT,
32cb9cadadSEd Warnicke};
33cb9cadadSEd Warnicke
34a025b3eaSKlement Sekerastatic_always_inline u16
35a025b3eaSKlement Sekeraip4_map_port_and_security_check (map_domain_t * d, vlib_buffer_t * b0,
36a025b3eaSKlement Sekera				 u8 * error)
3706e3d075SKeith Burns (alagalah){
38cb9cadadSEd Warnicke  u16 port;
39a025b3eaSKlement Sekera  if (d->psid_length > 0)
40a025b3eaSKlement Sekera    {
41a025b3eaSKlement Sekera      ip4_header_t *ip = vlib_buffer_get_current (b0);
42cb9cadadSEd Warnicke
43a025b3eaSKlement Sekera      if (PREDICT_FALSE
44a025b3eaSKlement Sekera	  ((ip->ip_version_and_header_length != 0x45)
45a025b3eaSKlement Sekera	   || clib_host_to_net_u16 (ip->length) < 28))
46a025b3eaSKlement Sekera	{
47a025b3eaSKlement Sekera	  return 0;
48a025b3eaSKlement Sekera	}
49cb9cadadSEd Warnicke
50a025b3eaSKlement Sekera      port = vnet_buffer (b0)->ip.reass.l4_dst_port;
51cb9cadadSEd Warnicke
52a025b3eaSKlement Sekera      /* Verify that port is not among the well-known ports */
53a025b3eaSKlement Sekera      if ((d->psid_offset > 0)
54a025b3eaSKlement Sekera	  && (clib_net_to_host_u16 (port) < (0x1 << (16 - d->psid_offset))))
5506e3d075SKeith Burns (alagalah)	{
56a025b3eaSKlement Sekera	  *error = MAP_ERROR_ENCAP_SEC_CHECK;
5706e3d075SKeith Burns (alagalah)	}
5806e3d075SKeith Burns (alagalah)      else
5906e3d075SKeith Burns (alagalah)	{
60a025b3eaSKlement Sekera	  return port;
61cb9cadadSEd Warnicke	}
62cb9cadadSEd Warnicke    }
63cb9cadadSEd Warnicke  return (0);
64cb9cadadSEd Warnicke}
65cb9cadadSEd Warnicke
66cb9cadadSEd Warnicke/*
67cb9cadadSEd Warnicke * ip4_map_vtcfl
68cb9cadadSEd Warnicke */
69cb9cadadSEd Warnickestatic_always_inline u32
7006e3d075SKeith Burns (alagalah)ip4_map_vtcfl (ip4_header_t * ip4, vlib_buffer_t * p)
71cb9cadadSEd Warnicke{
72cb9cadadSEd Warnicke  map_main_t *mm = &map_main;
73cb9cadadSEd Warnicke  u8 tc = mm->tc_copy ? ip4->tos : mm->tc;
74cb9cadadSEd Warnicke  u32 vtcfl = 0x6 << 28;
75cb9cadadSEd Warnicke  vtcfl |= tc << 20;
7606e3d075SKeith Burns (alagalah)  vtcfl |= vnet_buffer (p)->ip.flow_hash & 0x000fffff;
77cb9cadadSEd Warnicke
7806e3d075SKeith Burns (alagalah)  return (clib_host_to_net_u32 (vtcfl));
79cb9cadadSEd Warnicke}
80cb9cadadSEd Warnicke
81366ac6ecSOle Troan/*
82366ac6ecSOle Troan * ip4_map_ttl
83366ac6ecSOle Troan */
84366ac6ecSOle Troanstatic inline void
8506e3d075SKeith Burns (alagalah)ip4_map_decrement_ttl (ip4_header_t * ip, u8 * error)
86366ac6ecSOle Troan{
87366ac6ecSOle Troan  i32 ttl = ip->ttl;
88366ac6ecSOle Troan
89366ac6ecSOle Troan  /* Input node should have reject packets with ttl 0. */
90366ac6ecSOle Troan  ASSERT (ip->ttl > 0);
91366ac6ecSOle Troan
9206e3d075SKeith Burns (alagalah)  u32 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
93366ac6ecSOle Troan  checksum += checksum >= 0xffff;
94366ac6ecSOle Troan  ip->checksum = checksum;
95366ac6ecSOle Troan  ttl -= 1;
96366ac6ecSOle Troan  ip->ttl = ttl;
97366ac6ecSOle Troan  *error = ttl <= 0 ? IP4_ERROR_TIME_EXPIRED : *error;
98366ac6ecSOle Troan
99366ac6ecSOle Troan  /* Verify checksum. */
10006e3d075SKeith Burns (alagalah)  ASSERT (ip->checksum == ip4_header_checksum (ip));
101366ac6ecSOle Troan}
102366ac6ecSOle Troan
1039fb87553SOle Troanstatic u32
104eb284a1fSOle Troanip4_map_fragment (vlib_main_t * vm, u32 bi, u16 mtu, bool df, u32 ** buffers,
105eb284a1fSOle Troan		  u8 * error)
1069fb87553SOle Troan{
1079fb87553SOle Troan  map_main_t *mm = &map_main;
108eb284a1fSOle Troan  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
1099fb87553SOle Troan
11006e3d075SKeith Burns (alagalah)  if (mm->frag_inner)
11106e3d075SKeith Burns (alagalah)    {
112eb284a1fSOle Troan      /* IPv4 fragmented packets inside of IPv6 */
113eb284a1fSOle Troan      ip4_frag_do_fragment (vm, bi, mtu, sizeof (ip6_header_t), buffers);
114eb284a1fSOle Troan
115eb284a1fSOle Troan      /* Fixup */
116eb284a1fSOle Troan      u32 *i;
117eb284a1fSOle Troan      vec_foreach (i, *buffers)
118eb284a1fSOle Troan      {
119eb284a1fSOle Troan	vlib_buffer_t *p = vlib_get_buffer (vm, *i);
120eb284a1fSOle Troan	ip6_header_t *ip6 = vlib_buffer_get_current (p);
121eb284a1fSOle Troan	ip6->payload_length =
122eb284a1fSOle Troan	  clib_host_to_net_u16 (p->current_length - sizeof (ip6_header_t));
123eb284a1fSOle Troan      }
12406e3d075SKeith Burns (alagalah)    }
12506e3d075SKeith Burns (alagalah)  else
12606e3d075SKeith Burns (alagalah)    {
12706e3d075SKeith Burns (alagalah)      if (df && !mm->frag_ignore_df)
12806e3d075SKeith Burns (alagalah)	{
12906e3d075SKeith Burns (alagalah)	  icmp4_error_set_vnet_buffer (b, ICMP4_destination_unreachable,
13006e3d075SKeith Burns (alagalah)				       ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
13106e3d075SKeith Burns (alagalah)				       mtu);
13206e3d075SKeith Burns (alagalah)	  vlib_buffer_advance (b, sizeof (ip6_header_t));
13306e3d075SKeith Burns (alagalah)	  *error = MAP_ERROR_DF_SET;
13406e3d075SKeith Burns (alagalah)	  return (IP4_MAP_NEXT_ICMP_ERROR);
13506e3d075SKeith Burns (alagalah)	}
136eb284a1fSOle Troan
137eb284a1fSOle Troan      /* Create IPv6 fragments here */
138eb284a1fSOle Troan      ip6_frag_do_fragment (vm, bi, mtu, 0, buffers);
1399fb87553SOle Troan    }
140eb284a1fSOle Troan  return (IP4_MAP_NEXT_IP6_LOOKUP);
1419fb87553SOle Troan}
1429fb87553SOle Troan
143cb9cadadSEd Warnicke/*
144cb9cadadSEd Warnicke * ip4_map
145cb9cadadSEd Warnicke */
146cb9cadadSEd Warnickestatic uword
14706e3d075SKeith Burns (alagalah)ip4_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
148cb9cadadSEd Warnicke{
149cb9cadadSEd Warnicke  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
15006e3d075SKeith Burns (alagalah)  vlib_node_runtime_t *error_node =
15106e3d075SKeith Burns (alagalah)    vlib_node_get_runtime (vm, ip4_map_node.index);
15206e3d075SKeith Burns (alagalah)  from = vlib_frame_vector_args (frame);
153cb9cadadSEd Warnicke  n_left_from = frame->n_vectors;
154cb9cadadSEd Warnicke  next_index = node->cached_next_index;
155cb9cadadSEd Warnicke  map_main_t *mm = &map_main;
156cb9cadadSEd Warnicke  vlib_combined_counter_main_t *cm = mm->domain_counters;
157067cd622SDamjan Marion  u32 thread_index = vm->thread_index;
15806e3d075SKeith Burns (alagalah)
15906e3d075SKeith Burns (alagalah)  while (n_left_from > 0)
16006e3d075SKeith Burns (alagalah)    {
16106e3d075SKeith Burns (alagalah)      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
16206e3d075SKeith Burns (alagalah)      while (n_left_from > 0 && n_left_to_next > 0)
16306e3d075SKeith Burns (alagalah)	{
16406e3d075SKeith Burns (alagalah)	  u32 pi0;
16506e3d075SKeith Burns (alagalah)	  vlib_buffer_t *p0;
16606e3d075SKeith Burns (alagalah)	  map_domain_t *d0;
16706e3d075SKeith Burns (alagalah)	  u8 error0 = MAP_ERROR_NONE;
16806e3d075SKeith Burns (alagalah)	  ip4_header_t *ip40;
16906e3d075SKeith Burns (alagalah)	  u16 port0 = 0;
17006e3d075SKeith Burns (alagalah)	  ip6_header_t *ip6h0;
17106e3d075SKeith Burns (alagalah)	  u32 next0 = IP4_MAP_NEXT_IP6_LOOKUP;
17206e3d075SKeith Burns (alagalah)	  u32 map_domain_index0 = ~0;
173eb284a1fSOle Troan	  u32 *buffer0 = 0;
174eb284a1fSOle Troan	  bool free_original_buffer0 = false;
175eb284a1fSOle Troan	  u32 *frag_from0, frag_left0;
17606e3d075SKeith Burns (alagalah)
17706e3d075SKeith Burns (alagalah)	  pi0 = to_next[0] = from[0];
17806e3d075SKeith Burns (alagalah)	  from += 1;
17906e3d075SKeith Burns (alagalah)	  n_left_from -= 1;
18006e3d075SKeith Burns (alagalah)
18106e3d075SKeith Burns (alagalah)	  p0 = vlib_get_buffer (vm, pi0);
18206e3d075SKeith Burns (alagalah)	  ip40 = vlib_buffer_get_current (p0);
183fc7344f9SJon Loeliger
184fc7344f9SJon Loeliger	  d0 =
185fc7344f9SJon Loeliger	    ip4_map_get_domain (&ip40->dst_address, &map_domain_index0,
186fc7344f9SJon Loeliger				&error0);
187fc7344f9SJon Loeliger	  if (!d0)
188fc7344f9SJon Loeliger	    {			/* Guess it wasn't for us */
189fc7344f9SJon Loeliger	      vnet_feature_next (&next0, p0);
190fc7344f9SJon Loeliger	      goto exit;
191fc7344f9SJon Loeliger	    }
19206e3d075SKeith Burns (alagalah)
19306e3d075SKeith Burns (alagalah)	  /*
19406e3d075SKeith Burns (alagalah)	   * Shared IPv4 address
19506e3d075SKeith Burns (alagalah)	   */
196a025b3eaSKlement Sekera	  port0 = ip4_map_port_and_security_check (d0, p0, &error0);
19706e3d075SKeith Burns (alagalah)
198b15ad951SJon Loeliger	  /*
199b15ad951SJon Loeliger	   * Clamp TCP MSS value.
200b15ad951SJon Loeliger	   */
201b15ad951SJon Loeliger	  if (ip40->protocol == IP_PROTOCOL_TCP)
202b15ad951SJon Loeliger	    {
203b15ad951SJon Loeliger	      tcp_header_t *tcp = ip4_next_header (ip40);
204b15ad951SJon Loeliger	      if (mm->tcp_mss > 0 && tcp_syn (tcp))
205b15ad951SJon Loeliger		{
206b15ad951SJon Loeliger		  ip_csum_t csum = tcp->checksum;
207b15ad951SJon Loeliger		  map_mss_clamping (tcp, &csum, mm->tcp_mss);
208b15ad951SJon Loeliger		  tcp->checksum = ip_csum_fold (csum);
209b15ad951SJon Loeliger		}
210b15ad951SJon Loeliger	    }
211b15ad951SJon Loeliger
21206e3d075SKeith Burns (alagalah)	  /* Decrement IPv4 TTL */
21306e3d075SKeith Burns (alagalah)	  ip4_map_decrement_ttl (ip40, &error0);
21406e3d075SKeith Burns (alagalah)	  bool df0 =
215853e720fSEd Warnicke	    ip40->flags_and_fragment_offset &
21606e3d075SKeith Burns (alagalah)	    clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
21706e3d075SKeith Burns (alagalah)
21806e3d075SKeith Burns (alagalah)	  /* MAP calc */
21906e3d075SKeith Burns (alagalah)	  u32 da40 = clib_net_to_host_u32 (ip40->dst_address.as_u32);
22006e3d075SKeith Burns (alagalah)	  u16 dp40 = clib_net_to_host_u16 (port0);
22106e3d075SKeith Burns (alagalah)	  u64 dal60 = map_get_pfx (d0, da40, dp40);
22206e3d075SKeith Burns (alagalah)	  u64 dar60 = map_get_sfx (d0, da40, dp40);
223a025b3eaSKlement Sekera	  if (dal60 == 0 && dar60 == 0 && error0 == MAP_ERROR_NONE)
22406e3d075SKeith Burns (alagalah)	    error0 = MAP_ERROR_NO_BINDING;
22506e3d075SKeith Burns (alagalah)
22606e3d075SKeith Burns (alagalah)	  /* construct ipv6 header */
22706e3d075SKeith Burns (alagalah)	  vlib_buffer_advance (p0, -(sizeof (ip6_header_t)));
22806e3d075SKeith Burns (alagalah)	  ip6h0 = vlib_buffer_get_current (p0);
22906e3d075SKeith Burns (alagalah)	  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
23006e3d075SKeith Burns (alagalah)
23106e3d075SKeith Burns (alagalah)	  ip6h0->ip_version_traffic_class_and_flow_label =
23206e3d075SKeith Burns (alagalah)	    ip4_map_vtcfl (ip40, p0);
23306e3d075SKeith Burns (alagalah)	  ip6h0->payload_length = ip40->length;
23406e3d075SKeith Burns (alagalah)	  ip6h0->protocol = IP_PROTOCOL_IP_IN_IP;
23506e3d075SKeith Burns (alagalah)	  ip6h0->hop_limit = 0x40;
23606e3d075SKeith Burns (alagalah)	  ip6h0->src_address = d0->ip6_src;
23706e3d075SKeith Burns (alagalah)	  ip6h0->dst_address.as_u64[0] = clib_host_to_net_u64 (dal60);
23806e3d075SKeith Burns (alagalah)	  ip6h0->dst_address.as_u64[1] = clib_host_to_net_u64 (dar60);
23906e3d075SKeith Burns (alagalah)
24006e3d075SKeith Burns (alagalah)	  /*
24106e3d075SKeith Burns (alagalah)	   * Determine next node. Can be one of:
242eb284a1fSOle Troan	   * ip6-lookup, ip6-rewrite, error-drop
24306e3d075SKeith Burns (alagalah)	   */
24406e3d075SKeith Burns (alagalah)	  if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
24506e3d075SKeith Burns (alagalah)	    {
24606e3d075SKeith Burns (alagalah)	      if (PREDICT_FALSE
24706e3d075SKeith Burns (alagalah)		  (d0->mtu
24806e3d075SKeith Burns (alagalah)		   && (clib_net_to_host_u16 (ip6h0->payload_length) +
24906e3d075SKeith Burns (alagalah)		       sizeof (*ip6h0) > d0->mtu)))
25006e3d075SKeith Burns (alagalah)		{
251eb284a1fSOle Troan		  next0 =
252eb284a1fSOle Troan		    ip4_map_fragment (vm, pi0, d0->mtu, df0, &buffer0,
253eb284a1fSOle Troan				      &error0);
254eb284a1fSOle Troan
255eb284a1fSOle Troan		  if (error0 == MAP_ERROR_NONE)
256eb284a1fSOle Troan		    {
257eb284a1fSOle Troan		      free_original_buffer0 = true;
258eb284a1fSOle Troan		    }
25906e3d075SKeith Burns (alagalah)		}
26006e3d075SKeith Burns (alagalah)	      else
26106e3d075SKeith Burns (alagalah)		{
26206e3d075SKeith Burns (alagalah)		  next0 =
26306e3d075SKeith Burns (alagalah)		    ip4_map_ip6_lookup_bypass (p0,
26406e3d075SKeith Burns (alagalah)					       ip40) ?
26506e3d075SKeith Burns (alagalah)		    IP4_MAP_NEXT_IP6_REWRITE : next0;
26606e3d075SKeith Burns (alagalah)		  vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX,
267586afd76SDamjan Marion						   thread_index,
26806e3d075SKeith Burns (alagalah)						   map_domain_index0, 1,
26906e3d075SKeith Burns (alagalah)						   clib_net_to_host_u16
27006e3d075SKeith Burns (alagalah)						   (ip6h0->payload_length) +
27106e3d075SKeith Burns (alagalah)						   40);
27206e3d075SKeith Burns (alagalah)		}
27306e3d075SKeith Burns (alagalah)	    }
27406e3d075SKeith Burns (alagalah)	  else
27506e3d075SKeith Burns (alagalah)	    {
27606e3d075SKeith Burns (alagalah)	      next0 = IP4_MAP_NEXT_DROP;
27706e3d075SKeith Burns (alagalah)	    }
27806e3d075SKeith Burns (alagalah)
27906e3d075SKeith Burns (alagalah)	  if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
28006e3d075SKeith Burns (alagalah)	    {
281640edcd9SKlement Sekera	      map_add_trace (vm, node, p0, map_domain_index0, port0);
28206e3d075SKeith Burns (alagalah)	    }
28306e3d075SKeith Burns (alagalah)
28406e3d075SKeith Burns (alagalah)	  p0->error = error_node->errors[error0];
285fc7344f9SJon Loeliger	exit:
286eb284a1fSOle Troan	  /* Send fragments that were added in the frame */
287eb284a1fSOle Troan	  if (free_original_buffer0)
288eb284a1fSOle Troan	    {
289eb284a1fSOle Troan	      vlib_buffer_free_one (vm, pi0);	/* Free original packet */
290eb284a1fSOle Troan	    }
291eb284a1fSOle Troan	  else
292eb284a1fSOle Troan	    {
293eb284a1fSOle Troan	      vec_add1 (buffer0, pi0);
294eb284a1fSOle Troan	    }
295eb284a1fSOle Troan
296eb284a1fSOle Troan	  frag_from0 = buffer0;
297eb284a1fSOle Troan	  frag_left0 = vec_len (buffer0);
298eb284a1fSOle Troan
299eb284a1fSOle Troan	  while (frag_left0 > 0)
300eb284a1fSOle Troan	    {
301eb284a1fSOle Troan	      while (frag_left0 > 0 && n_left_to_next > 0)
302eb284a1fSOle Troan		{
303eb284a1fSOle Troan		  u32 i0;
304eb284a1fSOle Troan		  i0 = to_next[0] = frag_from0[0];
305eb284a1fSOle Troan		  frag_from0 += 1;
306eb284a1fSOle Troan		  frag_left0 -= 1;
307eb284a1fSOle Troan		  to_next += 1;
308eb284a1fSOle Troan		  n_left_to_next -= 1;
309eb284a1fSOle Troan
310eb284a1fSOle Troan		  vlib_get_buffer (vm, i0)->error =
311eb284a1fSOle Troan		    error_node->errors[error0];
312eb284a1fSOle Troan		  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
313eb284a1fSOle Troan						   to_next, n_left_to_next,
314eb284a1fSOle Troan						   i0, next0);
315eb284a1fSOle Troan		}
316eb284a1fSOle Troan	      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
317eb284a1fSOle Troan	      vlib_get_next_frame (vm, node, next_index, to_next,
318eb284a1fSOle Troan				   n_left_to_next);
319eb284a1fSOle Troan	    }
320eb284a1fSOle Troan	  vec_reset_length (buffer0);
321cb9cadadSEd Warnicke	}
32206e3d075SKeith Burns (alagalah)      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
323cb9cadadSEd Warnicke    }
324cb9cadadSEd Warnicke
325cb9cadadSEd Warnicke  return frame->n_vectors;
326cb9cadadSEd Warnicke}
327cb9cadadSEd Warnicke
328cb9cadadSEd Warnickestatic char *map_error_strings[] = {
329cb9cadadSEd Warnicke#define _(sym,string) string,
330cb9cadadSEd Warnicke  foreach_map_error
331cb9cadadSEd Warnicke#undef _
332cb9cadadSEd Warnicke};
333cb9cadadSEd Warnicke
334fc7344f9SJon Loeliger
33506e3d075SKeith Burns (alagalah)/* *INDENT-OFF* */
336fc7344f9SJon LoeligerVNET_FEATURE_INIT (ip4_map_feature, static) =
337fc7344f9SJon Loeliger{
338fc7344f9SJon Loeliger  .arc_name = "ip4-unicast",
339fc7344f9SJon Loeliger  .node_name = "ip4-map",
340a025b3eaSKlement Sekera  .runs_before = VNET_FEATURES ("ip4-flow-classify"),
341a025b3eaSKlement Sekera  .runs_after = VNET_FEATURES("ip4-sv-reassembly-feature"),
342fc7344f9SJon Loeliger};
343fc7344f9SJon Loeliger
344cb9cadadSEd WarnickeVLIB_REGISTER_NODE(ip4_map_node) = {
345cb9cadadSEd Warnicke  .function = ip4_map,
346cb9cadadSEd Warnicke  .name = "ip4-map",
347cb9cadadSEd Warnicke  .vector_size = sizeof(u32),
348cb9cadadSEd Warnicke  .format_trace = format_map_trace,
349cb9cadadSEd Warnicke  .type = VLIB_NODE_TYPE_INTERNAL,
350607de1a0SDamjan Marion
351cb9cadadSEd Warnicke  .n_errors = MAP_N_ERROR,
352cb9cadadSEd Warnicke  .error_strings = map_error_strings,
353cb9cadadSEd Warnicke
354cb9cadadSEd Warnicke  .n_next_nodes = IP4_MAP_N_NEXT,
355cb9cadadSEd Warnicke  .next_nodes = {
356cb9cadadSEd Warnicke    [IP4_MAP_NEXT_IP6_LOOKUP] = "ip6-lookup",
357cb9cadadSEd Warnicke#ifdef MAP_SKIP_IP6_LOOKUP
35880823809SNeale Ranns    [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-load-balance",
359cb9cadadSEd Warnicke#endif
3609fb87553SOle Troan    [IP4_MAP_NEXT_ICMP_ERROR] = "ip4-icmp-error",
361cb9cadadSEd Warnicke    [IP4_MAP_NEXT_DROP] = "error-drop",
362cb9cadadSEd Warnicke  },
363cb9cadadSEd Warnicke};
36406e3d075SKeith Burns (alagalah)/* *INDENT-ON* */
365cb9cadadSEd Warnicke
36606e3d075SKeith Burns (alagalah)/*
36706e3d075SKeith Burns (alagalah) * fd.io coding-style-patch-verification: ON
36806e3d075SKeith Burns (alagalah) *
36906e3d075SKeith Burns (alagalah) * Local Variables:
37006e3d075SKeith Burns (alagalah) * eval: (c-set-style "gnu")
37106e3d075SKeith Burns (alagalah) * End:
37206e3d075SKeith Burns (alagalah) */