blob: 1425786a4b1be4454d79a7bcc82d18f3aa560c2c [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
Neale Ranns4c7c8e52017-10-21 09:37:55 -070040#include <vnet/ip/ip4_input.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070041#include <vnet/ethernet/ethernet.h>
42#include <vnet/ppp/ppp.h>
43#include <vnet/hdlc/hdlc.h>
44
Dave Barachd7cb1b52016-12-09 09:52:16 -050045typedef struct
46{
Ed Warnickecb9cada2015-12-08 15:45:58 -070047 u8 packet_data[64];
48} ip4_input_trace_t;
49
Dave Barachd7cb1b52016-12-09 09:52:16 -050050static u8 *
51format_ip4_input_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070052{
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 *);
Dave Barachd7cb1b52016-12-09 09:52:16 -050055 ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070056
57 s = format (s, "%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -050058 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
60 return s;
61}
Damjan Marion3ade6b62018-05-26 18:53:34 +020062
63static_always_inline u32
64ip4_input_set_next (u32 sw_if_index, vlib_buffer_t * b, int arc_enabled)
65{
66 ip4_main_t *im = &ip4_main;
67 ip_lookup_main_t *lm = &im->lookup_main;
68 u32 next;
69 u8 arc;
70
71 ip4_header_t *ip = vlib_buffer_get_current (b);
72
73 if (PREDICT_FALSE (ip4_address_is_multicast (&ip->dst_address)))
74 {
75 next = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
76 arc = lm->mcast_feature_arc_index;
77 }
78 else
79 {
80 next = IP4_INPUT_NEXT_LOOKUP;
81 arc = lm->ucast_feature_arc_index;
82 }
83
84 if (arc_enabled)
85 vnet_feature_arc_start (arc, sw_if_index, &next, b);
86
87 return next;
88}
89
90static_always_inline void
Damjan Marion067cd622018-07-11 12:47:43 +020091ip4_input_check_sw_if_index (vlib_main_t * vm,
92 vlib_simple_counter_main_t * cm, u32 sw_if_index,
Damjan Marion3ade6b62018-05-26 18:53:34 +020093 u32 * last_sw_if_index, u32 * cnt,
94 int *arc_enabled)
95{
96 ip4_main_t *im = &ip4_main;
97 ip_lookup_main_t *lm = &im->lookup_main;
98 u32 thread_index;
99 if (*last_sw_if_index == sw_if_index)
100 {
101 (*cnt)++;
102 return;
103 }
104
Damjan Marion067cd622018-07-11 12:47:43 +0200105 thread_index = vm->thread_index;
Damjan Marion3ade6b62018-05-26 18:53:34 +0200106 if (*cnt)
107 vlib_increment_simple_counter (cm, thread_index, *last_sw_if_index, *cnt);
108 *cnt = 1;
109 *last_sw_if_index = sw_if_index;
110
111 if (vnet_have_features (lm->ucast_feature_arc_index, sw_if_index) ||
112 vnet_have_features (lm->mcast_feature_arc_index, sw_if_index))
113 *arc_enabled = 1;
114 else
115 *arc_enabled = 0;
116}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118/* Validate IP v4 packets and pass them either to forwarding code
119 or drop/punt exception packets. */
120always_inline uword
121ip4_input_inline (vlib_main_t * vm,
122 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500123 vlib_frame_t * frame, int verify_checksum)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500125 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion3ade6b62018-05-26 18:53:34 +0200126 u32 n_left_from, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200127 u32 thread_index = vm->thread_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500128 vlib_node_runtime_t *error_node =
129 vlib_node_get_runtime (vm, ip4_input_node.index);
130 vlib_simple_counter_main_t *cm;
Damjan Marion3ade6b62018-05-26 18:53:34 +0200131 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
132 ip4_header_t *ip[4];
133 u16 nexts[VLIB_FRAME_SIZE], *next;
134 u32 sw_if_index[4];
135 u32 last_sw_if_index = ~0;
136 u32 cnt = 0;
137 int arc_enabled = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
139 from = vlib_frame_vector_args (frame);
140 n_left_from = frame->n_vectors;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
142 if (node->flags & VLIB_NODE_FLAG_TRACE)
143 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
144 /* stride */ 1,
145 sizeof (ip4_input_trace_t));
146
147 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500148 VNET_INTERFACE_COUNTER_IP4);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149
Damjan Marion3ade6b62018-05-26 18:53:34 +0200150 vlib_get_buffers (vm, from, bufs, n_left_from);
151 b = bufs;
152 next = nexts;
153 while (n_left_from >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 {
Damjan Marion3ade6b62018-05-26 18:53:34 +0200155 u32 x = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
Damjan Marion3ade6b62018-05-26 18:53:34 +0200157 /* Prefetch next iteration. */
158 if (n_left_from >= 12)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159 {
Damjan Marion3ade6b62018-05-26 18:53:34 +0200160 vlib_prefetch_buffer_header (b[8], LOAD);
161 vlib_prefetch_buffer_header (b[9], LOAD);
162 vlib_prefetch_buffer_header (b[10], LOAD);
163 vlib_prefetch_buffer_header (b[11], LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
Damjan Marion3ade6b62018-05-26 18:53:34 +0200165 CLIB_PREFETCH (b[4]->data, sizeof (ip4_header_t), LOAD);
166 CLIB_PREFETCH (b[5]->data, sizeof (ip4_header_t), LOAD);
167 CLIB_PREFETCH (b[6]->data, sizeof (ip4_header_t), LOAD);
168 CLIB_PREFETCH (b[7]->data, sizeof (ip4_header_t), LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169 }
170
Damjan Marion3ade6b62018-05-26 18:53:34 +0200171 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
172 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
173 vnet_buffer (b[2])->ip.adj_index[VLIB_RX] = ~0;
174 vnet_buffer (b[3])->ip.adj_index[VLIB_RX] = ~0;
175
176 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
177 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
178 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
179 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
180
181 x |= sw_if_index[0] ^ last_sw_if_index;
182 x |= sw_if_index[1] ^ last_sw_if_index;
183 x |= sw_if_index[2] ^ last_sw_if_index;
184 x |= sw_if_index[3] ^ last_sw_if_index;
185
186 if (PREDICT_TRUE (x == 0))
187 {
188 /* we deal with 4 more packets sharing the same sw_if_index
189 with the previous one, so we can optimize */
190 cnt += 4;
191 if (arc_enabled)
192 {
193 next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
194 next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
195 next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
196 next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
197 }
198 else
199 {
200 next[0] = ip4_input_set_next (sw_if_index[0], b[0], 0);
201 next[1] = ip4_input_set_next (sw_if_index[1], b[1], 0);
202 next[2] = ip4_input_set_next (sw_if_index[2], b[2], 0);
203 next[3] = ip4_input_set_next (sw_if_index[3], b[3], 0);
204 }
205 }
206 else
207 {
Damjan Marion067cd622018-07-11 12:47:43 +0200208 ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
209 &last_sw_if_index, &cnt, &arc_enabled);
210 ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
211 &last_sw_if_index, &cnt, &arc_enabled);
212 ip4_input_check_sw_if_index (vm, cm, sw_if_index[2],
213 &last_sw_if_index, &cnt, &arc_enabled);
214 ip4_input_check_sw_if_index (vm, cm, sw_if_index[3],
215 &last_sw_if_index, &cnt, &arc_enabled);
Damjan Marion3ade6b62018-05-26 18:53:34 +0200216
217 next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
218 next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
219 next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
220 next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
221 }
222
223 ip[0] = vlib_buffer_get_current (b[0]);
224 ip[1] = vlib_buffer_get_current (b[1]);
225 ip[2] = vlib_buffer_get_current (b[2]);
226 ip[3] = vlib_buffer_get_current (b[3]);
227
228 ip4_input_check_x4 (vm, error_node, b, ip, next, verify_checksum);
229
230 /* next */
231 b += 4;
232 next += 4;
233 n_left_from -= 4;
234 }
235 while (n_left_from)
236 {
237 u32 next0;
238 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
239 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
Damjan Marion067cd622018-07-11 12:47:43 +0200240 ip4_input_check_sw_if_index (vm, cm, sw_if_index[0], &last_sw_if_index,
Damjan Marion3ade6b62018-05-26 18:53:34 +0200241 &cnt, &arc_enabled);
242 next0 = ip4_input_set_next (sw_if_index[0], b[0], arc_enabled);
243 ip[0] = vlib_buffer_get_current (b[0]);
244 ip4_input_check_x1 (vm, error_node, b[0], ip[0], &next0,
245 verify_checksum);
246 next[0] = next0;
247
248 /* next */
249 b += 1;
250 next += 1;
251 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 }
253
Damjan Marion3ade6b62018-05-26 18:53:34 +0200254 vlib_increment_simple_counter (cm, thread_index, last_sw_if_index, cnt);
255 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 return frame->n_vectors;
257}
258
Dave Barach132d51d2016-07-07 10:10:17 -0400259/** \brief IPv4 input node.
260 @node ip4-input
261
262 This is the IPv4 input node: validates ip4 header checksums,
263 verifies ip header lengths, discards pkts with expired TTLs,
264 and sends pkts to the set of ip feature nodes configured on
265 the rx interface.
266
267 @param vm vlib_main_t corresponding to the current thread
268 @param node vlib_node_runtime_t
269 @param frame vlib_frame_t whose contents should be dispatched
270
271 @par Graph mechanics: buffer metadata, next index usage
272
273 @em Uses:
Dave Barachd7cb1b52016-12-09 09:52:16 -0500274 - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
Dave Barach132d51d2016-07-07 10:10:17 -0400275 multicast status.
276 - <code>b->current_config_index</code> corresponding to each pkt's
Dave Barachd7cb1b52016-12-09 09:52:16 -0500277 rx sw_if_index.
Dave Barach132d51d2016-07-07 10:10:17 -0400278 - This sets the per-packet graph trajectory, ensuring that
279 each packet visits the per-interface features in order.
280
281 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
282 - Indicates the @c sw_if_index value of the interface that the
283 packet was received on.
284
285 @em Sets:
286 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
287 - The lookup result adjacency index.
288
289 <em>Next Indices:</em>
290 - Dispatches pkts to the (first) feature node:
291 <code> vnet_get_config_data (... &next0 ...); </code>
Dave Barachd7cb1b52016-12-09 09:52:16 -0500292 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -0400293*/
Damjan Marion812b32d2018-05-28 21:26:47 +0200294VLIB_NODE_FN (ip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
Damjan Marion3ade6b62018-05-26 18:53:34 +0200295 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296{
297 return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
298}
299
Damjan Marion812b32d2018-05-28 21:26:47 +0200300VLIB_NODE_FN (ip4_input_no_checksum_node) (vlib_main_t * vm,
Damjan Marion3ade6b62018-05-26 18:53:34 +0200301 vlib_node_runtime_t * node,
302 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303{
304 return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
305}
306
Damjan Marion812b32d2018-05-28 21:26:47 +0200307#ifndef CLIB_MARCH_VARIANT
Neale Ranns4c7c8e52017-10-21 09:37:55 -0700308char *ip4_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309#define _(sym,string) string,
310 foreach_ip4_error
311#undef _
312};
Damjan Marion6e363512018-08-10 22:39:11 +0200313#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700314
Dave Barachd7cb1b52016-12-09 09:52:16 -0500315/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316VLIB_REGISTER_NODE (ip4_input_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700317 .name = "ip4-input",
318 .vector_size = sizeof (u32),
319
320 .n_errors = IP4_N_ERROR,
321 .error_strings = ip4_error_strings,
322
323 .n_next_nodes = IP4_INPUT_N_NEXT,
324 .next_nodes = {
325 [IP4_INPUT_NEXT_DROP] = "error-drop",
326 [IP4_INPUT_NEXT_PUNT] = "error-punt",
Neale Rannsc667ffd2018-06-27 18:59:03 -0700327 [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328 [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
Neale Ranns32e1c012016-11-22 17:07:28 +0000329 [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
Ole Troan92eade12016-01-13 20:17:08 +0100330 [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Klement Sekera75e7d132017-09-20 08:26:30 +0200331 [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-reassembly",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332 },
333
334 .format_buffer = format_ip4_header,
335 .format_trace = format_ip4_input_trace,
336};
337
Damjan Marion812b32d2018-05-28 21:26:47 +0200338VLIB_REGISTER_NODE (ip4_input_no_checksum_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 .name = "ip4-input-no-checksum",
340 .vector_size = sizeof (u32),
341
Neale Ranns8a03e4f2018-07-17 07:15:05 -0700342 .sibling_of = "ip4-input",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 .format_buffer = format_ip4_header,
344 .format_trace = format_ip4_input_trace,
345};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500346/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347
Dave Barachd7cb1b52016-12-09 09:52:16 -0500348static clib_error_t *
349ip4_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500351 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Dave Barachd7cb1b52016-12-09 09:52:16 -0500353 ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
354 ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
355 hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356
357 {
Damjan Marion6e363512018-08-10 22:39:11 +0200358 extern vlib_node_registration_t ip4_input_no_checksum_node;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500359 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 pn = pg_get_node (ip4_input_node.index);
361 pn->unformat_edit = unformat_pg_ip4_header;
362 pn = pg_get_node (ip4_input_no_checksum_node.index);
363 pn->unformat_edit = unformat_pg_ip4_header;
364 }
365
366 if ((error = vlib_call_init_function (vm, ip4_cli_init)))
367 return error;
368
369 if ((error = vlib_call_init_function (vm, ip4_source_check_init)))
370 return error;
371
Dave Barachd7cb1b52016-12-09 09:52:16 -0500372 if ((error = vlib_call_init_function
Dave Barach6f9bca22016-04-30 10:25:32 -0400373 (vm, ip4_source_and_port_range_check_init)))
374 return error;
375
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 /* Set flow hash to something non-zero. */
377 ip4_main.flow_hash_seed = 0xdeadbeef;
378
379 /* Default TTL for packets we generate. */
380 ip4_main.host_config.ttl = 64;
381
382 return error;
383}
384
385VLIB_INIT_FUNCTION (ip4_init);
Dave Barach49433ad2018-08-08 17:59:03 -0400386
387static clib_error_t *
388ip4_main_loop_enter (vlib_main_t * vm)
389{
390 ip4_main_t *im = &ip4_main;
391 vlib_thread_main_t *tm = &vlib_thread_main;
392 u32 n_vlib_mains = tm->n_vlib_mains;
393 int i;
394
395
396 vec_validate (im->arp_throttle_bitmaps, n_vlib_mains);
397 vec_validate (im->arp_throttle_seeds, n_vlib_mains);
398 vec_validate (im->arp_throttle_last_seed_change_time, n_vlib_mains);
399
400 for (i = 0; i < n_vlib_mains; i++)
401 vec_validate (im->arp_throttle_bitmaps[i],
402 (ARP_THROTTLE_BITS / BITS (uword)) - 1);
403 return 0;
404}
405
406VLIB_MAIN_LOOP_ENTER_FUNCTION (ip4_main_loop_enter);
407
Dave Barachd7cb1b52016-12-09 09:52:16 -0500408/*
409 * fd.io coding-style-patch-verification: ON
410 *
411 * Local Variables:
412 * eval: (c-set-style "gnu")
413 * End:
414 */