FD.io VPP  v18.11-rc0-18-g2a3fb1a
Vector Packet Processing
ip4_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/ip4_input.c: IP v4 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/ip4_input.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 #ifndef CLIB_MARCH_VARIANT
51 static u8 *
52 format_ip4_input_trace (u8 * s, va_list * va)
53 {
54  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
55  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
56  ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
57 
58  s = format (s, "%U",
59  format_ip4_header, t->packet_data, sizeof (t->packet_data));
60 
61  return s;
62 }
63 #endif
64 
66 ip4_input_set_next (u32 sw_if_index, vlib_buffer_t * b, int arc_enabled)
67 {
68  ip4_main_t *im = &ip4_main;
69  ip_lookup_main_t *lm = &im->lookup_main;
70  u32 next;
71  u8 arc;
72 
74 
76  {
78  arc = lm->mcast_feature_arc_index;
79  }
80  else
81  {
82  next = IP4_INPUT_NEXT_LOOKUP;
83  arc = lm->ucast_feature_arc_index;
84  }
85 
86  if (arc_enabled)
87  vnet_feature_arc_start (arc, sw_if_index, &next, b);
88 
89  return next;
90 }
91 
94  vlib_simple_counter_main_t * cm, u32 sw_if_index,
95  u32 * last_sw_if_index, u32 * cnt,
96  int *arc_enabled)
97 {
98  ip4_main_t *im = &ip4_main;
99  ip_lookup_main_t *lm = &im->lookup_main;
100  u32 thread_index;
101  if (*last_sw_if_index == sw_if_index)
102  {
103  (*cnt)++;
104  return;
105  }
106 
107  thread_index = vm->thread_index;
108  if (*cnt)
109  vlib_increment_simple_counter (cm, thread_index, *last_sw_if_index, *cnt);
110  *cnt = 1;
111  *last_sw_if_index = sw_if_index;
112 
113  if (vnet_have_features (lm->ucast_feature_arc_index, sw_if_index) ||
114  vnet_have_features (lm->mcast_feature_arc_index, sw_if_index))
115  *arc_enabled = 1;
116  else
117  *arc_enabled = 0;
118 }
119 
120 /* Validate IP v4 packets and pass them either to forwarding code
121  or drop/punt exception packets. */
124  vlib_node_runtime_t * node,
125  vlib_frame_t * frame, int verify_checksum)
126 {
127  vnet_main_t *vnm = vnet_get_main ();
128  u32 n_left_from, *from;
129  u32 thread_index = vm->thread_index;
130  vlib_node_runtime_t *error_node =
133  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
134  ip4_header_t *ip[4];
135  u16 nexts[VLIB_FRAME_SIZE], *next;
136  u32 sw_if_index[4];
137  u32 last_sw_if_index = ~0;
138  u32 cnt = 0;
139  int arc_enabled = 0;
140 
141  from = vlib_frame_vector_args (frame);
142  n_left_from = frame->n_vectors;
143 
144  if (node->flags & VLIB_NODE_FLAG_TRACE)
145  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
146  /* stride */ 1,
147  sizeof (ip4_input_trace_t));
148 
151 
152  vlib_get_buffers (vm, from, bufs, n_left_from);
153  b = bufs;
154  next = nexts;
155  while (n_left_from >= 4)
156  {
157  u32 x = 0;
158 
159  /* Prefetch next iteration. */
160  if (n_left_from >= 12)
161  {
162  vlib_prefetch_buffer_header (b[8], LOAD);
163  vlib_prefetch_buffer_header (b[9], LOAD);
164  vlib_prefetch_buffer_header (b[10], LOAD);
165  vlib_prefetch_buffer_header (b[11], LOAD);
166 
167  CLIB_PREFETCH (b[4]->data, sizeof (ip4_header_t), LOAD);
168  CLIB_PREFETCH (b[5]->data, sizeof (ip4_header_t), LOAD);
169  CLIB_PREFETCH (b[6]->data, sizeof (ip4_header_t), LOAD);
170  CLIB_PREFETCH (b[7]->data, sizeof (ip4_header_t), LOAD);
171  }
172 
173  vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
174  vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
175  vnet_buffer (b[2])->ip.adj_index[VLIB_RX] = ~0;
176  vnet_buffer (b[3])->ip.adj_index[VLIB_RX] = ~0;
177 
178  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
179  sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
180  sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
181  sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
182 
183  x |= sw_if_index[0] ^ last_sw_if_index;
184  x |= sw_if_index[1] ^ last_sw_if_index;
185  x |= sw_if_index[2] ^ last_sw_if_index;
186  x |= sw_if_index[3] ^ last_sw_if_index;
187 
188  if (PREDICT_TRUE (x == 0))
189  {
190  /* we deal with 4 more packets sharing the same sw_if_index
191  with the previous one, so we can optimize */
192  cnt += 4;
193  if (arc_enabled)
194  {
195  next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
196  next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
197  next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
198  next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
199  }
200  else
201  {
202  next[0] = ip4_input_set_next (sw_if_index[0], b[0], 0);
203  next[1] = ip4_input_set_next (sw_if_index[1], b[1], 0);
204  next[2] = ip4_input_set_next (sw_if_index[2], b[2], 0);
205  next[3] = ip4_input_set_next (sw_if_index[3], b[3], 0);
206  }
207  }
208  else
209  {
210  ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
211  &last_sw_if_index, &cnt, &arc_enabled);
212  ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
213  &last_sw_if_index, &cnt, &arc_enabled);
214  ip4_input_check_sw_if_index (vm, cm, sw_if_index[2],
215  &last_sw_if_index, &cnt, &arc_enabled);
216  ip4_input_check_sw_if_index (vm, cm, sw_if_index[3],
217  &last_sw_if_index, &cnt, &arc_enabled);
218 
219  next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
220  next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
221  next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
222  next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
223  }
224 
225  ip[0] = vlib_buffer_get_current (b[0]);
226  ip[1] = vlib_buffer_get_current (b[1]);
227  ip[2] = vlib_buffer_get_current (b[2]);
228  ip[3] = vlib_buffer_get_current (b[3]);
229 
230  ip4_input_check_x4 (vm, error_node, b, ip, next, verify_checksum);
231 
232  /* next */
233  b += 4;
234  next += 4;
235  n_left_from -= 4;
236  }
237  while (n_left_from)
238  {
239  u32 next0;
240  vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
241  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
242  ip4_input_check_sw_if_index (vm, cm, sw_if_index[0], &last_sw_if_index,
243  &cnt, &arc_enabled);
244  next0 = ip4_input_set_next (sw_if_index[0], b[0], arc_enabled);
245  ip[0] = vlib_buffer_get_current (b[0]);
246  ip4_input_check_x1 (vm, error_node, b[0], ip[0], &next0,
247  verify_checksum);
248  next[0] = next0;
249 
250  /* next */
251  b += 1;
252  next += 1;
253  n_left_from -= 1;
254  }
255 
256  vlib_increment_simple_counter (cm, thread_index, last_sw_if_index, cnt);
257  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
258  return frame->n_vectors;
259 }
260 
261 /** \brief IPv4 input node.
262  @node ip4-input
263 
264  This is the IPv4 input node: validates ip4 header checksums,
265  verifies ip header lengths, discards pkts with expired TTLs,
266  and sends pkts to the set of ip feature nodes configured on
267  the rx interface.
268 
269  @param vm vlib_main_t corresponding to the current thread
270  @param node vlib_node_runtime_t
271  @param frame vlib_frame_t whose contents should be dispatched
272 
273  @par Graph mechanics: buffer metadata, next index usage
274 
275  @em Uses:
276  - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
277  multicast status.
278  - <code>b->current_config_index</code> corresponding to each pkt's
279  rx sw_if_index.
280  - This sets the per-packet graph trajectory, ensuring that
281  each packet visits the per-interface features in order.
282 
283  - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
284  - Indicates the @c sw_if_index value of the interface that the
285  packet was received on.
286 
287  @em Sets:
288  - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
289  - The lookup result adjacency index.
290 
291  <em>Next Indices:</em>
292  - Dispatches pkts to the (first) feature node:
293  <code> vnet_get_config_data (... &next0 ...); </code>
294  or @c error-drop
295 */
297  vlib_frame_t * frame)
298 {
299  return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
300 }
301 
303  vlib_node_runtime_t * node,
304  vlib_frame_t * frame)
305 {
306  return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
307 }
308 
309 #ifndef CLIB_MARCH_VARIANT
310 char *ip4_error_strings[] = {
311 #define _(sym,string) string,
313 #undef _
314 };
315 
316 /* *INDENT-OFF* */
318  .name = "ip4-input",
319  .vector_size = sizeof (u32),
320 
321  .n_errors = IP4_N_ERROR,
322  .error_strings = ip4_error_strings,
323 
324  .n_next_nodes = IP4_INPUT_N_NEXT,
325  .next_nodes = {
326  [IP4_INPUT_NEXT_DROP] = "error-drop",
327  [IP4_INPUT_NEXT_PUNT] = "error-punt",
328  [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
329  [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
330  [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
331  [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
332  [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-reassembly",
333  },
334 
335  .format_buffer = format_ip4_header,
336  .format_trace = format_ip4_input_trace,
337 };
338 
340  .name = "ip4-input-no-checksum",
341  .vector_size = sizeof (u32),
342 
343  .n_next_nodes = IP4_INPUT_N_NEXT,
344  .next_nodes = {
345  [IP4_INPUT_NEXT_DROP] = "error-drop",
346  [IP4_INPUT_NEXT_PUNT] = "error-punt",
347  [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
348  [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
349  [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
350  [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
351  [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-reassembly",
352  },
353 
354  .format_buffer = format_ip4_header,
355  .format_trace = format_ip4_input_trace,
356 };
357 /* *INDENT-ON* */
358 
359 static clib_error_t *
361 {
362  clib_error_t *error;
363 
364  ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
365  ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
366  hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
367 
368  {
369  pg_node_t *pn;
370  pn = pg_get_node (ip4_input_node.index);
374  }
375 
376  if ((error = vlib_call_init_function (vm, ip4_cli_init)))
377  return error;
378 
380  return error;
381 
382  if ((error = vlib_call_init_function
384  return error;
385 
386  /* Set flow hash to something non-zero. */
387  ip4_main.flow_hash_seed = 0xdeadbeef;
388 
389  /* Default TTL for packets we generate. */
390  ip4_main.host_config.ttl = 64;
391 
392  return error;
393 }
394 
396 #endif
397 
398 /*
399  * fd.io coding-style-patch-verification: ON
400  *
401  * Local Variables:
402  * eval: (c-set-style "gnu")
403  * End:
404  */
#define CLIB_UNUSED(x)
Definition: clib.h:79
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
vnet_interface_main_t interface_main
Definition: vnet.h:56
format_function_t format_ip4_header
Definition: format.h:89
#define PREDICT_TRUE(x)
Definition: clib.h:106
u32 thread_index
Definition: main.h:176
static_always_inline u32 ip4_input_set_next(u32 sw_if_index, vlib_buffer_t *b, int arc_enabled)
Definition: ip4_input.c:66
unformat_function_t unformat_pg_ip4_header
Definition: format.h:94
ip_lookup_main_t lookup_main
Definition: ip4.h:97
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 increment)
Increment a simple counter.
Definition: counter.h:79
static_always_inline int vnet_have_features(u8 arc, u32 sw_if_index)
Definition: feature.h:183
#define VLIB_NODE_FN(node)
Definition: node.h:173
struct ip4_main_t::@204 host_config
Template information for VPP generated packets.
static clib_error_t * ip4_cli_init(vlib_main_t *vm)
Definition: ip46_cli.c:307
u8 mcast_feature_arc_index
Feature arc indices.
Definition: lookup.h:135
unsigned char u8
Definition: types.h:56
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:356
#define static_always_inline
Definition: clib.h:93
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
static clib_error_t * ip4_init(vlib_main_t *vm)
Definition: ip4_input.c:360
#define always_inline
Definition: clib.h:92
ip4_address_t dst_address
Definition: ip4_packet.h:169
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:184
char * ip4_error_strings[]
Definition: ip4_input.c:310
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static void ip4_input_check_x1(vlib_main_t *vm, vlib_node_runtime_t *error_node, vlib_buffer_t *p0, ip4_header_t *ip0, u32 *next0, int verify_checksum)
Definition: ip4_input.h:280
unsigned int u32
Definition: types.h:88
A collection of simple counters.
Definition: counter.h:58
#define vlib_call_init_function(vm, x)
Definition: init.h:227
#define VLIB_FRAME_SIZE
Definition: node.h:364
vlib_node_registration_t ip4_input_no_checksum_node
(constructor) VLIB_REGISTER_NODE (ip4_input_no_checksum_node)
Definition: ip4_input.c:339
static u8 * format_ip4_input_trace(u8 *s, va_list *va)
Definition: ip4_input.c:52
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
static uword ip4_address_is_multicast(ip4_address_t *a)
Definition: ip4_packet.h:317
#define PREDICT_FALSE(x)
Definition: clib.h:105
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:810
u8 packet_data[64]
Definition: ip4_input.c:47
#define foreach_ip4_error
Definition: ip4_error.h:43
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
u16 n_vectors
Definition: node.h:380
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:77
vlib_main_t * vm
Definition: buffer.c:294
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:332
clib_error_t * ip4_source_check_init(vlib_main_t *vm)
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:89
unformat_function_t * unformat_edit
Definition: pg.h:313
void hdlc_register_input_protocol(vlib_main_t *vm, hdlc_protocol_t protocol, u32 node_index)
Definition: node.c:351
static uword ip4_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int verify_checksum)
Definition: ip4_input.c:123
IPv4 main type.
Definition: ip4.h:95
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1342
u8 ucast_feature_arc_index
Definition: lookup.h:136
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
clib_error_t * ip4_source_and_port_range_check_init(vlib_main_t *vm)
static void ip4_input_check_x4(vlib_main_t *vm, vlib_node_runtime_t *error_node, vlib_buffer_t **p, ip4_header_t **ip, u16 *next, int verify_checksum)
Definition: ip4_input.h:81
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define vnet_buffer(b)
Definition: buffer.h:359
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:832
vlib_node_registration_t ip4_input_node
(constructor) VLIB_REGISTER_NODE (ip4_input_node)
Definition: ip4_input.c:317
void ppp_register_input_protocol(vlib_main_t *vm, ppp_protocol_t protocol, u32 node_index)
Definition: node.c:338
u16 flags
Copy of main node flags.
Definition: node.h:486
u32 flow_hash_seed
Seed for Jenkins hash used to compute ip4 flow hash.
Definition: ip4.h:138
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:128
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:295
u8 ttl
TTL to use for host generated packets.
Definition: ip4.h:144
Definition: pg.h:310
Definition: defs.h:46
static_always_inline void ip4_input_check_sw_if_index(vlib_main_t *vm, vlib_simple_counter_main_t *cm, u32 sw_if_index, u32 *last_sw_if_index, u32 *cnt, int *arc_enabled)
Definition: ip4_input.c:93
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:217