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