blob: 121f40f473d483ef76b542d5b17287129bb6e688 [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}
62
Ed Warnickecb9cada2015-12-08 15:45:58 -070063/* Validate IP v4 packets and pass them either to forwarding code
64 or drop/punt exception packets. */
65always_inline uword
66ip4_input_inline (vlib_main_t * vm,
67 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -050068 vlib_frame_t * frame, int verify_checksum)
Ed Warnickecb9cada2015-12-08 15:45:58 -070069{
Dave Barachd7cb1b52016-12-09 09:52:16 -050070 ip4_main_t *im = &ip4_main;
71 vnet_main_t *vnm = vnet_get_main ();
72 ip_lookup_main_t *lm = &im->lookup_main;
73 u32 n_left_from, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070074 ip4_input_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -050075 vlib_node_runtime_t *error_node =
76 vlib_node_get_runtime (vm, ip4_input_node.index);
77 vlib_simple_counter_main_t *cm;
Damjan Marion586afd72017-04-05 19:18:20 +020078 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 from = vlib_frame_vector_args (frame);
81 n_left_from = frame->n_vectors;
82 next_index = node->cached_next_index;
83
84 if (node->flags & VLIB_NODE_FLAG_TRACE)
85 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
86 /* stride */ 1,
87 sizeof (ip4_input_trace_t));
88
89 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
Dave Barachd7cb1b52016-12-09 09:52:16 -050090 VNET_INTERFACE_COUNTER_IP4);
Ed Warnickecb9cada2015-12-08 15:45:58 -070091
92 while (n_left_from > 0)
93 {
94 u32 n_left_to_next;
95
Dave Barachd7cb1b52016-12-09 09:52:16 -050096 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
98 while (n_left_from >= 4 && n_left_to_next >= 2)
99 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500100 vlib_buffer_t *p0, *p1;
101 ip4_header_t *ip0, *ip1;
Neale Ranns4c7c8e52017-10-21 09:37:55 -0700102 u32 sw_if_index0, pi0, next0;
103 u32 sw_if_index1, pi1, next1;
104 u8 arc0, arc1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105
106 /* Prefetch next iteration. */
107 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500108 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700109
110 p2 = vlib_get_buffer (vm, from[2]);
111 p3 = vlib_get_buffer (vm, from[3]);
112
113 vlib_prefetch_buffer_header (p2, LOAD);
114 vlib_prefetch_buffer_header (p3, LOAD);
115
116 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
117 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
118 }
119
120 to_next[0] = pi0 = from[0];
121 to_next[1] = pi1 = from[1];
122 from += 2;
123 to_next += 2;
124 n_left_from -= 2;
125 n_left_to_next -= 2;
126
127 p0 = vlib_get_buffer (vm, pi0);
128 p1 = vlib_get_buffer (vm, pi1);
129
130 ip0 = vlib_buffer_get_current (p0);
131 ip1 = vlib_buffer_get_current (p1);
132
133 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
134 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
135
Damjan Marion4d489932016-12-09 03:21:27 -0800136 if (PREDICT_FALSE (ip4_address_is_multicast (&ip0->dst_address)))
137 {
138 arc0 = lm->mcast_feature_arc_index;
139 next0 = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
140 }
141 else
142 {
143 arc0 = lm->ucast_feature_arc_index;
144 next0 = IP4_INPUT_NEXT_LOOKUP;
Damjan Marion4d489932016-12-09 03:21:27 -0800145 }
146
147 if (PREDICT_FALSE (ip4_address_is_multicast (&ip1->dst_address)))
148 {
149 arc1 = lm->mcast_feature_arc_index;
150 next1 = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
151 }
152 else
153 {
154 arc1 = lm->ucast_feature_arc_index;
155 next1 = IP4_INPUT_NEXT_LOOKUP;
Damjan Marion4d489932016-12-09 03:21:27 -0800156 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157
158 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
159 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
160
Damjan Marion8b3191e2016-11-09 19:54:20 +0100161 vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
162 vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163
Damjan Marion586afd72017-04-05 19:18:20 +0200164 vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
165 vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
Neale Ranns4c7c8e52017-10-21 09:37:55 -0700166 ip4_input_check_x2 (vm, error_node,
167 p0, p1, ip0, ip1,
168 &next0, &next1, verify_checksum);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169
170 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
171 to_next, n_left_to_next,
172 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500173 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 while (n_left_from > 0 && n_left_to_next > 0)
175 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500176 vlib_buffer_t *p0;
177 ip4_header_t *ip0;
Neale Ranns4c7c8e52017-10-21 09:37:55 -0700178 u32 sw_if_index0, pi0, next0;
179 u8 arc0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180
181 pi0 = from[0];
182 to_next[0] = pi0;
183 from += 1;
184 to_next += 1;
185 n_left_from -= 1;
186 n_left_to_next -= 1;
187
188 p0 = vlib_get_buffer (vm, pi0);
189 ip0 = vlib_buffer_get_current (p0);
190
191 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
192
Damjan Marion4d489932016-12-09 03:21:27 -0800193 if (PREDICT_FALSE (ip4_address_is_multicast (&ip0->dst_address)))
194 {
195 arc0 = lm->mcast_feature_arc_index;
196 next0 = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
197 }
198 else
199 {
200 arc0 = lm->ucast_feature_arc_index;
201 next0 = IP4_INPUT_NEXT_LOOKUP;
Damjan Marion4d489932016-12-09 03:21:27 -0800202 }
203
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100205 vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206
Damjan Marion586afd72017-04-05 19:18:20 +0200207 vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
Neale Ranns4c7c8e52017-10-21 09:37:55 -0700208 ip4_input_check_x1 (vm, error_node, p0, ip0, &next0,
209 verify_checksum);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
211 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
212 to_next, n_left_to_next,
213 pi0, next0);
214 }
215
216 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
217 }
218
219 return frame->n_vectors;
220}
221
Dave Barach132d51d2016-07-07 10:10:17 -0400222/** \brief IPv4 input node.
223 @node ip4-input
224
225 This is the IPv4 input node: validates ip4 header checksums,
226 verifies ip header lengths, discards pkts with expired TTLs,
227 and sends pkts to the set of ip feature nodes configured on
228 the rx interface.
229
230 @param vm vlib_main_t corresponding to the current thread
231 @param node vlib_node_runtime_t
232 @param frame vlib_frame_t whose contents should be dispatched
233
234 @par Graph mechanics: buffer metadata, next index usage
235
236 @em Uses:
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
Dave Barach132d51d2016-07-07 10:10:17 -0400238 multicast status.
239 - <code>b->current_config_index</code> corresponding to each pkt's
Dave Barachd7cb1b52016-12-09 09:52:16 -0500240 rx sw_if_index.
Dave Barach132d51d2016-07-07 10:10:17 -0400241 - This sets the per-packet graph trajectory, ensuring that
242 each packet visits the per-interface features in order.
243
244 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
245 - Indicates the @c sw_if_index value of the interface that the
246 packet was received on.
247
248 @em Sets:
249 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
250 - The lookup result adjacency index.
251
252 <em>Next Indices:</em>
253 - Dispatches pkts to the (first) feature node:
254 <code> vnet_get_config_data (... &next0 ...); </code>
Dave Barachd7cb1b52016-12-09 09:52:16 -0500255 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -0400256*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -0500258ip4_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259{
260 return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
261}
262
263static uword
264ip4_input_no_checksum (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500265 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266{
267 return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
268}
269
Neale Ranns4c7c8e52017-10-21 09:37:55 -0700270char *ip4_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271#define _(sym,string) string,
272 foreach_ip4_error
273#undef _
274};
275
Dave Barachd7cb1b52016-12-09 09:52:16 -0500276/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277VLIB_REGISTER_NODE (ip4_input_node) = {
278 .function = ip4_input,
279 .name = "ip4-input",
280 .vector_size = sizeof (u32),
281
282 .n_errors = IP4_N_ERROR,
283 .error_strings = ip4_error_strings,
284
285 .n_next_nodes = IP4_INPUT_N_NEXT,
286 .next_nodes = {
287 [IP4_INPUT_NEXT_DROP] = "error-drop",
288 [IP4_INPUT_NEXT_PUNT] = "error-punt",
289 [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
Neale Ranns32e1c012016-11-22 17:07:28 +0000290 [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
Ole Troan92eade12016-01-13 20:17:08 +0100291 [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 },
293
294 .format_buffer = format_ip4_header,
295 .format_trace = format_ip4_input_trace,
296};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500297/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298
Dave Barachd7cb1b52016-12-09 09:52:16 -0500299VLIB_NODE_FUNCTION_MULTIARCH (ip4_input_node, ip4_input);
Damjan Marion1c80e832016-05-11 23:07:18 +0200300
Dave Barachd7cb1b52016-12-09 09:52:16 -0500301/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302VLIB_REGISTER_NODE (ip4_input_no_checksum_node,static) = {
303 .function = ip4_input_no_checksum,
304 .name = "ip4-input-no-checksum",
305 .vector_size = sizeof (u32),
306
307 .n_next_nodes = IP4_INPUT_N_NEXT,
308 .next_nodes = {
309 [IP4_INPUT_NEXT_DROP] = "error-drop",
310 [IP4_INPUT_NEXT_PUNT] = "error-punt",
311 [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
Neale Ranns32e1c012016-11-22 17:07:28 +0000312 [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
Ole Troan92eade12016-01-13 20:17:08 +0100313 [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700314 },
315
316 .format_buffer = format_ip4_header,
317 .format_trace = format_ip4_input_trace,
318};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500319/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320
Dave Barachd7cb1b52016-12-09 09:52:16 -0500321VLIB_NODE_FUNCTION_MULTIARCH (ip4_input_no_checksum_node,
322 ip4_input_no_checksum);
Damjan Marion1c80e832016-05-11 23:07:18 +0200323
Dave Barachd7cb1b52016-12-09 09:52:16 -0500324static clib_error_t *
325ip4_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500327 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329 ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
330 ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
331 hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332
333 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500334 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 pn = pg_get_node (ip4_input_node.index);
336 pn->unformat_edit = unformat_pg_ip4_header;
337 pn = pg_get_node (ip4_input_no_checksum_node.index);
338 pn->unformat_edit = unformat_pg_ip4_header;
339 }
340
341 if ((error = vlib_call_init_function (vm, ip4_cli_init)))
342 return error;
343
344 if ((error = vlib_call_init_function (vm, ip4_source_check_init)))
345 return error;
346
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 if ((error = vlib_call_init_function
Dave Barach6f9bca22016-04-30 10:25:32 -0400348 (vm, ip4_source_and_port_range_check_init)))
349 return error;
350
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 /* Set flow hash to something non-zero. */
352 ip4_main.flow_hash_seed = 0xdeadbeef;
353
354 /* Default TTL for packets we generate. */
355 ip4_main.host_config.ttl = 64;
356
357 return error;
358}
359
360VLIB_INIT_FUNCTION (ip4_init);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500361
362/*
363 * fd.io coding-style-patch-verification: ON
364 *
365 * Local Variables:
366 * eval: (c-set-style "gnu")
367 * End:
368 */