FD.io VPP  v17.04-9-g99c0734
Vector Packet Processing
ip6_input.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  * ip/ip6_input.c: IP v6 input node
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <vnet/ip/ip.h>
41 #include <vnet/ethernet/ethernet.h>
42 #include <vnet/ppp/ppp.h>
43 #include <vnet/hdlc/hdlc.h>
44 
45 typedef struct
46 {
47  u8 packet_data[64];
49 
50 static u8 *
51 format_ip6_input_trace (u8 * s, va_list * va)
52 {
53  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
54  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
55  ip6_input_trace_t *t = va_arg (*va, ip6_input_trace_t *);
56 
57  s = format (s, "%U",
58  format_ip6_header, t->packet_data, sizeof (t->packet_data));
59 
60  return s;
61 }
62 
63 typedef enum
64 {
71 
72 /* Validate IP v6 packets and pass them either to forwarding code
73  or drop exception packets. */
74 static uword
76 {
77  vnet_main_t *vnm = vnet_get_main ();
78  ip6_main_t *im = &ip6_main;
79  ip_lookup_main_t *lm = &im->lookup_main;
80  u32 n_left_from, *from, *to_next;
81  ip6_input_next_t next_index;
82  vlib_node_runtime_t *error_node =
85  u32 cpu_index = os_get_cpu_number ();
86 
87  from = vlib_frame_vector_args (frame);
88  n_left_from = frame->n_vectors;
89  next_index = node->cached_next_index;
90 
91  if (node->flags & VLIB_NODE_FLAG_TRACE)
92  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
93  /* stride */ 1,
94  sizeof (ip6_input_trace_t));
95 
98 
99  while (n_left_from > 0)
100  {
101  u32 n_left_to_next;
102 
103  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
104 
105  while (n_left_from >= 4 && n_left_to_next >= 2)
106  {
107  vlib_buffer_t *p0, *p1;
108  ip6_header_t *ip0, *ip1;
109  u32 pi0, sw_if_index0, next0 = 0;
110  u32 pi1, sw_if_index1, next1 = 0;
111  u8 error0, error1, arc0, arc1;
112 
113  /* Prefetch next iteration. */
114  {
115  vlib_buffer_t *p2, *p3;
116 
117  p2 = vlib_get_buffer (vm, from[2]);
118  p3 = vlib_get_buffer (vm, from[3]);
119 
120  vlib_prefetch_buffer_header (p2, LOAD);
121  vlib_prefetch_buffer_header (p3, LOAD);
122 
123  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
124  CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
125  }
126 
127  pi0 = from[0];
128  pi1 = from[1];
129 
130  to_next[0] = pi0;
131  to_next[1] = pi1;
132  from += 2;
133  to_next += 2;
134  n_left_from -= 2;
135  n_left_to_next -= 2;
136 
137  p0 = vlib_get_buffer (vm, pi0);
138  p1 = vlib_get_buffer (vm, pi1);
139 
140  ip0 = vlib_buffer_get_current (p0);
141  ip1 = vlib_buffer_get_current (p1);
142 
143  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
144  sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
145 
147  {
148  arc0 = lm->mcast_feature_arc_index;
150  }
151  else
152  {
153  arc0 = lm->ucast_feature_arc_index;
154  next0 = IP6_INPUT_NEXT_LOOKUP;
155  }
156 
158  {
159  arc1 = lm->mcast_feature_arc_index;
161  }
162  else
163  {
164  arc1 = lm->ucast_feature_arc_index;
165  next1 = IP6_INPUT_NEXT_LOOKUP;
166  }
167 
168  vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
169  vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
170 
171  vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
172  vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1);
173 
174  vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
175  vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1);
176 
177  error0 = error1 = IP6_ERROR_NONE;
178 
179  /* Version != 6? Drop it. */
180  error0 =
181  (clib_net_to_host_u32
183  6 ? IP6_ERROR_VERSION : error0;
184  error1 =
185  (clib_net_to_host_u32
187  6 ? IP6_ERROR_VERSION : error1;
188 
189  /* hop limit < 1? Drop it. for link-local broadcast packets,
190  * like dhcpv6 packets from client has hop-limit 1, which should not
191  * be dropped.
192  */
193  error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
194  error1 = ip1->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error1;
195 
196  /* L2 length must be at least minimal IP header. */
197  error0 =
198  p0->current_length <
199  sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
200  error1 =
201  p1->current_length <
202  sizeof (ip1[0]) ? IP6_ERROR_TOO_SHORT : error1;
203 
204  if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
205  {
206  if (error0 == IP6_ERROR_TIME_EXPIRED)
207  {
208  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
209  ICMP6_time_exceeded_ttl_exceeded_in_transit,
210  0);
212  }
213  else
214  {
215  next0 = IP6_INPUT_NEXT_DROP;
216  }
217  }
218  if (PREDICT_FALSE (error1 != IP6_ERROR_NONE))
219  {
220  if (error1 == IP6_ERROR_TIME_EXPIRED)
221  {
222  icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
223  ICMP6_time_exceeded_ttl_exceeded_in_transit,
224  0);
226  }
227  else
228  {
229  next1 = IP6_INPUT_NEXT_DROP;
230  }
231  }
232 
233  p0->error = error_node->errors[error0];
234  p1->error = error_node->errors[error1];
235 
236  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
237  to_next, n_left_to_next,
238  pi0, pi1, next0, next1);
239  }
240 
241  while (n_left_from > 0 && n_left_to_next > 0)
242  {
243  vlib_buffer_t *p0;
244  ip6_header_t *ip0;
245  u32 pi0, sw_if_index0, next0 = 0;
246  u8 error0, arc0;
247 
248  pi0 = from[0];
249  to_next[0] = pi0;
250  from += 1;
251  to_next += 1;
252  n_left_from -= 1;
253  n_left_to_next -= 1;
254 
255  p0 = vlib_get_buffer (vm, pi0);
256  ip0 = vlib_buffer_get_current (p0);
257 
258  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
260  {
261  arc0 = lm->mcast_feature_arc_index;
263  }
264  else
265  {
266  arc0 = lm->ucast_feature_arc_index;
267  next0 = IP6_INPUT_NEXT_LOOKUP;
268  }
269 
270  vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
271  vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
272 
273  vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
274  error0 = IP6_ERROR_NONE;
275 
276  /* Version != 6? Drop it. */
277  error0 =
278  (clib_net_to_host_u32
280  6 ? IP6_ERROR_VERSION : error0;
281 
282  /* hop limit < 1? Drop it. for link-local broadcast packets,
283  * like dhcpv6 packets from client has hop-limit 1, which should not
284  * be dropped.
285  */
286  error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
287 
288  /* L2 length must be at least minimal IP header. */
289  error0 =
290  p0->current_length <
291  sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
292 
293  if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
294  {
295  if (error0 == IP6_ERROR_TIME_EXPIRED)
296  {
297  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
298  ICMP6_time_exceeded_ttl_exceeded_in_transit,
299  0);
301  }
302  else
303  {
304  next0 = IP6_INPUT_NEXT_DROP;
305  }
306  }
307  p0->error = error_node->errors[error0];
308 
309  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
310  to_next, n_left_to_next,
311  pi0, next0);
312  }
313 
314  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
315  }
316 
317  return frame->n_vectors;
318 }
319 
320 static char *ip6_error_strings[] = {
321 #define _(sym,string) string,
323 #undef _
324 };
325 
326 /* *INDENT-OFF* */
328  .function = ip6_input,
329  .name = "ip6-input",
330  .vector_size = sizeof (u32),
331 
332  .n_errors = IP6_N_ERROR,
333  .error_strings = ip6_error_strings,
334 
335  .n_next_nodes = IP6_INPUT_N_NEXT,
336  .next_nodes = {
337  [IP6_INPUT_NEXT_DROP] = "error-drop",
338  [IP6_INPUT_NEXT_LOOKUP] = "ip6-lookup",
339  [IP6_INPUT_NEXT_ICMP_ERROR] = "ip6-icmp-error",
340  [IP6_INPUT_NEXT_LOOKUP_MULTICAST] = "ip6-mfib-forward-lookup",
341  },
342 
343  .format_buffer = format_ip6_header,
344  .format_trace = format_ip6_input_trace,
345 };
346 /* *INDENT-ON* */
347 
350 {
351  ethernet_register_input_type (vm, ETHERNET_TYPE_IP6, ip6_input_node.index);
352  ppp_register_input_protocol (vm, PPP_PROTOCOL_ip6, ip6_input_node.index);
353  hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip6, ip6_input_node.index);
354 
355  {
356  pg_node_t *pn;
357  pn = pg_get_node (ip6_input_node.index);
359  }
360 
361  /* Set flow hash to something non-zero. */
362  ip6_main.flow_hash_seed = 0xdeadbeef;
363 
364  /* Default hop limit for packets we generate. */
365  ip6_main.host_config.ttl = 64;
366 
367  return /* no error */ 0;
368 }
369 
371 
372 /*
373  * fd.io coding-style-patch-verification: ON
374  *
375  * Local Variables:
376  * eval: (c-set-style "gnu")
377  * End:
378  */
#define CLIB_UNUSED(x)
Definition: clib.h:79
static u8 * format_ip6_input_trace(u8 *s, va_list *va)
Definition: ip6_input.c:51
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
vnet_interface_main_t interface_main
Definition: vnet.h:57
u32 flow_hash_seed
Definition: ip6.h:194
struct ip6_main_t::@132 host_config
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:459
u8 ttl
Definition: ip6.h:199
static clib_error_t * ip6_init(vlib_main_t *vm)
Definition: ip6_input.c:349
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:418
u8 mcast_feature_arc_index
Feature arc indices.
Definition: lookup.h:350
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:350
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
vlib_node_registration_t ip6_input_node
(constructor) VLIB_REGISTER_NODE (ip6_input_node)
Definition: ip6_input.c:327
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:164
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
A collection of simple counters.
Definition: counter.h:58
void icmp6_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp6.c:509
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:71
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
#define PREDICT_FALSE(x)
Definition: clib.h:97
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:625
#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:216
#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:350
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:276
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
unformat_function_t * unformat_edit
Definition: pg.h:307
static char * ip6_error_strings[]
Definition: ip6_input.c:320
void hdlc_register_input_protocol(vlib_main_t *vm, hdlc_protocol_t protocol, u32 node_index)
Definition: node.c:326
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:455
unsigned int u32
Definition: types.h:88
ip6_main_t ip6_main
Definition: ip6_forward.c:2846
ip_lookup_main_t lookup_main
Definition: ip6.h:151
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
ip6_input_next_t
Definition: ip6_input.c:63
format_function_t format_ip6_header
Definition: format.h:98
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1296
u64 uword
Definition: types.h:112
u8 ucast_feature_arc_index
Definition: lookup.h:351
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:328
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:45
static uword ip6_address_is_multicast(ip6_address_t *a)
Definition: ip6_packet.h:145
unsigned char u8
Definition: types.h:56
unformat_function_t unformat_pg_ip6_header
Definition: format.h:99
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
#define foreach_ip6_error
Definition: ip6_error.h:43
#define vnet_buffer(b)
Definition: buffer.h:294
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:152
void ppp_register_input_protocol(vlib_main_t *vm, ppp_protocol_t protocol, u32 node_index)
Definition: node.c:338
static uword ip6_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_input.c:75
u16 flags
Copy of main node flags.
Definition: node.h:449
u8 packet_data[64]
Definition: ip6_input.c:47
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 cpu_index, u32 index, u64 increment)
Increment a simple counter.
Definition: counter.h:78
Definition: pg.h:304
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:341
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:201