node.c revision 9534696b
1/*
2 * node.c: ipip packet processing
3 *
4 * Copyright (c) 2018 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or aipiped to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <vlib/vlib.h>
19#include <vnet/ipip/ipip.h>
20#include <vnet/ip/ip6_packet.h>
21#include <vnet/mpls/mpls.h>
22#include <vnet/pg/pg.h>
23#include <vppinfra/sparse_vec.h>
24
25#define foreach_ipip_input_next                                                \
26  _(PUNT, "error-punt")                                                        \
27  _(DROP, "error-drop")                                                        \
28  _(IP4_INPUT, "ip4-input")                                                    \
29  _(IP6_INPUT, "ip6-input")
30
31typedef enum
32{
33#define _(s, n) IPIP_INPUT_NEXT_##s,
34  foreach_ipip_input_next
35#undef _
36    IPIP_INPUT_N_NEXT,
37} ipip_input_next_t;
38
39typedef struct
40{
41  u32 tunnel_id;
42  u32 length;
43  ip46_address_t src;
44  ip46_address_t dst;
45  u8 is_ipv6;
46} ipip_rx_trace_t;
47
48static u8 *
49format_ipip_rx_trace (u8 * s, va_list * args)
50{
51  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53  ipip_rx_trace_t *t = va_arg (*args, ipip_rx_trace_t *);
54
55  s = format (s, "IPIP: tunnel %d len %d src %U dst %U", t->tunnel_id,
56	      clib_net_to_host_u16 (t->length), format_ip46_address, &t->src,
57	      IP46_TYPE_ANY, format_ip46_address, &t->dst, IP46_TYPE_ANY);
58  return s;
59}
60
61always_inline uword
62ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
63	    vlib_frame_t * from_frame, bool is_ipv6)
64{
65  ipip_main_t *gm = &ipip_main;
66  u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
67  u32 tunnel_sw_if_index = ~0;
68  u32 thread_index = vm->thread_index;
69  u32 len;
70  vnet_interface_main_t *im = &gm->vnet_main->interface_main;
71
72  from = vlib_frame_vector_args (from_frame);
73  n_left_from = from_frame->n_vectors;
74  next_index = node->cached_next_index;
75  while (n_left_from > 0)
76    {
77      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
78
79      while (n_left_from > 0 && n_left_to_next > 0)
80	{
81	  u32 bi0;
82	  vlib_buffer_t *b0;
83	  ip4_header_t *ip40;
84	  ip6_header_t *ip60;
85	  u32 next0 = IPIP_INPUT_NEXT_DROP;
86	  ip46_address_t src0 = ip46_address_initializer, dst0 =
87	    ip46_address_initializer;
88	  ipip_transport_t transport0;
89	  u8 inner_protocol0;
90
91	  bi0 = to_next[0] = from[0];
92	  from += 1;
93	  n_left_from -= 1;
94	  to_next += 1;
95	  n_left_to_next -= 1;
96
97	  b0 = vlib_get_buffer (vm, bi0);
98
99	  if (is_ipv6)
100	    {
101	      ip60 = vlib_buffer_get_current (b0);
102	      /* Check for outer fragmentation */
103	      if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
104		{
105		  next0 = IPIP_INPUT_NEXT_DROP;
106		  b0->error = node->errors[IPIP_ERROR_FRAGMENTED_PACKET];
107		  goto drop;
108		}
109
110	      vlib_buffer_advance (b0, sizeof (*ip60));
111	      ip_set (&src0, &ip60->src_address, false);
112	      ip_set (&dst0, &ip60->dst_address, false);
113	      inner_protocol0 = ip60->protocol;
114	      transport0 = IPIP_TRANSPORT_IP6;
115	    }
116	  else
117	    {
118	      ip40 = vlib_buffer_get_current (b0);
119	      /* Check for outer fragmentation */
120	      if (ip40->flags_and_fragment_offset &
121		  clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS))
122		{
123		  next0 = IPIP_INPUT_NEXT_DROP;
124		  b0->error = node->errors[IPIP_ERROR_FRAGMENTED_PACKET];
125		  goto drop;
126		}
127	      vlib_buffer_advance (b0, sizeof (*ip40));
128	      ip_set (&src0, &ip40->src_address, true);
129	      ip_set (&dst0, &ip40->dst_address, true);
130	      inner_protocol0 = ip40->protocol;
131	      transport0 = IPIP_TRANSPORT_IP4;
132	    }
133
134	  /*
135	   * Find tunnel. First a lookup for P2P tunnels, then a lookup
136	   * for multipoint tunnels
137	   */
138	  ipip_tunnel_key_t key0 = {.transport = transport0,
139	    .fib_index = vnet_buffer (b0)->ip.fib_index,
140	    .src = dst0,
141	    .dst = src0
142	  };
143	  ipip_tunnel_t *t0 = ipip_tunnel_db_find (&key0);
144	  if (!t0)
145	    {
146	      ip46_address_reset (&key0.dst);
147	      t0 = ipip_tunnel_db_find (&key0);
148	      if (!t0)
149		{
150		  next0 = IPIP_INPUT_NEXT_DROP;
151		  b0->error = node->errors[IPIP_ERROR_NO_TUNNEL];
152		  goto drop;
153		}
154	    }
155	  tunnel_sw_if_index = t0->sw_if_index;
156
157	  len = vlib_buffer_length_in_chain (vm, b0);
158	  vnet_buffer (b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
159
160	  if (inner_protocol0 == IP_PROTOCOL_IPV6)
161	    {
162	      next0 = IPIP_INPUT_NEXT_IP6_INPUT;
163
164	      if (t0->flags & IPIP_TUNNEL_FLAG_DECAP_COPY_ECN)
165		{
166		  if (is_ipv6)
167		    ip6_set_ecn_network_order ((ip60 + 1),
168					       ip6_ecn_network_order (ip60));
169		  else
170		    ip6_set_ecn_network_order ((ip6_header_t *) (ip40 + 1),
171					       ip4_header_get_ecn (ip40));
172		}
173	    }
174	  else if (inner_protocol0 == IP_PROTOCOL_IP_IN_IP)
175	    {
176	      next0 = IPIP_INPUT_NEXT_IP4_INPUT;
177	      if (t0->flags & IPIP_TUNNEL_FLAG_DECAP_COPY_ECN)
178		{
179		  if (is_ipv6)
180		    ip4_header_set_ecn_w_chksum ((ip4_header_t *) (ip60 + 1),
181						 ip6_ecn_network_order
182						 (ip60));
183		  else
184		    ip4_header_set_ecn_w_chksum (ip40 + 1,
185						 ip4_header_get_ecn (ip40));
186		}
187	    }
188
189	  if (!is_ipv6 && t0->mode == IPIP_MODE_6RD
190	      && t0->sixrd.security_check)
191	    {
192	      ip6_header_t *inner_ip60 = vlib_buffer_get_current (b0);
193	      if (sixrd_get_addr_net (t0, inner_ip60->src_address.as_u64[0])
194		  != ip40->src_address.as_u32)
195		{
196		  next0 = IPIP_INPUT_NEXT_DROP;
197		  b0->error = node->errors[IPIP_ERROR_NO_TUNNEL];
198		  goto drop;
199		}
200	    }
201
202	  vlib_increment_combined_counter (im->combined_sw_if_counters +
203					   VNET_INTERFACE_COUNTER_RX,
204					   thread_index, tunnel_sw_if_index,
205					   1 /* packets */ ,
206					   len /* bytes */ );
207
208	drop:
209	  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
210	    {
211	      ipip_rx_trace_t *tr =
212		vlib_add_trace (vm, node, b0, sizeof (*tr));
213	      tr->tunnel_id = tunnel_sw_if_index;
214	      if (is_ipv6)
215		{
216		  tr->length = ip60->payload_length;
217		  tr->src.ip6.as_u64[0] = ip60->src_address.as_u64[0];
218		  tr->src.ip6.as_u64[1] = ip60->src_address.as_u64[1];
219		  tr->dst.ip6.as_u64[0] = ip60->dst_address.as_u64[0];
220		  tr->dst.ip6.as_u64[1] = ip60->dst_address.as_u64[1];
221		}
222	      else
223		{
224		  tr->length = ip40->length;
225		  tr->src.ip4.as_u32 = ip40->src_address.as_u32;
226		  tr->dst.ip4.as_u32 = ip40->dst_address.as_u32;
227		}
228	    }
229
230	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
231					   n_left_to_next, bi0, next0);
232	}
233
234      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
235    }
236  vlib_node_increment_counter (vm,
237			       !is_ipv6 ? ipip4_input_node.index :
238			       ipip6_input_node.index, IPIP_ERROR_DECAP_PKTS,
239			       from_frame->n_vectors);
240  return from_frame->n_vectors;
241}
242
243VLIB_NODE_FN (ipip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
244				 vlib_frame_t * from_frame)
245{
246  return ipip_input (vm, node, from_frame, /* is_ip6 */ false);
247}
248
249VLIB_NODE_FN (ipip6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
250				 vlib_frame_t * from_frame)
251{
252  return ipip_input (vm, node, from_frame, /* is_ip6 */ true);
253}
254
255static char *ipip_error_strings[] = {
256#define _(sym,string) string,
257  foreach_ipip_error
258#undef _
259};
260
261/* *INDENT-OFF* */
262VLIB_REGISTER_NODE(ipip4_input_node) = {
263    .name = "ipip4-input",
264    /* Takes a vector of packets. */
265    .vector_size = sizeof(u32),
266    .n_errors = IPIP_N_ERROR,
267    .error_strings = ipip_error_strings,
268    .n_next_nodes = IPIP_INPUT_N_NEXT,
269    .next_nodes =
270        {
271#define _(s, n) [IPIP_INPUT_NEXT_##s] = n,
272            foreach_ipip_input_next
273#undef _
274        },
275    .format_trace = format_ipip_rx_trace,
276};
277
278VLIB_REGISTER_NODE(ipip6_input_node) = {
279    .name = "ipip6-input",
280    /* Takes a vector of packets. */
281    .vector_size = sizeof(u32),
282    .n_errors = IPIP_N_ERROR,
283    .error_strings = ipip_error_strings,
284    .n_next_nodes = IPIP_INPUT_N_NEXT,
285    .next_nodes =
286        {
287#define _(s, n) [IPIP_INPUT_NEXT_##s] = n,
288            foreach_ipip_input_next
289#undef _
290        },
291    .format_trace = format_ipip_rx_trace,
292};
293
294/* *INDENT-ON* */
295
296/*
297 * fd.io coding-style-patch-verification: ON
298 *
299 * Local Variables:
300 * eval: (c-set-style "gnu")
301 * End:
302 */
303