FD.io VPP  v17.01-9-ge7dcee4
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 {
70 
71 /* Validate IP v6 packets and pass them either to forwarding code
72  or drop exception packets. */
73 static uword
75 {
76  vnet_main_t *vnm = vnet_get_main ();
77  ip6_main_t *im = &ip6_main;
78  ip_lookup_main_t *lm = &im->lookup_main;
79  u32 n_left_from, *from, *to_next;
80  ip6_input_next_t next_index;
81  vlib_node_runtime_t *error_node =
84  u32 cpu_index = os_get_cpu_number ();
85 
86  from = vlib_frame_vector_args (frame);
87  n_left_from = frame->n_vectors;
88  next_index = node->cached_next_index;
89 
90  if (node->flags & VLIB_NODE_FLAG_TRACE)
91  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
92  /* stride */ 1,
93  sizeof (ip6_input_trace_t));
94 
97 
98  while (n_left_from > 0)
99  {
100  u32 n_left_to_next;
101 
102  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
103 
104  while (n_left_from >= 4 && n_left_to_next >= 2)
105  {
106  vlib_buffer_t *p0, *p1;
107  ip6_header_t *ip0, *ip1;
108  u32 pi0, sw_if_index0, next0 = 0;
109  u32 pi1, sw_if_index1, next1 = 0;
110  u8 error0, error1, arc0, arc1;
111 
112  /* Prefetch next iteration. */
113  {
114  vlib_buffer_t *p2, *p3;
115 
116  p2 = vlib_get_buffer (vm, from[2]);
117  p3 = vlib_get_buffer (vm, from[3]);
118 
119  vlib_prefetch_buffer_header (p2, LOAD);
120  vlib_prefetch_buffer_header (p3, LOAD);
121 
122  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
123  CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
124  }
125 
126  pi0 = from[0];
127  pi1 = from[1];
128 
129  to_next[0] = pi0;
130  to_next[1] = pi1;
131  from += 2;
132  to_next += 2;
133  n_left_from -= 2;
134  n_left_to_next -= 2;
135 
136  p0 = vlib_get_buffer (vm, pi0);
137  p1 = vlib_get_buffer (vm, pi1);
138 
139  ip0 = vlib_buffer_get_current (p0);
140  ip1 = vlib_buffer_get_current (p1);
141 
142  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
143  sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
144 
145  arc0 =
148  arc1 =
151 
152  vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
153  vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
154 
155  vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
156  vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1);
157 
158  vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
159  vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1);
160 
161  error0 = error1 = IP6_ERROR_NONE;
162 
163  /* Version != 6? Drop it. */
164  error0 =
165  (clib_net_to_host_u32
167  6 ? IP6_ERROR_VERSION : error0;
168  error1 =
169  (clib_net_to_host_u32
171  6 ? IP6_ERROR_VERSION : error1;
172 
173  /* hop limit < 1? Drop it. for link-local broadcast packets,
174  * like dhcpv6 packets from client has hop-limit 1, which should not
175  * be dropped.
176  */
177  error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
178  error1 = ip1->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error1;
179 
180  /* L2 length must be at least minimal IP header. */
181  error0 =
182  p0->current_length <
183  sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
184  error1 =
185  p1->current_length <
186  sizeof (ip1[0]) ? IP6_ERROR_TOO_SHORT : error1;
187 
188  if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
189  {
190  if (error0 == IP6_ERROR_TIME_EXPIRED)
191  {
192  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
193  ICMP6_time_exceeded_ttl_exceeded_in_transit,
194  0);
196  }
197  else
198  {
199  next0 = IP6_INPUT_NEXT_DROP;
200  }
201  }
202  if (PREDICT_FALSE (error1 != IP6_ERROR_NONE))
203  {
204  if (error1 == IP6_ERROR_TIME_EXPIRED)
205  {
206  icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
207  ICMP6_time_exceeded_ttl_exceeded_in_transit,
208  0);
210  }
211  else
212  {
213  next1 = IP6_INPUT_NEXT_DROP;
214  }
215  }
216 
217  p0->error = error_node->errors[error0];
218  p1->error = error_node->errors[error1];
219 
220  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
221  to_next, n_left_to_next,
222  pi0, pi1, next0, next1);
223  }
224 
225  while (n_left_from > 0 && n_left_to_next > 0)
226  {
227  vlib_buffer_t *p0;
228  ip6_header_t *ip0;
229  u32 pi0, sw_if_index0, next0 = 0;
230  u8 error0, arc0;
231 
232  pi0 = from[0];
233  to_next[0] = pi0;
234  from += 1;
235  to_next += 1;
236  n_left_from -= 1;
237  n_left_to_next -= 1;
238 
239  p0 = vlib_get_buffer (vm, pi0);
240  ip0 = vlib_buffer_get_current (p0);
241 
242  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
243  arc0 =
246  vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
247  vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
248 
249  vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
250  error0 = IP6_ERROR_NONE;
251 
252  /* Version != 6? Drop it. */
253  error0 =
254  (clib_net_to_host_u32
256  6 ? IP6_ERROR_VERSION : error0;
257 
258  /* hop limit < 1? Drop it. for link-local broadcast packets,
259  * like dhcpv6 packets from client has hop-limit 1, which should not
260  * be dropped.
261  */
262  error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
263 
264  /* L2 length must be at least minimal IP header. */
265  error0 =
266  p0->current_length <
267  sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
268 
269  if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
270  {
271  if (error0 == IP6_ERROR_TIME_EXPIRED)
272  {
273  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
274  ICMP6_time_exceeded_ttl_exceeded_in_transit,
275  0);
277  }
278  else
279  {
280  next0 = IP6_INPUT_NEXT_DROP;
281  }
282  }
283  p0->error = error_node->errors[error0];
284 
285  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
286  to_next, n_left_to_next,
287  pi0, next0);
288  }
289 
290  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
291  }
292 
293  return frame->n_vectors;
294 }
295 
296 static char *ip6_error_strings[] = {
297 #define _(sym,string) string,
299 #undef _
300 };
301 
302 /* *INDENT-OFF* */
304  .function = ip6_input,
305  .name = "ip6-input",
306  .vector_size = sizeof (u32),
307 
308  .n_errors = IP6_N_ERROR,
309  .error_strings = ip6_error_strings,
310 
311  .n_next_nodes = IP6_INPUT_N_NEXT,
312  .next_nodes = {
313  [IP6_INPUT_NEXT_DROP] = "error-drop",
314  [IP6_INPUT_NEXT_LOOKUP] = "ip6-lookup",
315  [IP6_INPUT_NEXT_ICMP_ERROR] = "ip6-icmp-error",
316  },
317 
318  .format_buffer = format_ip6_header,
319  .format_trace = format_ip6_input_trace,
320 };
321 /* *INDENT-ON* */
322 
325 {
326  ethernet_register_input_type (vm, ETHERNET_TYPE_IP6, ip6_input_node.index);
327  ppp_register_input_protocol (vm, PPP_PROTOCOL_ip6, ip6_input_node.index);
328  hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip6, ip6_input_node.index);
329 
330  {
331  pg_node_t *pn;
332  pn = pg_get_node (ip6_input_node.index);
334  }
335 
336  /* Set flow hash to something non-zero. */
337  ip6_main.flow_hash_seed = 0xdeadbeef;
338 
339  /* Default hop limit for packets we generate. */
340  ip6_main.host_config.ttl = 64;
341 
342  return /* no error */ 0;
343 }
344 
346 
347 /*
348  * fd.io coding-style-patch-verification: ON
349  *
350  * Local Variables:
351  * eval: (c-set-style "gnu")
352  * End:
353  */
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
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 cpu_index, u32 index, u32 increment)
Increment a simple counter.
Definition: counter.h:78
#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_interface_main_t interface_main
Definition: vnet.h:57
u32 flow_hash_seed
Definition: ip6.h:168
u8 ttl
Definition: ip6.h:173
static clib_error_t * ip6_init(vlib_main_t *vm)
Definition: ip6_input.c:324
vlib_error_t * errors
Definition: node.h:419
u8 mcast_feature_arc_index
Feature arc indices.
Definition: lookup.h:388
struct ip6_main_t::@169 host_config
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:350
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
unformat_function_t unformat_pg_ip6_header
Definition: format.h:99
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
vlib_node_registration_t ip6_input_node
(constructor) VLIB_REGISTER_NODE (ip6_input_node)
Definition: ip6_input.c:303
#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:59
void ppp_register_input_protocol(vlib_main_t *vm, ppp_protocol_t protocol, u32 node_index)
Definition: node.c:329
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:82
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
#define PREDICT_FALSE(x)
Definition: clib.h:97
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:614
#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:121
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
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:296
void hdlc_register_input_protocol(vlib_main_t *vm, hdlc_protocol_t protocol, u32 node_index)
Definition: node.c:319
u16 cached_next_index
Definition: node.h:463
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:361
ip6_main_t ip6_main
Definition: ip6_forward.c:2828
ip_lookup_main_t lookup_main
Definition: ip6.h:135
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
ip6_input_next_t
Definition: ip6_input.c:63
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1282
u64 uword
Definition: types.h:112
u8 ucast_feature_arc_index
Definition: lookup.h:389
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:324
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:141
unsigned char u8
Definition: types.h:56
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 vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:170
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u8 data[0]
Packet data.
Definition: buffer.h:158
static uword ip6_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_input.c:74
format_function_t format_ip6_header
Definition: format.h:98
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
Definition: pg.h:304
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:337
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:203