Line data Source code
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/pg/pg.h>
43 : #include <vnet/ppp/ppp.h>
44 : #include <vnet/hdlc/hdlc.h>
45 : #include <vnet/util/throttle.h>
46 :
47 : typedef struct
48 : {
49 : u8 packet_data[64];
50 : } ip4_input_trace_t;
51 :
52 : static u8 *
53 348992 : format_ip4_input_trace (u8 * s, va_list * va)
54 : {
55 348992 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
56 348992 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
57 348992 : ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
58 :
59 348992 : s = format (s, "%U",
60 348992 : format_ip4_header, t->packet_data, sizeof (t->packet_data));
61 :
62 348992 : return s;
63 : }
64 :
65 : static_always_inline u32
66 13548700 : ip4_input_set_next (u32 sw_if_index, vlib_buffer_t * b, int arc_enabled)
67 : {
68 13548700 : ip4_main_t *im = &ip4_main;
69 13548700 : ip_lookup_main_t *lm = &im->lookup_main;
70 : u32 next;
71 : u8 arc;
72 :
73 13548700 : ip4_header_t *ip = vlib_buffer_get_current (b);
74 :
75 13548700 : if (PREDICT_FALSE (ip4_address_is_multicast (&ip->dst_address)))
76 : {
77 2116 : next = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
78 2116 : arc = lm->mcast_feature_arc_index;
79 : }
80 : else
81 : {
82 13546600 : next = IP4_INPUT_NEXT_LOOKUP;
83 13546600 : arc = lm->ucast_feature_arc_index;
84 : }
85 :
86 13548700 : if (arc_enabled)
87 1475900 : vnet_feature_arc_start (arc, sw_if_index, &next, b);
88 :
89 13548700 : return next;
90 : }
91 :
92 : static_always_inline void
93 1519010 : ip4_input_check_sw_if_index (vlib_main_t * vm,
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 1519010 : ip4_main_t *im = &ip4_main;
99 1519010 : ip_lookup_main_t *lm = &im->lookup_main;
100 : u32 thread_index;
101 1519010 : if (*last_sw_if_index == sw_if_index)
102 : {
103 1153710 : (*cnt)++;
104 1153710 : return;
105 : }
106 :
107 365296 : thread_index = vm->thread_index;
108 365296 : if (*cnt)
109 68772 : vlib_increment_simple_counter (cm, thread_index, *last_sw_if_index, *cnt);
110 365296 : *cnt = 1;
111 365296 : *last_sw_if_index = sw_if_index;
112 :
113 719611 : if (vnet_have_features (lm->ucast_feature_arc_index, sw_if_index) ||
114 354315 : vnet_have_features (lm->mcast_feature_arc_index, sw_if_index))
115 10981 : *arc_enabled = 1;
116 : else
117 354315 : *arc_enabled = 0;
118 : }
119 :
120 : /* Validate IP v4 packets and pass them either to forwarding code
121 : or drop/punt exception packets. */
122 : always_inline uword
123 296524 : ip4_input_inline (vlib_main_t * vm,
124 : vlib_node_runtime_t * node,
125 : vlib_frame_t * frame, int verify_checksum)
126 : {
127 296524 : vnet_main_t *vnm = vnet_get_main ();
128 : u32 n_left_from, *from;
129 296524 : u32 thread_index = vm->thread_index;
130 : vlib_node_runtime_t *error_node =
131 296524 : vlib_node_get_runtime (vm, ip4_input_node.index);
132 : vlib_simple_counter_main_t *cm;
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 296524 : u32 last_sw_if_index = ~0;
138 296524 : u32 cnt = 0;
139 296524 : int arc_enabled = 0;
140 :
141 296524 : from = vlib_frame_vector_args (frame);
142 296524 : n_left_from = frame->n_vectors;
143 :
144 296524 : if (node->flags & VLIB_NODE_FLAG_TRACE)
145 12731 : vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
146 : /* stride */ 1,
147 : sizeof (ip4_input_trace_t));
148 :
149 296524 : cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
150 : VNET_INTERFACE_COUNTER_IP4);
151 :
152 296524 : vlib_get_buffers (vm, from, bufs, n_left_from);
153 296524 : b = bufs;
154 296524 : next = nexts;
155 : #if (CLIB_N_PREFETCHES >= 8)
156 3581190 : while (n_left_from >= 4)
157 : {
158 3284670 : u32 x = 0;
159 :
160 : /* Prefetch next iteration. */
161 3284670 : if (n_left_from >= 12)
162 : {
163 2890850 : vlib_prefetch_buffer_header (b[8], LOAD);
164 2890850 : vlib_prefetch_buffer_header (b[9], LOAD);
165 2890850 : vlib_prefetch_buffer_header (b[10], LOAD);
166 2890850 : vlib_prefetch_buffer_header (b[11], LOAD);
167 :
168 2890850 : vlib_prefetch_buffer_data (b[4], LOAD);
169 2890850 : vlib_prefetch_buffer_data (b[5], LOAD);
170 2890840 : vlib_prefetch_buffer_data (b[6], LOAD);
171 2890840 : vlib_prefetch_buffer_data (b[7], LOAD);
172 : }
173 :
174 3284660 : vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
175 3284660 : vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
176 3284660 : vnet_buffer (b[2])->ip.adj_index[VLIB_RX] = ~0;
177 3284660 : vnet_buffer (b[3])->ip.adj_index[VLIB_RX] = ~0;
178 :
179 3284660 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
180 3284660 : sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
181 3284660 : sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
182 3284660 : sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
183 :
184 3284660 : x |= sw_if_index[0] ^ last_sw_if_index;
185 3284660 : x |= sw_if_index[1] ^ last_sw_if_index;
186 3284660 : x |= sw_if_index[2] ^ last_sw_if_index;
187 3284660 : x |= sw_if_index[3] ^ last_sw_if_index;
188 :
189 3284660 : if (PREDICT_TRUE (x == 0))
190 : {
191 : /* we deal with 4 more packets sharing the same sw_if_index
192 : with the previous one, so we can optimize */
193 3007420 : cnt += 4;
194 3007420 : if (arc_enabled)
195 : {
196 87434 : next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
197 87442 : next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
198 87449 : next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
199 87461 : next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
200 : }
201 : else
202 : {
203 2919990 : next[0] = ip4_input_set_next (sw_if_index[0], b[0], 0);
204 2919990 : next[1] = ip4_input_set_next (sw_if_index[1], b[1], 0);
205 2919990 : next[2] = ip4_input_set_next (sw_if_index[2], b[2], 0);
206 2919990 : next[3] = ip4_input_set_next (sw_if_index[3], b[3], 0);
207 : }
208 : }
209 : else
210 : {
211 277237 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
212 : &last_sw_if_index, &cnt, &arc_enabled);
213 277237 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
214 : &last_sw_if_index, &cnt, &arc_enabled);
215 277237 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[2],
216 : &last_sw_if_index, &cnt, &arc_enabled);
217 277237 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[3],
218 : &last_sw_if_index, &cnt, &arc_enabled);
219 :
220 277237 : next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
221 277237 : next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
222 277237 : next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
223 277237 : next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
224 : }
225 :
226 3284690 : ip[0] = vlib_buffer_get_current (b[0]);
227 3284690 : ip[1] = vlib_buffer_get_current (b[1]);
228 3284680 : ip[2] = vlib_buffer_get_current (b[2]);
229 3284680 : ip[3] = vlib_buffer_get_current (b[3]);
230 :
231 3284680 : ip4_input_check_x4 (vm, error_node, b, ip, next, verify_checksum);
232 :
233 : /* next */
234 3284660 : b += 4;
235 3284660 : next += 4;
236 3284660 : n_left_from -= 4;
237 : }
238 : #elif (CLIB_N_PREFETCHES >= 4)
239 : while (n_left_from >= 2)
240 : {
241 : u32 x = 0;
242 : u32 next0, next1;
243 :
244 : /* Prefetch next iteration. */
245 : if (n_left_from >= 6)
246 : {
247 : vlib_prefetch_buffer_header (b[4], LOAD);
248 : vlib_prefetch_buffer_header (b[5], LOAD);
249 :
250 : vlib_prefetch_buffer_data (b[2], LOAD);
251 : vlib_prefetch_buffer_data (b[3], LOAD);
252 : }
253 :
254 : vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
255 : vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
256 :
257 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
258 : sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
259 :
260 : x |= sw_if_index[0] ^ last_sw_if_index;
261 : x |= sw_if_index[1] ^ last_sw_if_index;
262 :
263 : if (PREDICT_TRUE (x == 0))
264 : {
265 : /* we deal with 2 more packets sharing the same sw_if_index
266 : with the previous one, so we can optimize */
267 : cnt += 2;
268 : if (arc_enabled)
269 : {
270 : next0 = ip4_input_set_next (sw_if_index[0], b[0], 1);
271 : next1 = ip4_input_set_next (sw_if_index[1], b[1], 1);
272 : }
273 : else
274 : {
275 : next0 = ip4_input_set_next (sw_if_index[0], b[0], 0);
276 : next1 = ip4_input_set_next (sw_if_index[1], b[1], 0);
277 : }
278 : }
279 : else
280 : {
281 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
282 : &last_sw_if_index, &cnt, &arc_enabled);
283 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
284 : &last_sw_if_index, &cnt, &arc_enabled);
285 :
286 : next0 = ip4_input_set_next (sw_if_index[0], b[0], 1);
287 : next1 = ip4_input_set_next (sw_if_index[1], b[1], 1);
288 : }
289 :
290 : ip[0] = vlib_buffer_get_current (b[0]);
291 : ip[1] = vlib_buffer_get_current (b[1]);
292 :
293 : ip4_input_check_x2 (vm, error_node, b[0], b[1], ip[0], ip[1],
294 : &next0, &next1, verify_checksum);
295 : next[0] = (u16) next0;
296 : next[1] = (u16) next1;
297 :
298 : /* next */
299 : b += 2;
300 : next += 2;
301 : n_left_from -= 2;
302 : }
303 : #endif
304 :
305 706585 : while (n_left_from)
306 : {
307 : u32 next0;
308 410061 : vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
309 410061 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
310 410061 : ip4_input_check_sw_if_index (vm, cm, sw_if_index[0], &last_sw_if_index,
311 : &cnt, &arc_enabled);
312 410061 : next0 = ip4_input_set_next (sw_if_index[0], b[0], arc_enabled);
313 410061 : ip[0] = vlib_buffer_get_current (b[0]);
314 410061 : ip4_input_check_x1 (vm, error_node, b[0], ip[0], &next0,
315 : verify_checksum);
316 410062 : next[0] = next0;
317 :
318 : /* next */
319 410062 : b += 1;
320 410062 : next += 1;
321 410062 : n_left_from -= 1;
322 : }
323 :
324 296524 : vlib_increment_simple_counter (cm, thread_index, last_sw_if_index, cnt);
325 296524 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
326 296524 : return frame->n_vectors;
327 : }
328 :
329 : /** \brief IPv4 input node.
330 : @node ip4-input
331 :
332 : This is the IPv4 input node: validates ip4 header checksums,
333 : verifies ip header lengths, discards pkts with expired TTLs,
334 : and sends pkts to the set of ip feature nodes configured on
335 : the rx interface.
336 :
337 : @param vm vlib_main_t corresponding to the current thread
338 : @param node vlib_node_runtime_t
339 : @param frame vlib_frame_t whose contents should be dispatched
340 :
341 : @par Graph mechanics: buffer metadata, next index usage
342 :
343 : @em Uses:
344 : - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
345 : multicast status.
346 : - <code>b->current_config_index</code> corresponding to each pkt's
347 : rx sw_if_index.
348 : - This sets the per-packet graph trajectory, ensuring that
349 : each packet visits the per-interface features in order.
350 :
351 : - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
352 : - Indicates the @c sw_if_index value of the interface that the
353 : packet was received on.
354 :
355 : @em Sets:
356 : - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
357 : - The lookup result adjacency index.
358 :
359 : <em>Next Indices:</em>
360 : - Dispatches pkts to the (first) feature node:
361 : <code> vnet_get_config_data (... &next0 ...); </code>
362 : or @c error-drop
363 : */
364 293883 : VLIB_NODE_FN (ip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
365 : vlib_frame_t * frame)
366 : {
367 291583 : return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
368 : }
369 :
370 7241 : VLIB_NODE_FN (ip4_input_no_checksum_node) (vlib_main_t * vm,
371 : vlib_node_runtime_t * node,
372 : vlib_frame_t * frame)
373 : {
374 4941 : return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
375 : }
376 :
377 : /* *INDENT-OFF* */
378 183788 : VLIB_REGISTER_NODE (ip4_input_node) = {
379 : .name = "ip4-input",
380 : .vector_size = sizeof (u32),
381 : .protocol_hint = VLIB_NODE_PROTO_HINT_IP4,
382 :
383 : .n_errors = IP4_N_ERROR,
384 : .error_counters = ip4_error_counters,
385 :
386 : .n_next_nodes = IP4_INPUT_N_NEXT,
387 : .next_nodes = {
388 : [IP4_INPUT_NEXT_DROP] = "error-drop",
389 : [IP4_INPUT_NEXT_PUNT] = "error-punt",
390 : [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
391 : [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
392 : [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
393 : [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
394 : },
395 :
396 : .format_buffer = format_ip4_header,
397 : .format_trace = format_ip4_input_trace,
398 : };
399 :
400 183788 : VLIB_REGISTER_NODE (ip4_input_no_checksum_node) = {
401 : .name = "ip4-input-no-checksum",
402 : .vector_size = sizeof (u32),
403 :
404 : .sibling_of = "ip4-input",
405 : .format_buffer = format_ip4_header,
406 : .format_trace = format_ip4_input_trace,
407 : };
408 : /* *INDENT-ON* */
409 :
410 : static clib_error_t *
411 575 : ip4_init (vlib_main_t * vm)
412 : {
413 : clib_error_t *error;
414 :
415 575 : ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
416 575 : ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
417 575 : hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
418 :
419 : {
420 : extern vlib_node_registration_t ip4_input_no_checksum_node;
421 : pg_node_t *pn;
422 575 : pn = pg_get_node (ip4_input_node.index);
423 575 : pn->unformat_edit = unformat_pg_ip4_header;
424 575 : pn = pg_get_node (ip4_input_no_checksum_node.index);
425 575 : pn->unformat_edit = unformat_pg_ip4_header;
426 : }
427 :
428 575 : if ((error = vlib_call_init_function (vm, ip4_cli_init)))
429 0 : return error;
430 :
431 575 : if ((error = vlib_call_init_function
432 : (vm, ip4_source_and_port_range_check_init)))
433 0 : return error;
434 :
435 : /* Set flow hash to something non-zero. */
436 575 : ip4_main.flow_hash_seed = 0xdeadbeef;
437 :
438 : /* Default TTL for packets we generate. */
439 575 : ip4_main.host_config.ttl = 64;
440 :
441 575 : return error;
442 : }
443 :
444 13823 : VLIB_INIT_FUNCTION (ip4_init);
445 :
446 : /*
447 : * fd.io coding-style-patch-verification: ON
448 : *
449 : * Local Variables:
450 : * eval: (c-set-style "gnu")
451 : * End:
452 : */
|