1425786a4b1be4454d79a7bcc82d18f3aa560c2c
[vpp.git] / src / vnet / ip / ip4_input.c
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];
48 } ip4_input_trace_t;
49
50 static u8 *
51 format_ip4_input_trace (u8 * s, va_list * va)
52 {
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 *);
55   ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
56
57   s = format (s, "%U",
58               format_ip4_header, t->packet_data, sizeof (t->packet_data));
59
60   return s;
61 }
62
63 static_always_inline u32
64 ip4_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
90 static_always_inline void
91 ip4_input_check_sw_if_index (vlib_main_t * vm,
92                              vlib_simple_counter_main_t * cm, u32 sw_if_index,
93                              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
105   thread_index = vm->thread_index;
106   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 }
117
118 /* Validate IP v4 packets and pass them either to forwarding code
119    or drop/punt exception packets. */
120 always_inline uword
121 ip4_input_inline (vlib_main_t * vm,
122                   vlib_node_runtime_t * node,
123                   vlib_frame_t * frame, int verify_checksum)
124 {
125   vnet_main_t *vnm = vnet_get_main ();
126   u32 n_left_from, *from;
127   u32 thread_index = vm->thread_index;
128   vlib_node_runtime_t *error_node =
129     vlib_node_get_runtime (vm, ip4_input_node.index);
130   vlib_simple_counter_main_t *cm;
131   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;
138
139   from = vlib_frame_vector_args (frame);
140   n_left_from = frame->n_vectors;
141
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,
148                          VNET_INTERFACE_COUNTER_IP4);
149
150   vlib_get_buffers (vm, from, bufs, n_left_from);
151   b = bufs;
152   next = nexts;
153   while (n_left_from >= 4)
154     {
155       u32 x = 0;
156
157       /* Prefetch next iteration. */
158       if (n_left_from >= 12)
159         {
160           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);
164
165           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);
169         }
170
171       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         {
208           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);
216
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];
240       ip4_input_check_sw_if_index (vm, cm, sw_if_index[0], &last_sw_if_index,
241                                    &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;
252     }
253
254   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);
256   return frame->n_vectors;
257 }
258
259 /** \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:
274     - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
275       multicast status.
276     - <code>b->current_config_index</code> corresponding to each pkt's
277       rx sw_if_index.
278          - 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>
292       or @c error-drop
293 */
294 VLIB_NODE_FN (ip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
295                                vlib_frame_t * frame)
296 {
297   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
298 }
299
300 VLIB_NODE_FN (ip4_input_no_checksum_node) (vlib_main_t * vm,
301                                            vlib_node_runtime_t * node,
302                                            vlib_frame_t * frame)
303 {
304   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
305 }
306
307 #ifndef CLIB_MARCH_VARIANT
308 char *ip4_error_strings[] = {
309 #define _(sym,string) string,
310   foreach_ip4_error
311 #undef _
312 };
313 #endif
314
315 /* *INDENT-OFF* */
316 VLIB_REGISTER_NODE (ip4_input_node) = {
317   .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",
327     [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
328     [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
329     [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
330     [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
331     [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-reassembly",
332   },
333
334   .format_buffer = format_ip4_header,
335   .format_trace = format_ip4_input_trace,
336 };
337
338 VLIB_REGISTER_NODE (ip4_input_no_checksum_node) = {
339   .name = "ip4-input-no-checksum",
340   .vector_size = sizeof (u32),
341
342   .sibling_of = "ip4-input",
343   .format_buffer = format_ip4_header,
344   .format_trace = format_ip4_input_trace,
345 };
346 /* *INDENT-ON* */
347
348 static clib_error_t *
349 ip4_init (vlib_main_t * vm)
350 {
351   clib_error_t *error;
352
353   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);
356
357   {
358     extern vlib_node_registration_t ip4_input_no_checksum_node;
359     pg_node_t *pn;
360     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
372   if ((error = vlib_call_init_function
373        (vm, ip4_source_and_port_range_check_init)))
374     return error;
375
376   /* 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
385 VLIB_INIT_FUNCTION (ip4_init);
386
387 static clib_error_t *
388 ip4_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
406 VLIB_MAIN_LOOP_ENTER_FUNCTION (ip4_main_loop_enter);
407
408 /*
409  * fd.io coding-style-patch-verification: ON
410  *
411  * Local Variables:
412  * eval: (c-set-style "gnu")
413  * End:
414  */