blob: 31b687d734758a6b6f7c3fad7e815842beaf9edf [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_forward.c: IP v4 forwarding
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/vnet.h>
41#include <vnet/ip/ip.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010042#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
43#include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/ppp/ppp.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010045#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
Dave Barachd7cb1b52016-12-09 09:52:16 -050046#include <vnet/api_errno.h> /* for API error numbers */
47#include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
48#include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
49#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/fib/ip4_fib.h>
51#include <vnet/dpo/load_balance.h>
52#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000053#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
Billy McFall0683c9c2016-10-13 08:27:31 -040055/**
56 * @file
57 * @brief IPv4 Forwarding.
58 *
59 * This file contains the source code for IPv4 forwarding.
60 */
61
Pierre Pfister0febaf12016-06-08 12:23:21 +010062void
63ip4_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050064 vlib_node_runtime_t * node,
65 vlib_frame_t * frame,
66 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010067
Ed Warnickecb9cada2015-12-08 15:45:58 -070068always_inline uword
69ip4_lookup_inline (vlib_main_t * vm,
70 vlib_node_runtime_t * node,
71 vlib_frame_t * frame,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010072 int lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -070073{
Dave Barachd7cb1b52016-12-09 09:52:16 -050074 ip4_main_t *im = &ip4_main;
75 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
76 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -050078 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 from = vlib_frame_vector_args (frame);
81 n_left_from = frame->n_vectors;
82 next = node->cached_next_index;
83
84 while (n_left_from > 0)
85 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050086 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070087
Dave Barach670909e2016-10-18 15:25:35 -040088 while (n_left_from >= 8 && n_left_to_next >= 4)
Dave Barachd7cb1b52016-12-09 09:52:16 -050089 {
90 vlib_buffer_t *p0, *p1, *p2, *p3;
91 ip4_header_t *ip0, *ip1, *ip2, *ip3;
92 __attribute__ ((unused)) tcp_header_t *tcp0, *tcp1, *tcp2, *tcp3;
93 ip_lookup_next_t next0, next1, next2, next3;
94 const load_balance_t *lb0, *lb1, *lb2, *lb3;
95 ip4_fib_mtrie_t *mtrie0, *mtrie1, *mtrie2, *mtrie3;
96 ip4_fib_mtrie_leaf_t leaf0, leaf1, leaf2, leaf3;
97 ip4_address_t *dst_addr0, *dst_addr1, *dst_addr2, *dst_addr3;
98 __attribute__ ((unused)) u32 pi0, fib_index0, lb_index0,
99 is_tcp_udp0;
100 __attribute__ ((unused)) u32 pi1, fib_index1, lb_index1,
101 is_tcp_udp1;
102 __attribute__ ((unused)) u32 pi2, fib_index2, lb_index2,
103 is_tcp_udp2;
104 __attribute__ ((unused)) u32 pi3, fib_index3, lb_index3,
105 is_tcp_udp3;
106 flow_hash_config_t flow_hash_config0, flow_hash_config1;
107 flow_hash_config_t flow_hash_config2, flow_hash_config3;
108 u32 hash_c0, hash_c1, hash_c2, hash_c3;
Dave Barach670909e2016-10-18 15:25:35 -0400109 const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110
Dave Barachd7cb1b52016-12-09 09:52:16 -0500111 /* Prefetch next iteration. */
112 {
113 vlib_buffer_t *p4, *p5, *p6, *p7;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114
Dave Barachd7cb1b52016-12-09 09:52:16 -0500115 p4 = vlib_get_buffer (vm, from[4]);
116 p5 = vlib_get_buffer (vm, from[5]);
117 p6 = vlib_get_buffer (vm, from[6]);
118 p7 = vlib_get_buffer (vm, from[7]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 vlib_prefetch_buffer_header (p4, LOAD);
121 vlib_prefetch_buffer_header (p5, LOAD);
122 vlib_prefetch_buffer_header (p6, LOAD);
123 vlib_prefetch_buffer_header (p7, LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124
Dave Barachd7cb1b52016-12-09 09:52:16 -0500125 CLIB_PREFETCH (p4->data, sizeof (ip0[0]), LOAD);
126 CLIB_PREFETCH (p5->data, sizeof (ip0[0]), LOAD);
127 CLIB_PREFETCH (p6->data, sizeof (ip0[0]), LOAD);
128 CLIB_PREFETCH (p7->data, sizeof (ip0[0]), LOAD);
129 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barachd7cb1b52016-12-09 09:52:16 -0500131 pi0 = to_next[0] = from[0];
132 pi1 = to_next[1] = from[1];
133 pi2 = to_next[2] = from[2];
134 pi3 = to_next[3] = from[3];
Dave Barach670909e2016-10-18 15:25:35 -0400135
Dave Barachd7cb1b52016-12-09 09:52:16 -0500136 from += 4;
137 to_next += 4;
138 n_left_to_next -= 4;
139 n_left_from -= 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141 p0 = vlib_get_buffer (vm, pi0);
142 p1 = vlib_get_buffer (vm, pi1);
143 p2 = vlib_get_buffer (vm, pi2);
144 p3 = vlib_get_buffer (vm, pi3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
Dave Barachd7cb1b52016-12-09 09:52:16 -0500146 ip0 = vlib_buffer_get_current (p0);
147 ip1 = vlib_buffer_get_current (p1);
148 ip2 = vlib_buffer_get_current (p2);
149 ip3 = vlib_buffer_get_current (p3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150
Dave Barachd7cb1b52016-12-09 09:52:16 -0500151 dst_addr0 = &ip0->dst_address;
152 dst_addr1 = &ip1->dst_address;
153 dst_addr2 = &ip2->dst_address;
154 dst_addr3 = &ip3->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200155
Dave Barachd7cb1b52016-12-09 09:52:16 -0500156 fib_index0 =
157 vec_elt (im->fib_index_by_sw_if_index,
158 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
159 fib_index1 =
160 vec_elt (im->fib_index_by_sw_if_index,
161 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
162 fib_index2 =
163 vec_elt (im->fib_index_by_sw_if_index,
164 vnet_buffer (p2)->sw_if_index[VLIB_RX]);
165 fib_index3 =
166 vec_elt (im->fib_index_by_sw_if_index,
167 vnet_buffer (p3)->sw_if_index[VLIB_RX]);
168 fib_index0 =
169 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
170 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
171 fib_index1 =
172 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
173 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
174 fib_index2 =
175 (vnet_buffer (p2)->sw_if_index[VLIB_TX] ==
176 (u32) ~ 0) ? fib_index2 : vnet_buffer (p2)->sw_if_index[VLIB_TX];
177 fib_index3 =
178 (vnet_buffer (p3)->sw_if_index[VLIB_TX] ==
179 (u32) ~ 0) ? fib_index3 : vnet_buffer (p3)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180
181
Dave Barachd7cb1b52016-12-09 09:52:16 -0500182 if (!lookup_for_responses_to_locally_received_packets)
183 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100184 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
185 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Dave Barach670909e2016-10-18 15:25:35 -0400186 mtrie2 = &ip4_fib_get (fib_index2)->mtrie;
187 mtrie3 = &ip4_fib_get (fib_index3)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 leaf0 = leaf1 = leaf2 = leaf3 = IP4_FIB_MTRIE_LEAF_ROOT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barachd7cb1b52016-12-09 09:52:16 -0500191 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
192 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 0);
193 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 0);
194 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 0);
195 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196
Dave Barachd7cb1b52016-12-09 09:52:16 -0500197 tcp0 = (void *) (ip0 + 1);
198 tcp1 = (void *) (ip1 + 1);
199 tcp2 = (void *) (ip2 + 1);
200 tcp3 = (void *) (ip3 + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201
Dave Barachd7cb1b52016-12-09 09:52:16 -0500202 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
203 || ip0->protocol == IP_PROTOCOL_UDP);
204 is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
205 || ip1->protocol == IP_PROTOCOL_UDP);
206 is_tcp_udp2 = (ip2->protocol == IP_PROTOCOL_TCP
207 || ip2->protocol == IP_PROTOCOL_UDP);
208 is_tcp_udp3 = (ip1->protocol == IP_PROTOCOL_TCP
209 || ip1->protocol == IP_PROTOCOL_UDP);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
Dave Barachd7cb1b52016-12-09 09:52:16 -0500211 if (!lookup_for_responses_to_locally_received_packets)
212 {
213 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
214 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 1);
215 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 1);
216 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 1);
217 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218
Dave Barachd7cb1b52016-12-09 09:52:16 -0500219 if (!lookup_for_responses_to_locally_received_packets)
220 {
221 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
222 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
223 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 2);
224 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 2);
225 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226
Dave Barachd7cb1b52016-12-09 09:52:16 -0500227 if (!lookup_for_responses_to_locally_received_packets)
228 {
229 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
230 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
231 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 3);
232 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 3);
233 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234
Dave Barachd7cb1b52016-12-09 09:52:16 -0500235 if (lookup_for_responses_to_locally_received_packets)
236 {
237 lb_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
238 lb_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
239 lb_index2 = vnet_buffer (p2)->ip.adj_index[VLIB_RX];
240 lb_index3 = vnet_buffer (p3)->ip.adj_index[VLIB_RX];
241 }
242 else
243 {
244 /* Handle default route. */
245 leaf0 =
246 (leaf0 ==
247 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
248 leaf1 =
249 (leaf1 ==
250 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
251 leaf2 =
252 (leaf2 ==
253 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie2->default_leaf : leaf2);
254 leaf3 =
255 (leaf3 ==
256 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie3->default_leaf : leaf3);
257 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
258 lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
259 lb_index2 = ip4_fib_mtrie_leaf_get_adj_index (leaf2);
260 lb_index3 = ip4_fib_mtrie_leaf_get_adj_index (leaf3);
261 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100263 lb0 = load_balance_get (lb_index0);
264 lb1 = load_balance_get (lb_index1);
Dave Barach670909e2016-10-18 15:25:35 -0400265 lb2 = load_balance_get (lb_index2);
266 lb3 = load_balance_get (lb_index3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Dave Barachd7cb1b52016-12-09 09:52:16 -0500268 /* Use flow hash to compute multipath adjacency. */
269 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
270 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
271 hash_c2 = vnet_buffer (p2)->ip.flow_hash = 0;
272 hash_c3 = vnet_buffer (p3)->ip.flow_hash = 0;
273 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
274 {
275 flow_hash_config0 = lb0->lb_hash_config;
276 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
277 ip4_compute_flow_hash (ip0, flow_hash_config0);
278 }
279 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
280 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281 flow_hash_config1 = lb1->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500282 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
283 ip4_compute_flow_hash (ip1, flow_hash_config1);
284 }
285 if (PREDICT_FALSE (lb2->lb_n_buckets > 1))
286 {
287 flow_hash_config2 = lb2->lb_hash_config;
288 hash_c2 = vnet_buffer (p2)->ip.flow_hash =
289 ip4_compute_flow_hash (ip2, flow_hash_config2);
290 }
291 if (PREDICT_FALSE (lb3->lb_n_buckets > 1))
292 {
Dave Barach670909e2016-10-18 15:25:35 -0400293 flow_hash_config3 = lb3->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500294 hash_c3 = vnet_buffer (p3)->ip.flow_hash =
295 ip4_compute_flow_hash (ip3, flow_hash_config3);
296 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298 ASSERT (lb0->lb_n_buckets > 0);
299 ASSERT (is_pow2 (lb0->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500300 ASSERT (lb1->lb_n_buckets > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100301 ASSERT (is_pow2 (lb1->lb_n_buckets));
Dave Barach670909e2016-10-18 15:25:35 -0400302 ASSERT (lb2->lb_n_buckets > 0);
303 ASSERT (is_pow2 (lb2->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304 ASSERT (lb3->lb_n_buckets > 0);
Dave Barach670909e2016-10-18 15:25:35 -0400305 ASSERT (is_pow2 (lb3->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
Dave Barachd7cb1b52016-12-09 09:52:16 -0500307 dpo0 = load_balance_get_bucket_i (lb0,
308 (hash_c0 &
309 (lb0->lb_n_buckets_minus_1)));
310 dpo1 = load_balance_get_bucket_i (lb1,
311 (hash_c1 &
312 (lb1->lb_n_buckets_minus_1)));
313 dpo2 = load_balance_get_bucket_i (lb2,
314 (hash_c2 &
315 (lb2->lb_n_buckets_minus_1)));
316 dpo3 = load_balance_get_bucket_i (lb3,
317 (hash_c3 &
318 (lb3->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100320 next0 = dpo0->dpoi_next_node;
321 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
322 next1 = dpo1->dpoi_next_node;
323 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Dave Barach670909e2016-10-18 15:25:35 -0400324 next2 = dpo2->dpoi_next_node;
325 vnet_buffer (p2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
326 next3 = dpo3->dpoi_next_node;
327 vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200328
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329 vlib_increment_combined_counter
330 (cm, cpu_index, lb_index0, 1,
331 vlib_buffer_length_in_chain (vm, p0)
332 + sizeof (ethernet_header_t));
333 vlib_increment_combined_counter
334 (cm, cpu_index, lb_index1, 1,
335 vlib_buffer_length_in_chain (vm, p1)
336 + sizeof (ethernet_header_t));
337 vlib_increment_combined_counter
338 (cm, cpu_index, lb_index2, 1,
339 vlib_buffer_length_in_chain (vm, p2)
340 + sizeof (ethernet_header_t));
341 vlib_increment_combined_counter
342 (cm, cpu_index, lb_index3, 1,
343 vlib_buffer_length_in_chain (vm, p3)
344 + sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345
Dave Barach670909e2016-10-18 15:25:35 -0400346 vlib_validate_buffer_enqueue_x4 (vm, node, next,
347 to_next, n_left_to_next,
348 pi0, pi1, pi2, pi3,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500349 next0, next1, next2, next3);
350 }
Dave Barach75fc8542016-10-11 16:16:02 -0400351
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 while (n_left_from > 0 && n_left_to_next > 0)
353 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500354 vlib_buffer_t *p0;
355 ip4_header_t *ip0;
356 __attribute__ ((unused)) tcp_header_t *tcp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 ip_lookup_next_t next0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100358 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500359 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 ip4_fib_mtrie_leaf_t leaf0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500361 ip4_address_t *dst_addr0;
362 __attribute__ ((unused)) u32 pi0, fib_index0, is_tcp_udp0, lbi0;
363 flow_hash_config_t flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100364 const dpo_id_t *dpo0;
365 u32 hash_c0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
367 pi0 = from[0];
368 to_next[0] = pi0;
369
370 p0 = vlib_get_buffer (vm, pi0);
371
372 ip0 = vlib_buffer_get_current (p0);
373
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100374 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200375
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 fib_index0 =
377 vec_elt (im->fib_index_by_sw_if_index,
378 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
379 fib_index0 =
380 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
381 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Dave Barachd7cb1b52016-12-09 09:52:16 -0500383 if (!lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500385 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386
387 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
388
Damjan Marionaca64c92016-04-13 09:48:56 +0200389 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 }
391
392 tcp0 = (void *) (ip0 + 1);
393
394 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
395 || ip0->protocol == IP_PROTOCOL_UDP);
396
Dave Barachd7cb1b52016-12-09 09:52:16 -0500397 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200398 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399
Dave Barachd7cb1b52016-12-09 09:52:16 -0500400 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200401 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402
Dave Barachd7cb1b52016-12-09 09:52:16 -0500403 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200404 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405
406 if (lookup_for_responses_to_locally_received_packets)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100407 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408 else
409 {
410 /* Handle default route. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500411 leaf0 =
412 (leaf0 ==
413 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100414 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415 }
416
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418
419 /* Use flow hash to compute multipath adjacency. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500420 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
421 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
422 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100423 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424
Dave Barachd7cb1b52016-12-09 09:52:16 -0500425 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
426 ip4_compute_flow_hash (ip0, flow_hash_config0);
427 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100429 ASSERT (lb0->lb_n_buckets > 0);
430 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431
Dave Barachd7cb1b52016-12-09 09:52:16 -0500432 dpo0 = load_balance_get_bucket_i (lb0,
433 (hash_c0 &
434 (lb0->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100436 next0 = dpo0->dpoi_next_node;
437 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200438
Dave Barach75fc8542016-10-11 16:16:02 -0400439 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500440 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700441
442 from += 1;
443 to_next += 1;
444 n_left_to_next -= 1;
445 n_left_from -= 1;
446
447 if (PREDICT_FALSE (next0 != next))
448 {
449 n_left_to_next += 1;
450 vlib_put_next_frame (vm, node, next, n_left_to_next);
451 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453 to_next[0] = pi0;
454 to_next += 1;
455 n_left_to_next -= 1;
456 }
457 }
458
459 vlib_put_next_frame (vm, node, next, n_left_to_next);
460 }
461
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100462 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500463 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100464
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465 return frame->n_vectors;
466}
467
Chris Luke8e5b0412016-07-26 13:06:10 -0400468/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -0400469 @node ip4-lookup
470
471 This is the main IPv4 lookup dispatch node.
472
473 @param vm vlib_main_t corresponding to the current thread
474 @param node vlib_node_runtime_t
475 @param frame vlib_frame_t whose contents should be dispatched
476
477 @par Graph mechanics: buffer metadata, next index usage
478
479 @em Uses:
480 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
481 - Indicates the @c sw_if_index value of the interface that the
482 packet was received on.
483 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
484 - When the value is @c ~0 then the node performs a longest prefix
485 match (LPM) for the packet destination address in the FIB attached
486 to the receive interface.
487 - Otherwise perform LPM for the packet destination address in the
488 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
489 value (0, 1, ...) and not a VRF id.
490
491 @em Sets:
492 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
493 - The lookup result adjacency index.
494
495 <em>Next Index:</em>
496 - Dispatches the packet to the node index found in
497 ip_adjacency_t @c adj->lookup_next_index
498 (where @c adj is the lookup result adjacency).
499*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500static uword
501ip4_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500502 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503{
Damjan Marionaca64c92016-04-13 09:48:56 +0200504 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505 /* lookup_for_responses_to_locally_received_packets */
506 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507
508}
509
Dave Barachd7cb1b52016-12-09 09:52:16 -0500510static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100511
Dave Barachd7cb1b52016-12-09 09:52:16 -0500512VLIB_REGISTER_NODE (ip4_lookup_node) =
513{
514.function = ip4_lookup,.name = "ip4-lookup",.vector_size =
515 sizeof (u32),.format_trace = format_ip4_lookup_trace,.n_next_nodes =
516 IP_LOOKUP_N_NEXT,.next_nodes = IP4_LOOKUP_NEXT_NODES,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100517
Dave Barachd7cb1b52016-12-09 09:52:16 -0500518VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100519
520always_inline uword
521ip4_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500522 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500524 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
525 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100526 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500527 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100529 from = vlib_frame_vector_args (frame);
530 n_left_from = frame->n_vectors;
531 next = node->cached_next_index;
532
533 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100535
536 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500538 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100539
Dave Barach75fc8542016-10-11 16:16:02 -0400540
Neale Ranns2be95c12016-11-19 13:50:04 +0000541 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500542 {
543 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000544 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500545 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000546 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
547 const ip4_header_t *ip0, *ip1;
548 const dpo_id_t *dpo0, *dpo1;
549
Dave Barachd7cb1b52016-12-09 09:52:16 -0500550 /* Prefetch next iteration. */
551 {
552 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000553
554 p2 = vlib_get_buffer (vm, from[2]);
555 p3 = vlib_get_buffer (vm, from[3]);
556
557 vlib_prefetch_buffer_header (p2, STORE);
558 vlib_prefetch_buffer_header (p3, STORE);
559
560 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
561 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500562 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000563
564 pi0 = to_next[0] = from[0];
565 pi1 = to_next[1] = from[1];
566
567 from += 2;
568 n_left_from -= 2;
569 to_next += 2;
570 n_left_to_next -= 2;
571
572 p0 = vlib_get_buffer (vm, pi0);
573 p1 = vlib_get_buffer (vm, pi1);
574
575 ip0 = vlib_buffer_get_current (p0);
576 ip1 = vlib_buffer_get_current (p1);
577 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
578 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
579
Dave Barachd7cb1b52016-12-09 09:52:16 -0500580 lb0 = load_balance_get (lbi0);
581 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000582
Dave Barachd7cb1b52016-12-09 09:52:16 -0500583 /*
584 * this node is for via FIBs we can re-use the hash value from the
585 * to node if present.
586 * We don't want to use the same hash value at each level in the recursion
587 * graph as that would lead to polarisation
588 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000589 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000590
Dave Barachd7cb1b52016-12-09 09:52:16 -0500591 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
592 {
593 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
594 {
595 hc0 = vnet_buffer (p0)->ip.flow_hash =
596 vnet_buffer (p0)->ip.flow_hash >> 1;
597 }
598 else
599 {
600 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000601 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500602 }
603 }
604 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
605 {
606 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
607 {
608 hc1 = vnet_buffer (p1)->ip.flow_hash =
609 vnet_buffer (p1)->ip.flow_hash >> 1;
610 }
611 else
612 {
613 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000614 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500615 }
616 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000617
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 dpo0 =
619 load_balance_get_bucket_i (lb0,
620 hc0 & (lb0->lb_n_buckets_minus_1));
621 dpo1 =
622 load_balance_get_bucket_i (lb1,
623 hc1 & (lb1->lb_n_buckets_minus_1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000624
625 next0 = dpo0->dpoi_next_node;
626 next1 = dpo1->dpoi_next_node;
627
628 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
629 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
630
631 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500632 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000633 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000635
636 vlib_validate_buffer_enqueue_x2 (vm, node, next,
637 to_next, n_left_to_next,
638 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000640
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 while (n_left_from > 0 && n_left_to_next > 0)
642 {
643 ip_lookup_next_t next0;
644 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500645 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100646 u32 pi0, lbi0, hc0;
647 const ip4_header_t *ip0;
648 const dpo_id_t *dpo0;
649
650 pi0 = from[0];
651 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000652 from += 1;
653 to_next += 1;
654 n_left_to_next -= 1;
655 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656
657 p0 = vlib_get_buffer (vm, pi0);
658
659 ip0 = vlib_buffer_get_current (p0);
660 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
661
Dave Barachd7cb1b52016-12-09 09:52:16 -0500662 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100663
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000664 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500665 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
666 {
667 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
668 {
669 hc0 = vnet_buffer (p0)->ip.flow_hash =
670 vnet_buffer (p0)->ip.flow_hash >> 1;
671 }
672 else
673 {
674 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000675 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500676 }
677 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000678
Dave Barachd7cb1b52016-12-09 09:52:16 -0500679 dpo0 =
680 load_balance_get_bucket_i (lb0,
681 hc0 & (lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100682
683 next0 = dpo0->dpoi_next_node;
684 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
685
Dave Barach75fc8542016-10-11 16:16:02 -0400686 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100688
Neale Ranns2be95c12016-11-19 13:50:04 +0000689 vlib_validate_buffer_enqueue_x1 (vm, node, next,
690 to_next, n_left_to_next,
691 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100692 }
693
694 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 }
696
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 return frame->n_vectors;
698}
699
Dave Barachd7cb1b52016-12-09 09:52:16 -0500700VLIB_REGISTER_NODE (ip4_load_balance_node) =
701{
702.function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
703 sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
704 format_ip4_lookup_trace,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100707
708/* get first interface address */
709ip4_address_t *
710ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500711 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100712{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500713 ip_lookup_main_t *lm = &im->lookup_main;
714 ip_interface_address_t *ia = 0;
715 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100716
Neale Ranns32e1c012016-11-22 17:07:28 +0000717 /* *INDENT-OFF* */
718 foreach_ip_interface_address
719 (lm, ia, sw_if_index,
720 1 /* honor unnumbered */ ,
721 ({
722 ip4_address_t * a =
723 ip_interface_address_get_address (lm, ia);
724 result = a;
725 break;
726 }));
727 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100728 if (result_ia)
729 *result_ia = result ? ia : 0;
730 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731}
732
733static void
734ip4_add_interface_routes (u32 sw_if_index,
735 ip4_main_t * im, u32 fib_index,
736 ip_interface_address_t * a)
737{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500738 ip_lookup_main_t *lm = &im->lookup_main;
739 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100740 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500741 .fp_len = a->address_length,
742 .fp_proto = FIB_PROTOCOL_IP4,
743 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100744 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
746 a->neighbor_probe_adj_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100748 if (pfx.fp_len < 32)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500749 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100750 fib_node_index_t fei;
751
Neale Ranns32e1c012016-11-22 17:07:28 +0000752 fei = fib_table_entry_update_one_path (fib_index, &pfx,
753 FIB_SOURCE_INTERFACE,
754 (FIB_ENTRY_FLAG_CONNECTED |
755 FIB_ENTRY_FLAG_ATTACHED),
756 FIB_PROTOCOL_IP4,
757 /* No next-hop address */
758 NULL,
759 sw_if_index,
760 // invalid FIB index
761 ~0,
762 1,
763 // no out-label stack
764 NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500765 FIB_ROUTE_PATH_FLAG_NONE);
766 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
767 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100768
769 pfx.fp_len = 32;
770
771 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500772 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100773 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500774 lm->classify_table_index_by_sw_if_index[sw_if_index];
775 if (classify_table_index != (u32) ~ 0)
776 {
777 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100778
Dave Barachd7cb1b52016-12-09 09:52:16 -0500779 dpo_set (&dpo,
780 DPO_CLASSIFY,
781 DPO_PROTO_IP4,
782 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100783
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 fib_table_entry_special_dpo_add (fib_index,
785 &pfx,
786 FIB_SOURCE_CLASSIFY,
787 FIB_ENTRY_FLAG_NONE, &dpo);
788 dpo_reset (&dpo);
789 }
790 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100791
Neale Ranns32e1c012016-11-22 17:07:28 +0000792 fib_table_entry_update_one_path (fib_index, &pfx,
793 FIB_SOURCE_INTERFACE,
794 (FIB_ENTRY_FLAG_CONNECTED |
795 FIB_ENTRY_FLAG_LOCAL),
796 FIB_PROTOCOL_IP4,
797 &pfx.fp_addr,
798 sw_if_index,
799 // invalid FIB index
800 ~0,
801 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500802 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803}
804
805static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100806ip4_del_interface_routes (ip4_main_t * im,
807 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500808 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500810 fib_prefix_t pfx = {
811 .fp_len = address_length,
812 .fp_proto = FIB_PROTOCOL_IP4,
813 .fp_addr.ip4 = *address,
814 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
Dave Barachd7cb1b52016-12-09 09:52:16 -0500816 if (pfx.fp_len < 32)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100817 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500818 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100819 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820
Dave Barachd7cb1b52016-12-09 09:52:16 -0500821 pfx.fp_len = 32;
822 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823}
824
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100825void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500826ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100827{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500828 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100830 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
831
832 /*
833 * enable/disable only on the 1<->0 transition
834 */
835 if (is_enable)
836 {
837 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500838 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100839 }
840 else
841 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500842 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100843 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500844 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100845 }
Damjan Marion4d489932016-12-09 03:21:27 -0800846 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
847 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100848
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100849
Neale Ranns32e1c012016-11-22 17:07:28 +0000850 vnet_feature_enable_disable ("ip4-multicast",
851 "ip4-mfib-forward-lookup",
852 sw_if_index, is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100853}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855static clib_error_t *
856ip4_add_del_interface_address_internal (vlib_main_t * vm,
857 u32 sw_if_index,
858 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500859 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700860{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500861 vnet_main_t *vnm = vnet_get_main ();
862 ip4_main_t *im = &ip4_main;
863 ip_lookup_main_t *lm = &im->lookup_main;
864 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500866 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867
868 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
869 ip4_addr_fib_init (&ip4_af, address,
870 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
871 vec_add1 (addr_fib, ip4_af);
872
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100873 /* FIXME-LATER
874 * there is no support for adj-fib handling in the presence of overlapping
875 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
876 * most routers do.
877 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000878 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500879 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100881 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500882 with an existing address. */
883 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000884 foreach_ip_interface_address
885 (&im->lookup_main, ia, sw_if_index,
886 0 /* honor unnumbered */ ,
887 ({
888 ip4_address_t * x =
889 ip_interface_address_get_address
890 (&im->lookup_main, ia);
891 if (ip4_destination_matches_route
892 (im, address, x, ia->address_length) ||
893 ip4_destination_matches_route (im,
894 x,
895 address,
896 address_length))
897 return
898 clib_error_create
899 ("failed to add %U which conflicts with %U for interface %U",
900 format_ip4_address_and_length, address,
901 address_length,
902 format_ip4_address_and_length, x,
903 ia->address_length,
904 format_vnet_sw_if_index_name, vnm,
905 sw_if_index);
906 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000908 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700909
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 elts_before = pool_elts (lm->if_address_pool);
911
912 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500913 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700914 if (error)
915 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100918
919 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500920 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100921 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922 ip4_add_interface_routes (sw_if_index,
923 im, ip4_af.fib_index,
924 pool_elt_at_index
925 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926
927 /* If pool did not grow/shrink: add duplicate address. */
928 if (elts_before != pool_elts (lm->if_address_pool))
929 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500930 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 vec_foreach (cb, im->add_del_interface_address_callbacks)
932 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500933 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934 }
935
Dave Barachd7cb1b52016-12-09 09:52:16 -0500936done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937 vec_free (addr_fib);
938 return error;
939}
940
941clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000942ip4_add_del_interface_address (vlib_main_t * vm,
943 u32 sw_if_index,
944 ip4_address_t * address,
945 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946{
947 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500948 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949}
950
Dave Barachd6534602016-06-14 18:38:02 -0400951/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100953VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
954{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500955 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100956 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -0800957 .end_node = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100958 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
959};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100960
Dave Barachd7cb1b52016-12-09 09:52:16 -0500961VNET_FEATURE_INIT (ip4_flow_classify, static) =
962{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100963 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700964 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100965 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700966};
967
Dave Barachd7cb1b52016-12-09 09:52:16 -0500968VNET_FEATURE_INIT (ip4_inacl, static) =
969{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100970 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400971 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100972 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400973};
974
Dave Barachd7cb1b52016-12-09 09:52:16 -0500975VNET_FEATURE_INIT (ip4_source_check_1, static) =
976{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100977 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400978 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100979 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400980};
981
Dave Barachd7cb1b52016-12-09 09:52:16 -0500982VNET_FEATURE_INIT (ip4_source_check_2, static) =
983{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100984 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400985 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100986 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400987};
988
Dave Barachd7cb1b52016-12-09 09:52:16 -0500989VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
990{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100991 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400992 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100993 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400994};
995
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996VNET_FEATURE_INIT (ip4_policer_classify, static) =
997{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100998 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700999 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001001};
1002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003VNET_FEATURE_INIT (ip4_ipsec, static) =
1004{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001005 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001006 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001007 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -04001008};
1009
Dave Barachd7cb1b52016-12-09 09:52:16 -05001010VNET_FEATURE_INIT (ip4_vpath, static) =
1011{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001012 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001013 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -05001014 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1015};
1016
Dave Barachd7cb1b52016-12-09 09:52:16 -05001017VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1018{
John Lo37682e12016-11-30 12:51:39 -05001019 .arc_name = "ip4-unicast",
1020 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001021 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001022};
1023
Dave Barachd7cb1b52016-12-09 09:52:16 -05001024VNET_FEATURE_INIT (ip4_lookup, static) =
1025{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001026 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001027 .node_name = "ip4-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001028 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001029};
1030
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031VNET_FEATURE_INIT (ip4_drop, static) =
1032{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001033 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001034 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 .runs_before = 0, /* not before any other features */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001036};
1037
1038
Dave Barachd6534602016-06-14 18:38:02 -04001039/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001040VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1041{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001043 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -08001044 .end_node = "ip4-lookup-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001045 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1046};
1047
Dave Barachd7cb1b52016-12-09 09:52:16 -05001048VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1049{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001050 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001051 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001052 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001053};
1054
Dave Barachd7cb1b52016-12-09 09:52:16 -05001055VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1056{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001057 .arc_name = "ip4-multicast",
Neale Ranns32e1c012016-11-22 17:07:28 +00001058 .node_name = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001059 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001060};
1061
Dave Barachd7cb1b52016-12-09 09:52:16 -05001062VNET_FEATURE_INIT (ip4_mc_drop, static) =
1063{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001064 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001065 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001066 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001067};
Dave Barach5331c722016-08-17 11:54:30 -04001068
1069/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001070VNET_FEATURE_ARC_INIT (ip4_output, static) =
1071{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001072 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001073 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion892e0762016-12-09 18:52:05 +01001074 .end_node = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001075 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1076};
Dave Barach5331c722016-08-17 11:54:30 -04001077
Dave Barachd7cb1b52016-12-09 09:52:16 -05001078VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1079{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001080 .arc_name = "ip4-output",
1081 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001082 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1083};
1084
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1086{
Matus Fabian08a6f012016-11-15 06:08:51 -08001087 .arc_name = "ip4-output",
1088 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001089 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001090};
1091
1092/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001093VNET_FEATURE_INIT (ip4_interface_output, static) =
1094{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001095 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001096 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001097 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001098};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001099/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001100
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001102ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001104 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001106 /* Fill in lookup tables with default table (0). */
1107 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001108 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001109
Damjan Marion8b3191e2016-11-09 19:54:20 +01001110 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1111 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112
Damjan Marion8b3191e2016-11-09 19:54:20 +01001113 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1114 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 return /* no error */ 0;
1117}
1118
1119VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1120
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121/* Global IP4 main. */
1122ip4_main_t ip4_main;
1123
1124clib_error_t *
1125ip4_lookup_init (vlib_main_t * vm)
1126{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001127 ip4_main_t *im = &ip4_main;
1128 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129 uword i;
1130
Damjan Marion8b3191e2016-11-09 19:54:20 +01001131 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1132 return error;
1133
Ed Warnickecb9cada2015-12-08 15:45:58 -07001134 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1135 {
1136 u32 m;
1137
1138 if (i < 32)
1139 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001140 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141 m = ~0;
1142 im->fib_masks[i] = clib_host_to_net_u32 (m);
1143 }
1144
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1146
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001147 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001149 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001150
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001152 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 pn = pg_get_node (ip4_lookup_node.index);
1154 pn->unformat_edit = unformat_pg_ip4_header;
1155 }
1156
1157 {
1158 ethernet_arp_header_t h;
1159
1160 memset (&h, 0, sizeof (h));
1161
1162 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163 memset (h.ip4_over_ethernet[1].ethernet, 0,
1164 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165
1166#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1167#define _8(f,v) h.f = v;
1168 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1169 _16 (l3_type, ETHERNET_TYPE_IP4);
1170 _8 (n_l2_address_bytes, 6);
1171 _8 (n_l3_address_bytes, 4);
1172 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1173#undef _16
1174#undef _8
1175
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177 /* data */ &h,
1178 sizeof (h),
1179 /* alloc chunk size */ 8,
1180 "ip4 arp");
1181 }
1182
Dave Barach203c6322016-06-26 10:29:03 -04001183 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184}
1185
1186VLIB_INIT_FUNCTION (ip4_lookup_init);
1187
Dave Barachd7cb1b52016-12-09 09:52:16 -05001188typedef struct
1189{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001191 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192 u32 flow_hash;
1193 u32 fib_index;
1194
1195 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001196 u8 packet_data[64 - 1 * sizeof (u32)];
1197}
1198ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
Dave Barachd7cb1b52016-12-09 09:52:16 -05001200u8 *
1201format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202{
1203 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1204 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001205 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001206 uword indent = format_get_indent (s);
1207 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001208 format_white_space, indent,
1209 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001210 return s;
1211}
1212
Dave Barachd7cb1b52016-12-09 09:52:16 -05001213static u8 *
1214format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001215{
1216 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1217 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001218 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 uword indent = format_get_indent (s);
1220
John Loac8146c2016-09-27 17:44:02 -04001221 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001223 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001224 format_white_space, indent,
1225 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001226 return s;
1227}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228
Dave Barachd7cb1b52016-12-09 09:52:16 -05001229static u8 *
1230format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001231{
1232 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1233 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001234 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1235 vnet_main_t *vnm = vnet_get_main ();
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001236 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237
Vengada Govindanf1544482016-09-28 02:45:57 -07001238 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001239 t->fib_index, t->dpo_index, format_ip_adjacency,
1240 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001241 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001242 format_white_space, indent,
1243 format_ip_adjacency_packet_data,
1244 vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245 return s;
1246}
1247
1248/* Common trace function for all ip4-forward next nodes. */
1249void
1250ip4_forward_next_trace (vlib_main_t * vm,
1251 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001252 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001254 u32 *from, n_left;
1255 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256
1257 n_left = frame->n_vectors;
1258 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001259
Ed Warnickecb9cada2015-12-08 15:45:58 -07001260 while (n_left >= 4)
1261 {
1262 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001263 vlib_buffer_t *b0, *b1;
1264 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001265
1266 /* Prefetch next iteration. */
1267 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1268 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1269
1270 bi0 = from[0];
1271 bi1 = from[1];
1272
1273 b0 = vlib_get_buffer (vm, bi0);
1274 b1 = vlib_get_buffer (vm, bi1);
1275
1276 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1277 {
1278 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001279 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001280 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001281 t0->fib_index =
1282 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1283 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1284 vec_elt (im->fib_index_by_sw_if_index,
1285 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001286
Damjan Marionf1213b82016-03-13 02:22:06 +01001287 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001288 vlib_buffer_get_current (b0),
1289 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290 }
1291 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1292 {
1293 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001294 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001296 t1->fib_index =
1297 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1298 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1299 vec_elt (im->fib_index_by_sw_if_index,
1300 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1301 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1302 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303 }
1304 from += 2;
1305 n_left -= 2;
1306 }
1307
1308 while (n_left >= 1)
1309 {
1310 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001311 vlib_buffer_t *b0;
1312 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313
1314 bi0 = from[0];
1315
1316 b0 = vlib_get_buffer (vm, bi0);
1317
1318 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1319 {
1320 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001321 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001322 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001323 t0->fib_index =
1324 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1325 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1326 vec_elt (im->fib_index_by_sw_if_index,
1327 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1328 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1329 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001330 }
1331 from += 1;
1332 n_left -= 1;
1333 }
1334}
1335
1336static uword
1337ip4_drop_or_punt (vlib_main_t * vm,
1338 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001339 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001341 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342 uword n_packets = frame->n_vectors;
1343
Dave Barachd7cb1b52016-12-09 09:52:16 -05001344 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001345 /* stride */ 1,
1346 n_packets,
1347 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001348 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349
1350 if (node->flags & VLIB_NODE_FLAG_TRACE)
1351 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1352
1353 return n_packets;
1354}
1355
1356static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001357ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1358{
1359 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1360}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001361
1362static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001363ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1364{
1365 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1366}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367
Neale Ranns32e1c012016-11-22 17:07:28 +00001368/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001369VLIB_REGISTER_NODE (ip4_drop_node, static) =
1370{
Neale Ranns32e1c012016-11-22 17:07:28 +00001371 .function = ip4_drop,.
1372 name = "ip4-drop",
1373 .vector_size = sizeof (u32),
1374 .format_trace = format_ip4_forward_next_trace,
1375 .n_next_nodes = 1,
1376 .next_nodes = {
1377 [0] = "error-drop",
1378 },
1379};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380
Dave Barachd7cb1b52016-12-09 09:52:16 -05001381VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382
Dave Barachd7cb1b52016-12-09 09:52:16 -05001383VLIB_REGISTER_NODE (ip4_punt_node, static) =
1384{
Neale Ranns32e1c012016-11-22 17:07:28 +00001385 .function = ip4_punt,
1386 .name = "ip4-punt",
1387 .vector_size = sizeof (u32),
1388 .format_trace = format_ip4_forward_next_trace,
1389 .n_next_nodes = 1,
1390 .next_nodes = {
1391 [0] = "error-punt",
1392 },
1393};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394
Dave Barachd7cb1b52016-12-09 09:52:16 -05001395VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Neale Ranns32e1c012016-11-22 17:07:28 +00001396/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02001397
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398/* Compute TCP/UDP/ICMP4 checksum in software. */
1399u16
1400ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1401 ip4_header_t * ip0)
1402{
1403 ip_csum_t sum0;
1404 u32 ip_header_length, payload_length_host_byte_order;
1405 u32 n_this_buffer, n_bytes_left;
1406 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001407 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001408
Ed Warnickecb9cada2015-12-08 15:45:58 -07001409 /* Initialize checksum with ip header. */
1410 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001411 payload_length_host_byte_order =
1412 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1413 sum0 =
1414 clib_host_to_net_u32 (payload_length_host_byte_order +
1415 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416
1417 if (BITS (uword) == 32)
1418 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001419 sum0 =
1420 ip_csum_with_carry (sum0,
1421 clib_mem_unaligned (&ip0->src_address, u32));
1422 sum0 =
1423 ip_csum_with_carry (sum0,
1424 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425 }
1426 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001427 sum0 =
1428 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429
1430 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1431 data_this_buffer = (void *) ip0 + ip_header_length;
1432 if (n_this_buffer + ip_header_length > p0->current_length)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001433 n_this_buffer =
1434 p0->current_length >
1435 ip_header_length ? p0->current_length - ip_header_length : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436 while (1)
1437 {
1438 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1439 n_bytes_left -= n_this_buffer;
1440 if (n_bytes_left == 0)
1441 break;
1442
1443 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1444 p0 = vlib_get_buffer (vm, p0->next_buffer);
1445 data_this_buffer = vlib_buffer_get_current (p0);
1446 n_this_buffer = p0->current_length;
1447 }
1448
Dave Barachd7cb1b52016-12-09 09:52:16 -05001449 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450
1451 return sum16;
1452}
1453
John Lo37682e12016-11-30 12:51:39 -05001454u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001455ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1456{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001457 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1458 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001459 u16 sum16;
1460
1461 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1462 || ip0->protocol == IP_PROTOCOL_UDP);
1463
1464 udp0 = (void *) (ip0 + 1);
1465 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1466 {
1467 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1468 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1469 return p0->flags;
1470 }
1471
1472 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1473
1474 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1475 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1476
1477 return p0->flags;
1478}
1479
Dave Barach68b0fb02017-02-28 15:15:56 -05001480/* *INDENT-OFF* */
1481VNET_FEATURE_ARC_INIT (ip4_local) =
1482{
1483 .arc_name = "ip4-local",
1484 .start_nodes = VNET_FEATURES ("ip4-local"),
1485};
1486/* *INDENT-ON* */
1487
1488static inline uword
1489ip4_local_inline (vlib_main_t * vm,
1490 vlib_node_runtime_t * node,
1491 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001493 ip4_main_t *im = &ip4_main;
1494 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001495 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001496 u32 *from, *to_next, n_left_from, n_left_to_next;
1497 vlib_node_runtime_t *error_node =
1498 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001499 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001500
1501 from = vlib_frame_vector_args (frame);
1502 n_left_from = frame->n_vectors;
1503 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001504
Ed Warnickecb9cada2015-12-08 15:45:58 -07001505 if (node->flags & VLIB_NODE_FLAG_TRACE)
1506 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1507
1508 while (n_left_from > 0)
1509 {
1510 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1511
1512 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001513 {
1514 vlib_buffer_t *p0, *p1;
1515 ip4_header_t *ip0, *ip1;
1516 udp_header_t *udp0, *udp1;
1517 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1518 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1519 const dpo_id_t *dpo0, *dpo1;
1520 const load_balance_t *lb0, *lb1;
1521 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1522 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1523 i32 len_diff0, len_diff1;
1524 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1525 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001526 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001527
Dave Barachd7cb1b52016-12-09 09:52:16 -05001528 pi0 = to_next[0] = from[0];
1529 pi1 = to_next[1] = from[1];
1530 from += 2;
1531 n_left_from -= 2;
1532 to_next += 2;
1533 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001534
Dave Barach68b0fb02017-02-28 15:15:56 -05001535 next0 = next1 = IP_LOCAL_NEXT_DROP;
1536
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537 p0 = vlib_get_buffer (vm, pi0);
1538 p1 = vlib_get_buffer (vm, pi1);
1539
1540 ip0 = vlib_buffer_get_current (p0);
1541 ip1 = vlib_buffer_get_current (p1);
1542
Dave Barachd7cb1b52016-12-09 09:52:16 -05001543 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1544 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001545
Dave Barach68b0fb02017-02-28 15:15:56 -05001546 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1547 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1548
1549 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1550 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1551
1552 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001553 fib_index0 =
1554 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1555 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001556
Dave Barach68b0fb02017-02-28 15:15:56 -05001557 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001558 fib_index1 =
1559 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1560 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001561
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001562 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1563 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001564
1565 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1566
Dave Barachd7cb1b52016-12-09 09:52:16 -05001567 leaf0 =
1568 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1569 leaf1 =
1570 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001571
John Lo3419d0b2016-06-02 09:28:37 -04001572 /* Treat IP frag packets as "experimental" protocol for now
1573 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001574 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1575 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001576
1577 if (head_of_feature_arc == 0)
1578 {
1579 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1580 goto skip_checks;
1581 }
1582
Ed Warnickecb9cada2015-12-08 15:45:58 -07001583 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1584 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1585 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1586 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1587
1588 flags0 = p0->flags;
1589 flags1 = p1->flags;
1590
1591 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1592 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1593
1594 udp0 = ip4_next_header (ip0);
1595 udp1 = ip4_next_header (ip1);
1596
1597 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1598 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1599 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1600
Dave Barachd7cb1b52016-12-09 09:52:16 -05001601 leaf0 =
1602 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1603 leaf1 =
1604 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605
1606 /* Verify UDP length. */
1607 ip_len0 = clib_net_to_host_u16 (ip0->length);
1608 ip_len1 = clib_net_to_host_u16 (ip1->length);
1609 udp_len0 = clib_net_to_host_u16 (udp0->length);
1610 udp_len1 = clib_net_to_host_u16 (udp1->length);
1611
1612 len_diff0 = ip_len0 - udp_len0;
1613 len_diff1 = ip_len1 - udp_len1;
1614
1615 len_diff0 = is_udp0 ? len_diff0 : 0;
1616 len_diff1 = is_udp1 ? len_diff1 : 0;
1617
Dave Barachd7cb1b52016-12-09 09:52:16 -05001618 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1619 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620 {
1621 if (is_tcp_udp0)
1622 {
1623 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001624 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1626 good_tcp_udp0 =
1627 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1628 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1629 }
1630 if (is_tcp_udp1)
1631 {
1632 if (is_tcp_udp1
Dave Barachd7cb1b52016-12-09 09:52:16 -05001633 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001634 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1635 good_tcp_udp1 =
1636 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1637 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1638 }
1639 }
1640
1641 good_tcp_udp0 &= len_diff0 >= 0;
1642 good_tcp_udp1 &= len_diff1 >= 0;
1643
Dave Barachd7cb1b52016-12-09 09:52:16 -05001644 leaf0 =
1645 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1646 leaf1 =
1647 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648
1649 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1650
1651 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1652 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1653
1654 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001655 error0 = (is_tcp_udp0 && !good_tcp_udp0
1656 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1657 error1 = (is_tcp_udp1 && !good_tcp_udp1
1658 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659
Dave Barachd7cb1b52016-12-09 09:52:16 -05001660 leaf0 =
1661 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1662 leaf1 =
1663 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
1664 leaf0 =
1665 (leaf0 ==
1666 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1667 leaf1 =
1668 (leaf1 ==
1669 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001670
Dave Barachd7cb1b52016-12-09 09:52:16 -05001671 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1672 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1673 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001674
Dave Barachd7cb1b52016-12-09 09:52:16 -05001675 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1676 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1677 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001678
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679 lb0 = load_balance_get (lbi0);
1680 lb1 = load_balance_get (lbi1);
1681 dpo0 = load_balance_get_bucket_i (lb0, 0);
1682 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001683
Dave Barach75fc8542016-10-11 16:16:02 -04001684 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001685 * Must have a route to source otherwise we drop the packet.
1686 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001687 *
1688 * The checks are:
1689 * - the source is a recieve => it's from us => bogus, do this
1690 * first since it sets a different error code.
1691 * - uRPF check for any route to source - accept if passes.
1692 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001693 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001694 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001695 dpo0->dpoi_type == DPO_RECEIVE) ?
1696 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1697 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1698 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001699 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001700 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001701 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 dpo1->dpoi_type == DPO_RECEIVE) ?
1703 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1704 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1705 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001706 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001707 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708
1709 next0 = lm->local_next_by_ip_protocol[proto0];
1710 next1 = lm->local_next_by_ip_protocol[proto1];
1711
Dave Barach68b0fb02017-02-28 15:15:56 -05001712 skip_checks:
Dave Barachd7cb1b52016-12-09 09:52:16 -05001713 next0 =
1714 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1715 next1 =
1716 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001717
1718 p0->error = error0 ? error_node->errors[error0] : 0;
1719 p1->error = error1 ? error_node->errors[error1] : 0;
1720
Dave Barach68b0fb02017-02-28 15:15:56 -05001721 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001722 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001723 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1724 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1725 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1726 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001727 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001728
1729 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1730 n_left_to_next, pi0, pi1,
1731 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001732 }
1733
1734 while (n_left_from > 0 && n_left_to_next > 0)
1735 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001736 vlib_buffer_t *p0;
1737 ip4_header_t *ip0;
1738 udp_header_t *udp0;
1739 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001740 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001741 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742 i32 len_diff0;
1743 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001744 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001745 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001746 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001747
Ed Warnickecb9cada2015-12-08 15:45:58 -07001748 pi0 = to_next[0] = from[0];
1749 from += 1;
1750 n_left_from -= 1;
1751 to_next += 1;
1752 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001753
Dave Barach68b0fb02017-02-28 15:15:56 -05001754 next0 = IP_LOCAL_NEXT_DROP;
1755
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756 p0 = vlib_get_buffer (vm, pi0);
1757
1758 ip0 = vlib_buffer_get_current (p0);
1759
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001761
Dave Barach68b0fb02017-02-28 15:15:56 -05001762 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1763
1764 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1765
Neale Ranns32e1c012016-11-22 17:07:28 +00001766 fib_index0 =
1767 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1768 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001770 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001771
1772 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
1773
Dave Barachd7cb1b52016-12-09 09:52:16 -05001774 leaf0 =
1775 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001776
John Lo3419d0b2016-06-02 09:28:37 -04001777 /* Treat IP frag packets as "experimental" protocol for now
1778 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001780
1781 if (head_of_feature_arc == 0)
1782 {
1783 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1784 goto skip_check;
1785 }
1786
Ed Warnickecb9cada2015-12-08 15:45:58 -07001787 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1788 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1789
1790 flags0 = p0->flags;
1791
1792 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1793
1794 udp0 = ip4_next_header (ip0);
1795
1796 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1797 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1798
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 leaf0 =
1800 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801
1802 /* Verify UDP length. */
1803 ip_len0 = clib_net_to_host_u16 (ip0->length);
1804 udp_len0 = clib_net_to_host_u16 (udp0->length);
1805
1806 len_diff0 = ip_len0 - udp_len0;
1807
1808 len_diff0 = is_udp0 ? len_diff0 : 0;
1809
Dave Barachd7cb1b52016-12-09 09:52:16 -05001810 if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811 {
1812 if (is_tcp_udp0)
1813 {
1814 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001815 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001816 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1817 good_tcp_udp0 =
1818 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1819 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1820 }
1821 }
1822
1823 good_tcp_udp0 &= len_diff0 >= 0;
1824
Dave Barachd7cb1b52016-12-09 09:52:16 -05001825 leaf0 =
1826 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001827
1828 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1829
1830 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1831
1832 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001833 error0 = (is_tcp_udp0 && !good_tcp_udp0
1834 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001835
Dave Barachd7cb1b52016-12-09 09:52:16 -05001836 leaf0 =
1837 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1838 leaf0 =
1839 (leaf0 ==
1840 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001842 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001843 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001844
Dave Barachd7cb1b52016-12-09 09:52:16 -05001845 lb0 = load_balance_get (lbi0);
1846 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001847
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001848 vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001849 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001850
Neale Ranns3ee44042016-10-03 13:05:48 +01001851 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001852 dpo0->dpoi_type == DPO_RECEIVE) ?
1853 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1854 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1855 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001856 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001857 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858
Dave Barach68b0fb02017-02-28 15:15:56 -05001859 skip_check:
1860
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861 next0 = lm->local_next_by_ip_protocol[proto0];
1862
Dave Barachd7cb1b52016-12-09 09:52:16 -05001863 next0 =
1864 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865
Dave Barachd7cb1b52016-12-09 09:52:16 -05001866 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001867
Dave Barach68b0fb02017-02-28 15:15:56 -05001868 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001869 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001870 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1871 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001872 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001873
1874 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1875 n_left_to_next, pi0, next0);
1876
Ed Warnickecb9cada2015-12-08 15:45:58 -07001877 }
Dave Barach75fc8542016-10-11 16:16:02 -04001878
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1880 }
1881
1882 return frame->n_vectors;
1883}
1884
Dave Barach68b0fb02017-02-28 15:15:56 -05001885static uword
1886ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1887{
1888 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1889}
1890
1891/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001892VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893{
Dave Barach68b0fb02017-02-28 15:15:56 -05001894 .function = ip4_local,
1895 .name = "ip4-local",
1896 .vector_size = sizeof (u32),
1897 .format_trace = format_ip4_forward_next_trace,
1898 .n_next_nodes = IP_LOCAL_N_NEXT,
1899 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001900 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001901 [IP_LOCAL_NEXT_DROP] = "error-drop",
1902 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1903 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1904 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",},
1905};
1906/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001907
1908VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1909
Dave Barach68b0fb02017-02-28 15:15:56 -05001910static uword
1911ip4_local_end_of_arc (vlib_main_t * vm,
1912 vlib_node_runtime_t * node, vlib_frame_t * frame)
1913{
1914 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1915}
1916
1917/* *INDENT-OFF* */
1918VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1919 .function = ip4_local_end_of_arc,
1920 .name = "ip4-local-end-of-arc",
1921 .vector_size = sizeof (u32),
1922
1923 .format_trace = format_ip4_forward_next_trace,
1924 .sibling_of = "ip4-local",
1925};
1926
1927VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1928
1929VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1930 .arc_name = "ip4-local",
1931 .node_name = "ip4-local-end-of-arc",
1932 .runs_before = 0, /* not before any other features */
1933};
1934/* *INDENT-ON* */
1935
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936void
1937ip4_register_protocol (u32 protocol, u32 node_index)
1938{
1939 vlib_main_t *vm = vlib_get_main ();
1940 ip4_main_t *im = &ip4_main;
1941 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942
1943 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001944 lm->local_next_by_ip_protocol[protocol] =
1945 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946}
1947
1948static clib_error_t *
1949show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001950 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001951{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001952 ip4_main_t *im = &ip4_main;
1953 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001954 int i;
1955
1956 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001957 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958 {
1959 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001960 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961 }
1962 return 0;
1963}
1964
1965
1966
Billy McFall0683c9c2016-10-13 08:27:31 -04001967/*?
1968 * Display the set of protocols handled by the local IPv4 stack.
1969 *
1970 * @cliexpar
1971 * Example of how to display local protocol table:
1972 * @cliexstart{show ip local}
1973 * Protocols handled by ip4_local
1974 * 1
1975 * 17
1976 * 47
1977 * @cliexend
1978?*/
1979/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001980VLIB_CLI_COMMAND (show_ip_local, static) =
1981{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001982 .path = "show ip local",
1983 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001984 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001985};
Billy McFall0683c9c2016-10-13 08:27:31 -04001986/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001988always_inline uword
1989ip4_arp_inline (vlib_main_t * vm,
1990 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001991 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001993 vnet_main_t *vnm = vnet_get_main ();
1994 ip4_main_t *im = &ip4_main;
1995 ip_lookup_main_t *lm = &im->lookup_main;
1996 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001997 uword n_left_from, n_left_to_next_drop, next_index;
1998 static f64 time_last_seed_change = -1e100;
1999 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04002000 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002001 f64 time_now;
2002
2003 if (node->flags & VLIB_NODE_FLAG_TRACE)
2004 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2005
2006 time_now = vlib_time_now (vm);
2007 if (time_now - time_last_seed_change > 1e-3)
2008 {
2009 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002010 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
2011 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2013 hash_seeds[i] = r[i];
2014
2015 /* Mark all hash keys as been no-seen before. */
2016 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2017 hash_bitmap[i] = 0;
2018
2019 time_last_seed_change = time_now;
2020 }
2021
2022 from = vlib_frame_vector_args (frame);
2023 n_left_from = frame->n_vectors;
2024 next_index = node->cached_next_index;
2025 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002026 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027
2028 while (n_left_from > 0)
2029 {
2030 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2031 to_next_drop, n_left_to_next_drop);
2032
2033 while (n_left_from > 0 && n_left_to_next_drop > 0)
2034 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002035 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002036 ip_adjacency_t *adj0;
2037 vlib_buffer_t *p0;
2038 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002039 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002040
2041 pi0 = from[0];
2042
2043 p0 = vlib_get_buffer (vm, pi0);
2044
2045 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2046 adj0 = ip_get_adjacency (lm, adj_index0);
2047 ip0 = vlib_buffer_get_current (p0);
2048
Ed Warnickecb9cada2015-12-08 15:45:58 -07002049 a0 = hash_seeds[0];
2050 b0 = hash_seeds[1];
2051 c0 = hash_seeds[2];
2052
2053 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2054 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2055
Dave Barachd7cb1b52016-12-09 09:52:16 -05002056 if (is_glean)
2057 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002058 /*
2059 * this is the Glean case, so we are ARPing for the
2060 * packet's destination
2061 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002062 a0 ^= ip0->dst_address.data_u32;
2063 }
2064 else
2065 {
2066 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2067 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002068 b0 ^= sw_if_index0;
2069
2070 hash_v3_finalize32 (a0, b0, c0);
2071
2072 c0 &= BITS (hash_bitmap) - 1;
2073 c0 = c0 / BITS (uword);
2074 m0 = (uword) 1 << (c0 % BITS (uword));
2075
2076 bm0 = hash_bitmap[c0];
2077 drop0 = (bm0 & m0) != 0;
2078
2079 /* Mark it as seen. */
2080 hash_bitmap[c0] = bm0 | m0;
2081
2082 from += 1;
2083 n_left_from -= 1;
2084 to_next_drop[0] = pi0;
2085 to_next_drop += 1;
2086 n_left_to_next_drop -= 1;
2087
Dave Barachd7cb1b52016-12-09 09:52:16 -05002088 p0->error =
2089 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2090 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002091
Neale Rannsb80c5362016-10-08 13:03:40 +01002092 /*
2093 * the adj has been updated to a rewrite but the node the DPO that got
2094 * us here hasn't - yet. no big deal. we'll drop while we wait.
2095 */
2096 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2097 continue;
2098
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099 if (drop0)
2100 continue;
2101
Dave Barachd7cb1b52016-12-09 09:52:16 -05002102 /*
2103 * Can happen if the control-plane is programming tables
2104 * with traffic flowing; at least that's today's lame excuse.
2105 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002106 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2107 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002108 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002109 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002110 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002111 else
2112 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002113 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002114 u32 bi0 = 0;
2115 vlib_buffer_t *b0;
2116 ethernet_arp_header_t *h0;
2117 vnet_hw_interface_t *hw_if0;
2118
2119 h0 =
2120 vlib_packet_template_get_packet (vm,
2121 &im->ip4_arp_request_packet_template,
2122 &bi0);
2123
2124 /* Add rewrite/encap string for ARP packet. */
2125 vnet_rewrite_one_header (adj0[0], h0,
2126 sizeof (ethernet_header_t));
2127
2128 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2129
2130 /* Src ethernet address in ARP header. */
2131 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2132 hw_if0->hw_address,
2133 sizeof (h0->ip4_over_ethernet[0].ethernet));
2134
2135 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002136 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002137 /* The interface's source address is stashed in the Glean Adj */
2138 h0->ip4_over_ethernet[0].ip4 =
2139 adj0->sub_type.glean.receive_addr.ip4;
2140
2141 /* Copy in destination address we are requesting. This is the
2142 * glean case, so it's the packet's destination.*/
2143 h0->ip4_over_ethernet[1].ip4.data_u32 =
2144 ip0->dst_address.data_u32;
2145 }
2146 else
2147 {
2148 /* Src IP address in ARP header. */
2149 if (ip4_src_address_for_packet (lm, sw_if_index0,
2150 &h0->
2151 ip4_over_ethernet[0].ip4))
2152 {
2153 /* No source address available */
2154 p0->error =
2155 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2156 vlib_buffer_free (vm, &bi0, 1);
2157 continue;
2158 }
2159
2160 /* Copy in destination address we are requesting from the
2161 incomplete adj */
2162 h0->ip4_over_ethernet[1].ip4.data_u32 =
2163 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002164 }
2165
Dave Barachd7cb1b52016-12-09 09:52:16 -05002166 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2167 b0 = vlib_get_buffer (vm, bi0);
2168 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2169
2170 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2171
2172 vlib_set_next_frame_buffer (vm, node,
2173 adj0->rewrite_header.next_index,
2174 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002175 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002176 }
2177
2178 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2179 }
2180
2181 return frame->n_vectors;
2182}
2183
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002184static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002185ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002186{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002187 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002188}
2189
2190static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002191ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002192{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002193 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002194}
2195
Dave Barachd7cb1b52016-12-09 09:52:16 -05002196static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002197 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2198 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2199 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2200 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2201 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002202 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203};
2204
Dave Barachd7cb1b52016-12-09 09:52:16 -05002205VLIB_REGISTER_NODE (ip4_arp_node) =
2206{
2207 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2208 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2209 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2210 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2211 {
2212 [IP4_ARP_NEXT_DROP] = "error-drop",}
2213,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214
Dave Barachd7cb1b52016-12-09 09:52:16 -05002215VLIB_REGISTER_NODE (ip4_glean_node) =
2216{
2217 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2218 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2219 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2220 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2221 {
2222 [IP4_ARP_NEXT_DROP] = "error-drop",}
2223,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002224
Ed Warnickecb9cada2015-12-08 15:45:58 -07002225#define foreach_notrace_ip4_arp_error \
2226_(DROP) \
2227_(REQUEST_SENT) \
2228_(REPLICATE_DROP) \
2229_(REPLICATE_FAIL)
2230
Dave Barachd7cb1b52016-12-09 09:52:16 -05002231clib_error_t *
2232arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002233{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002234 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002235
2236 /* don't trace ARP request packets */
2237#define _(a) \
2238 vnet_pcap_drop_trace_filter_add_del \
2239 (rt->errors[IP4_ARP_ERROR_##a], \
2240 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002241 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002242#undef _
2243 return 0;
2244}
2245
Dave Barachd7cb1b52016-12-09 09:52:16 -05002246VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002247
2248
2249/* Send an ARP request to see if given destination is reachable on given interface. */
2250clib_error_t *
2251ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2252{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002253 vnet_main_t *vnm = vnet_get_main ();
2254 ip4_main_t *im = &ip4_main;
2255 ethernet_arp_header_t *h;
2256 ip4_address_t *src;
2257 ip_interface_address_t *ia;
2258 ip_adjacency_t *adj;
2259 vnet_hw_interface_t *hi;
2260 vnet_sw_interface_t *si;
2261 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002262 u32 bi = 0;
2263
2264 si = vnet_get_sw_interface (vnm, sw_if_index);
2265
2266 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2267 {
2268 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002269 format_ip4_address, dst,
2270 format_vnet_sw_if_index_name, vnm,
2271 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 }
2273
Dave Barachd7cb1b52016-12-09 09:52:16 -05002274 src =
2275 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2276 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002277 {
2278 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002279 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002280 (0,
2281 "no matching interface address for destination %U (interface %U)",
2282 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2283 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002284 }
2285
2286 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2287
Dave Barachd7cb1b52016-12-09 09:52:16 -05002288 h =
Neale Ranns32e1c012016-11-22 17:07:28 +00002289 vlib_packet_template_get_packet (vm,
2290 &im->ip4_arp_request_packet_template,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002291 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292
2293 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2294
Dave Barachd7cb1b52016-12-09 09:52:16 -05002295 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2296 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297
2298 h->ip4_over_ethernet[0].ip4 = src[0];
2299 h->ip4_over_ethernet[1].ip4 = dst[0];
2300
2301 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002302 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2303 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304
2305 /* Add encapsulation string for software interface (e.g. ethernet header). */
2306 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2307 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2308
2309 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002310 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2311 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002312 to_next[0] = bi;
2313 f->n_vectors = 1;
2314 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2315 }
2316
2317 return /* no error */ 0;
2318}
2319
Dave Barachd7cb1b52016-12-09 09:52:16 -05002320typedef enum
2321{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002322 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002323 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324} ip4_rewrite_next_t;
2325
2326always_inline uword
2327ip4_rewrite_inline (vlib_main_t * vm,
2328 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002329 vlib_frame_t * frame,
2330 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002331{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002332 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2333 u32 *from = vlib_frame_vector_args (frame);
2334 u32 n_left_from, n_left_to_next, *to_next, next_index;
2335 vlib_node_runtime_t *error_node =
2336 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002337
2338 n_left_from = frame->n_vectors;
2339 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002340 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04002341
Ed Warnickecb9cada2015-12-08 15:45:58 -07002342 while (n_left_from > 0)
2343 {
2344 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2345
2346 while (n_left_from >= 4 && n_left_to_next >= 2)
2347 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002348 ip_adjacency_t *adj0, *adj1;
2349 vlib_buffer_t *p0, *p1;
2350 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002351 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2352 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002353 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002354
Ed Warnickecb9cada2015-12-08 15:45:58 -07002355 /* Prefetch next iteration. */
2356 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002357 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002358
2359 p2 = vlib_get_buffer (vm, from[2]);
2360 p3 = vlib_get_buffer (vm, from[3]);
2361
2362 vlib_prefetch_buffer_header (p2, STORE);
2363 vlib_prefetch_buffer_header (p3, STORE);
2364
2365 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2366 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2367 }
2368
2369 pi0 = to_next[0] = from[0];
2370 pi1 = to_next[1] = from[1];
2371
2372 from += 2;
2373 n_left_from -= 2;
2374 to_next += 2;
2375 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002376
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 p0 = vlib_get_buffer (vm, pi0);
2378 p1 = vlib_get_buffer (vm, pi1);
2379
Neale Rannsf06aea52016-11-29 06:51:37 -08002380 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2381 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382
Dave Barachd7cb1b52016-12-09 09:52:16 -05002383 /* We should never rewrite a pkt using the MISS adjacency */
2384 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385
2386 ip0 = vlib_buffer_get_current (p0);
2387 ip1 = vlib_buffer_get_current (p1);
2388
2389 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002390 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391
2392 /* Decrement TTL & update checksum.
2393 Works either endian, so no need for byte swap. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002394 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002396 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397
2398 /* Input node should have reject packets with ttl 0. */
2399 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002400
2401 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002402 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403
2404 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002407
Dave Barachd7cb1b52016-12-09 09:52:16 -05002408 /*
2409 * If the ttl drops below 1 when forwarding, generate
2410 * an ICMP response.
2411 */
2412 if (PREDICT_FALSE (ttl0 <= 0))
2413 {
2414 error0 = IP4_ERROR_TIME_EXPIRED;
2415 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2416 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2417 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2418 0);
2419 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2420 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002421
2422 /* Verify checksum. */
2423 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2424 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002425 else
2426 {
2427 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2428 }
2429 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002430 {
2431 i32 ttl1 = ip1->ttl;
2432
2433 /* Input node should have reject packets with ttl 0. */
2434 ASSERT (ip1->ttl > 0);
2435
2436 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2437 checksum1 += checksum1 >= 0xffff;
2438
2439 ip1->checksum = checksum1;
2440 ttl1 -= 1;
2441 ip1->ttl = ttl1;
2442
Dave Barachd7cb1b52016-12-09 09:52:16 -05002443 /*
2444 * If the ttl drops below 1 when forwarding, generate
2445 * an ICMP response.
2446 */
2447 if (PREDICT_FALSE (ttl1 <= 0))
2448 {
2449 error1 = IP4_ERROR_TIME_EXPIRED;
2450 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2451 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2452 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2453 0);
2454 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2455 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456
2457 /* Verify checksum. */
2458 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2459 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2460 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002461 else
2462 {
2463 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2464 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465
2466 /* Rewrite packet header and updates lengths. */
2467 adj0 = ip_get_adjacency (lm, adj_index0);
2468 adj1 = ip_get_adjacency (lm, adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002469
Dave Barachd7cb1b52016-12-09 09:52:16 -05002470 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 rw_len0 = adj0[0].rewrite_header.data_bytes;
2472 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002473 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2474 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002475
Dave Barachd7cb1b52016-12-09 09:52:16 -05002476 /* Check MTU of outgoing interface. */
2477 error0 =
2478 (vlib_buffer_length_in_chain (vm, p0) >
2479 adj0[0].
2480 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2481 error0);
2482 error1 =
2483 (vlib_buffer_length_in_chain (vm, p1) >
2484 adj1[0].
2485 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2486 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002487
Dave Barachd7cb1b52016-12-09 09:52:16 -05002488 /*
Neale Ranns044183f2017-01-24 01:34:25 -08002489 * pre-fetch the per-adjacency counters
Dave Barachd7cb1b52016-12-09 09:52:16 -05002490 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002491 if (do_counters)
2492 {
2493 vlib_prefetch_combined_counter (&adjacency_counters,
2494 cpu_index, adj_index0);
2495 vlib_prefetch_combined_counter (&adjacency_counters,
2496 cpu_index, adj_index1);
2497 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002498
Dave Barachd7cb1b52016-12-09 09:52:16 -05002499 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2500 * to see the IP headerr */
2501 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2502 {
Damjan Marion892e0762016-12-09 18:52:05 +01002503 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002504 p0->current_data -= rw_len0;
2505 p0->current_length += rw_len0;
2506 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2507 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002508
Dave Barachd7cb1b52016-12-09 09:52:16 -05002509 vnet_feature_arc_start (lm->output_feature_arc_index,
2510 tx_sw_if_index0, &next0, p0);
2511 }
2512 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2513 {
Damjan Marion892e0762016-12-09 18:52:05 +01002514 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002515 p1->current_data -= rw_len1;
2516 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002517
Dave Barachd7cb1b52016-12-09 09:52:16 -05002518 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2519 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002520
Dave Barachd7cb1b52016-12-09 09:52:16 -05002521 vnet_feature_arc_start (lm->output_feature_arc_index,
2522 tx_sw_if_index1, &next1, p1);
2523 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002524
2525 /* Guess we are only writing on simple Ethernet header. */
2526 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002527 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002528
Neale Ranns044183f2017-01-24 01:34:25 -08002529 /*
2530 * Bump the per-adjacency counters
2531 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002532 if (do_counters)
2533 {
2534 vlib_increment_combined_counter
2535 (&adjacency_counters,
2536 cpu_index,
2537 adj_index0, 1,
2538 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002539
Neale Ranns9c6a6132017-02-21 05:33:14 -08002540 vlib_increment_combined_counter
2541 (&adjacency_counters,
2542 cpu_index,
2543 adj_index1, 1,
2544 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2545 }
Neale Ranns044183f2017-01-24 01:34:25 -08002546
Neale Ranns5e575b12016-10-03 09:40:25 +01002547 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002548 {
2549 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2550 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2551 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002552 if (is_mcast)
2553 {
2554 /*
2555 * copy bytes from the IP address into the MAC rewrite
2556 */
2557 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2558 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 1);
2559 }
Dave Barach75fc8542016-10-11 16:16:02 -04002560
Ed Warnickecb9cada2015-12-08 15:45:58 -07002561 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2562 to_next, n_left_to_next,
2563 pi0, pi1, next0, next1);
2564 }
2565
2566 while (n_left_from > 0 && n_left_to_next > 0)
2567 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002568 ip_adjacency_t *adj0;
2569 vlib_buffer_t *p0;
2570 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002573
Ed Warnickecb9cada2015-12-08 15:45:58 -07002574 pi0 = to_next[0] = from[0];
2575
2576 p0 = vlib_get_buffer (vm, pi0);
2577
Neale Rannsf06aea52016-11-29 06:51:37 -08002578 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579
Dave Barachd7cb1b52016-12-09 09:52:16 -05002580 /* We should never rewrite a pkt using the MISS adjacency */
2581 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002582
2583 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002584
Ed Warnickecb9cada2015-12-08 15:45:58 -07002585 ip0 = vlib_buffer_get_current (p0);
2586
2587 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002588 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002589
2590 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002591 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002592 {
2593 i32 ttl0 = ip0->ttl;
2594
2595 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2596
2597 checksum0 += checksum0 >= 0xffff;
2598
2599 ip0->checksum = checksum0;
2600
2601 ASSERT (ip0->ttl > 0);
2602
2603 ttl0 -= 1;
2604
2605 ip0->ttl = ttl0;
2606
2607 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2608
Dave Barachd7cb1b52016-12-09 09:52:16 -05002609 if (PREDICT_FALSE (ttl0 <= 0))
2610 {
2611 /*
2612 * If the ttl drops below 1 when forwarding, generate
2613 * an ICMP response.
2614 */
2615 error0 = IP4_ERROR_TIME_EXPIRED;
2616 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2617 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2618 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2619 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2620 0);
2621 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002622 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002623 else
2624 {
2625 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2626 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002627
Neale Ranns044183f2017-01-24 01:34:25 -08002628 vlib_prefetch_combined_counter (&adjacency_counters,
2629 cpu_index, adj_index0);
2630
Ed Warnickecb9cada2015-12-08 15:45:58 -07002631 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002632 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002633 if (is_mcast)
2634 {
2635 /*
2636 * copy bytes from the IP address into the MAC rewrite
2637 */
2638 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2639 }
Dave Barach75fc8542016-10-11 16:16:02 -04002640
Dave Barachd7cb1b52016-12-09 09:52:16 -05002641 /* Update packet buffer attributes/set output interface. */
2642 rw_len0 = adj0[0].rewrite_header.data_bytes;
2643 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002644
Neale Ranns044183f2017-01-24 01:34:25 -08002645 vlib_increment_combined_counter
2646 (&adjacency_counters,
2647 cpu_index,
2648 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002649
Dave Barachd7cb1b52016-12-09 09:52:16 -05002650 /* Check MTU of outgoing interface. */
2651 error0 = (vlib_buffer_length_in_chain (vm, p0)
2652 > adj0[0].rewrite_header.max_l3_packet_bytes
2653 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002654
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002656
Dave Barachd7cb1b52016-12-09 09:52:16 -05002657 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2658 * to see the IP headerr */
2659 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2660 {
2661 p0->current_data -= rw_len0;
2662 p0->current_length += rw_len0;
2663 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002664
Dave Barachd7cb1b52016-12-09 09:52:16 -05002665 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2666 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002667
Neale Ranns5e575b12016-10-03 09:40:25 +01002668 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002669 {
2670 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002671 }
2672
Dave Barachd7cb1b52016-12-09 09:52:16 -05002673 vnet_feature_arc_start (lm->output_feature_arc_index,
2674 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002675
Dave Barachd7cb1b52016-12-09 09:52:16 -05002676 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677
Ed Warnickecb9cada2015-12-08 15:45:58 -07002678 from += 1;
2679 n_left_from -= 1;
2680 to_next += 1;
2681 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002682
Ed Warnickecb9cada2015-12-08 15:45:58 -07002683 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2684 to_next, n_left_to_next,
2685 pi0, next0);
2686 }
Dave Barach75fc8542016-10-11 16:16:02 -04002687
Ed Warnickecb9cada2015-12-08 15:45:58 -07002688 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2689 }
2690
2691 /* Need to do trace after rewrites to pick up new packet data. */
2692 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002693 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002694
2695 return frame->n_vectors;
2696}
2697
Dave Barach132d51d2016-07-07 10:10:17 -04002698
Neale Rannsf06aea52016-11-29 06:51:37 -08002699/** @brief IPv4 rewrite node.
2700 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002701
2702 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2703 header checksum, fetch the ip adjacency, check the outbound mtu,
2704 apply the adjacency rewrite, and send pkts to the adjacency
2705 rewrite header's rewrite_next_index.
2706
2707 @param vm vlib_main_t corresponding to the current thread
2708 @param node vlib_node_runtime_t
2709 @param frame vlib_frame_t whose contents should be dispatched
2710
2711 @par Graph mechanics: buffer metadata, next index usage
2712
2713 @em Uses:
2714 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2715 - the rewrite adjacency index
2716 - <code>adj->lookup_next_index</code>
2717 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002718 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002719 - <code>adj->rewrite_header</code>
2720 - Rewrite string length, rewrite string, next_index
2721
2722 @em Sets:
2723 - <code>b->current_data, b->current_length</code>
2724 - Updated net of applying the rewrite string
2725
2726 <em>Next Indices:</em>
2727 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002728 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002729*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002730static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002731ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002732 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002733{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002734 if (adj_are_counters_enabled ())
2735 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2736 else
2737 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002738}
2739
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002740static uword
2741ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002742 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002743{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002744 if (adj_are_counters_enabled ())
2745 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2746 else
2747 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002748}
2749
Neale Ranns32e1c012016-11-22 17:07:28 +00002750static uword
2751ip4_rewrite_mcast (vlib_main_t * vm,
2752 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002753{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002754 if (adj_are_counters_enabled ())
2755 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2756 else
2757 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002758}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002759
Neale Ranns32e1c012016-11-22 17:07:28 +00002760/* *INDENT-OFF* */
2761VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2762 .function = ip4_rewrite,
2763 .name = "ip4-rewrite",
2764 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002765
Neale Ranns32e1c012016-11-22 17:07:28 +00002766 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002767
Neale Ranns32e1c012016-11-22 17:07:28 +00002768 .n_next_nodes = 2,
2769 .next_nodes = {
2770 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2771 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2772 },
2773};
2774VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2775
2776VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2777 .function = ip4_rewrite_mcast,
2778 .name = "ip4-rewrite-mcast",
2779 .vector_size = sizeof (u32),
2780
2781 .format_trace = format_ip4_rewrite_trace,
2782 .sibling_of = "ip4-rewrite",
2783};
2784VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2785
2786VLIB_REGISTER_NODE (ip4_midchain_node) = {
2787 .function = ip4_midchain,
2788 .name = "ip4-midchain",
2789 .vector_size = sizeof (u32),
2790 .format_trace = format_ip4_forward_next_trace,
2791 .sibling_of = "ip4-rewrite",
2792};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002793VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002794/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002795
Ed Warnickecb9cada2015-12-08 15:45:58 -07002796static clib_error_t *
2797add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002798 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002799{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002800 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002801 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002802 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002803 u32 sw_if_index, table_id;
2804
2805 sw_if_index = ~0;
2806
Dave Barachd7cb1b52016-12-09 09:52:16 -05002807 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002808 {
2809 error = clib_error_return (0, "unknown interface `%U'",
2810 format_unformat_error, input);
2811 goto done;
2812 }
2813
2814 if (unformat (input, "%d", &table_id))
2815 ;
2816 else
2817 {
2818 error = clib_error_return (0, "expected table id `%U'",
2819 format_unformat_error, input);
2820 goto done;
2821 }
2822
Neale Ranns4008ac92017-02-13 23:20:04 -08002823 /*
2824 * If the interface already has in IP address, then a change int
2825 * VRF is not allowed. The IP address applied must first be removed.
2826 * We do not do that automatically here, since VPP has no knowledge
2827 * of whether thoses subnets are valid in the destination VRF.
2828 */
2829 /* *INDENT-OFF* */
2830 foreach_ip_interface_address (&ip4_main.lookup_main,
2831 ia, sw_if_index,
2832 1 /* honor unnumbered */,
2833 ({
2834 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002835
Neale Ranns4008ac92017-02-13 23:20:04 -08002836 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2837 error = clib_error_return (0, "interface %U has address %U",
2838 format_vnet_sw_if_index_name, vnm,
2839 sw_if_index,
2840 format_ip4_address, a);
2841 goto done;
2842 }));
2843 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002844
Neale Ranns4008ac92017-02-13 23:20:04 -08002845{
2846 ip4_main_t *im = &ip4_main;
2847 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002848
Neale Ranns4008ac92017-02-13 23:20:04 -08002849 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2850
2851 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2852 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2853
2854 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2855 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2856 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2857}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002858
Dave Barachd7cb1b52016-12-09 09:52:16 -05002859done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002860return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002861}
2862
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002863/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002864 * Place the indicated interface into the supplied IPv4 FIB table (also known
2865 * as a VRF). If the FIB table does not exist, this command creates it. To
2866 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2867 * FIB table will only be displayed if a route has been added to the table, or
2868 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002869 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002870 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002871 * @note IP addresses added after setting the interface IP table are added to
2872 * the indicated FIB table. If an IP address is added prior to changing the
2873 * table then this is an error. The control plane must remove these addresses
2874 * first and then change the table. VPP will not automatically move the
2875 * addresses from the old to the new table as it does not know the validity
2876 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002877 *
2878 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002879 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2880 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002881 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002882/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002883VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2884{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002885 .path = "set interface ip table",
2886 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002887 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888};
Billy McFall0683c9c2016-10-13 08:27:31 -04002889/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002890
Dave Barachd7cb1b52016-12-09 09:52:16 -05002891int
2892ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2893{
2894 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002895 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002896 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002897
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002898 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002899
2900 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2901 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
2902 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
2903 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2904 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002905
Ed Warnickecb9cada2015-12-08 15:45:58 -07002906 /* Handle default route. */
2907 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002908
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002909 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002910
Dave Barachd7cb1b52016-12-09 09:52:16 -05002911 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002912}
Dave Barach75fc8542016-10-11 16:16:02 -04002913
Ed Warnickecb9cada2015-12-08 15:45:58 -07002914static clib_error_t *
2915test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002916 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002917{
Billy McFall309fe062016-10-14 07:37:33 -04002918 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919 u32 table_id = 0;
2920 f64 count = 1;
2921 u32 n;
2922 int i;
2923 ip4_address_t ip4_base_address;
2924 u64 errors = 0;
2925
Dave Barachd7cb1b52016-12-09 09:52:16 -05002926 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2927 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002929 {
2930 /* Make sure the entry exists. */
2931 fib = ip4_fib_get (table_id);
2932 if ((fib) && (fib->index != table_id))
2933 return clib_error_return (0, "<fib-index> %d does not exist",
2934 table_id);
2935 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002936 else if (unformat (input, "count %f", &count))
2937 ;
2938
2939 else if (unformat (input, "%U",
2940 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002941 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002942 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002943 return clib_error_return (0, "unknown input `%U'",
2944 format_unformat_error, input);
2945 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946
2947 n = count;
2948
2949 for (i = 0; i < n; i++)
2950 {
2951 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002953
Dave Barach75fc8542016-10-11 16:16:02 -04002954 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002955 clib_host_to_net_u32 (1 +
2956 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957 }
2958
Dave Barach75fc8542016-10-11 16:16:02 -04002959 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002960 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2961 else
2962 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2963
2964 return 0;
2965}
2966
Billy McFall0683c9c2016-10-13 08:27:31 -04002967/*?
2968 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2969 * given FIB table to determine if there is a conflict with the
2970 * adjacency table. The fib-id can be determined by using the
2971 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2972 * of 0 is used.
2973 *
2974 * @todo This command uses fib-id, other commands use table-id (not
2975 * just a name, they are different indexes). Would like to change this
2976 * to table-id for consistency.
2977 *
2978 * @cliexpar
2979 * Example of how to run the test lookup command:
2980 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2981 * No errors in 2 lookups
2982 * @cliexend
2983?*/
2984/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002985VLIB_CLI_COMMAND (lookup_test_command, static) =
2986{
2987 .path = "test lookup",
2988 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2989 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002990};
Billy McFall0683c9c2016-10-13 08:27:31 -04002991/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002992
Dave Barachd7cb1b52016-12-09 09:52:16 -05002993int
2994vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002995{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002996 ip4_main_t *im4 = &ip4_main;
2997 ip4_fib_t *fib;
2998 uword *p = hash_get (im4->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002999
3000 if (p == 0)
3001 return VNET_API_ERROR_NO_SUCH_FIB;
3002
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003003 fib = ip4_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003004
3005 fib->flow_hash_config = flow_hash_config;
3006 return 0;
3007}
Dave Barach75fc8542016-10-11 16:16:02 -04003008
Ed Warnickecb9cada2015-12-08 15:45:58 -07003009static clib_error_t *
3010set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003011 unformat_input_t * input,
3012 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003013{
3014 int matched = 0;
3015 u32 table_id = 0;
3016 u32 flow_hash_config = 0;
3017 int rv;
3018
Dave Barachd7cb1b52016-12-09 09:52:16 -05003019 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3020 {
3021 if (unformat (input, "table %d", &table_id))
3022 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003023#define _(a,v) \
3024 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003025 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003026#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003027 else
3028 break;
3029 }
Dave Barach75fc8542016-10-11 16:16:02 -04003030
Ed Warnickecb9cada2015-12-08 15:45:58 -07003031 if (matched == 0)
3032 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003033 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003034
Ed Warnickecb9cada2015-12-08 15:45:58 -07003035 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3036 switch (rv)
3037 {
3038 case 0:
3039 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003040
Ed Warnickecb9cada2015-12-08 15:45:58 -07003041 case VNET_API_ERROR_NO_SUCH_FIB:
3042 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003043
Ed Warnickecb9cada2015-12-08 15:45:58 -07003044 default:
3045 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3046 break;
3047 }
Dave Barach75fc8542016-10-11 16:16:02 -04003048
Ed Warnickecb9cada2015-12-08 15:45:58 -07003049 return 0;
3050}
Dave Barach75fc8542016-10-11 16:16:02 -04003051
Billy McFall0683c9c2016-10-13 08:27:31 -04003052/*?
3053 * Configure the set of IPv4 fields used by the flow hash.
3054 *
3055 * @cliexpar
3056 * Example of how to set the flow hash on a given table:
3057 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3058 * Example of display the configured flow hash:
3059 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003060 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3061 * 0.0.0.0/0
3062 * unicast-ip4-chain
3063 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3064 * [0] [@0]: dpo-drop ip6
3065 * 0.0.0.0/32
3066 * unicast-ip4-chain
3067 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3068 * [0] [@0]: dpo-drop ip6
3069 * 224.0.0.0/8
3070 * unicast-ip4-chain
3071 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3072 * [0] [@0]: dpo-drop ip6
3073 * 6.0.1.2/32
3074 * unicast-ip4-chain
3075 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3076 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3077 * 7.0.0.1/32
3078 * unicast-ip4-chain
3079 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3080 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3081 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3082 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3083 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3084 * 240.0.0.0/8
3085 * unicast-ip4-chain
3086 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3087 * [0] [@0]: dpo-drop ip6
3088 * 255.255.255.255/32
3089 * unicast-ip4-chain
3090 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3091 * [0] [@0]: dpo-drop ip6
3092 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3093 * 0.0.0.0/0
3094 * unicast-ip4-chain
3095 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3096 * [0] [@0]: dpo-drop ip6
3097 * 0.0.0.0/32
3098 * unicast-ip4-chain
3099 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3100 * [0] [@0]: dpo-drop ip6
3101 * 172.16.1.0/24
3102 * unicast-ip4-chain
3103 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3104 * [0] [@4]: ipv4-glean: af_packet0
3105 * 172.16.1.1/32
3106 * unicast-ip4-chain
3107 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3108 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3109 * 172.16.1.2/32
3110 * unicast-ip4-chain
3111 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3112 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3113 * 172.16.2.0/24
3114 * unicast-ip4-chain
3115 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3116 * [0] [@4]: ipv4-glean: af_packet1
3117 * 172.16.2.1/32
3118 * unicast-ip4-chain
3119 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3120 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3121 * 224.0.0.0/8
3122 * unicast-ip4-chain
3123 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3124 * [0] [@0]: dpo-drop ip6
3125 * 240.0.0.0/8
3126 * unicast-ip4-chain
3127 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3128 * [0] [@0]: dpo-drop ip6
3129 * 255.255.255.255/32
3130 * unicast-ip4-chain
3131 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3132 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003133 * @cliexend
3134?*/
3135/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003136VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3137{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003139 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003140 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003141 .function = set_ip_flow_hash_command_fn,
3142};
Billy McFall0683c9c2016-10-13 08:27:31 -04003143/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003144
Dave Barachd7cb1b52016-12-09 09:52:16 -05003145int
3146vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3147 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003148{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003149 vnet_main_t *vnm = vnet_get_main ();
3150 vnet_interface_main_t *im = &vnm->interface_main;
3151 ip4_main_t *ipm = &ip4_main;
3152 ip_lookup_main_t *lm = &ipm->lookup_main;
3153 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003154 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155
3156 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3157 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3158
3159 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3160 return VNET_API_ERROR_NO_SUCH_ENTRY;
3161
3162 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003163 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003164
Neale Rannsdf089a82016-10-02 16:39:06 +01003165 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3166
3167 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003168 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003169 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003170 .fp_len = 32,
3171 .fp_proto = FIB_PROTOCOL_IP4,
3172 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003173 };
3174 u32 fib_index;
3175
Dave Barachd7cb1b52016-12-09 09:52:16 -05003176 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3177 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003178
3179
Dave Barachd7cb1b52016-12-09 09:52:16 -05003180 if (table_index != (u32) ~ 0)
3181 {
3182 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003183
Dave Barachd7cb1b52016-12-09 09:52:16 -05003184 dpo_set (&dpo,
3185 DPO_CLASSIFY,
3186 DPO_PROTO_IP4,
3187 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003188
Dave Barachd7cb1b52016-12-09 09:52:16 -05003189 fib_table_entry_special_dpo_add (fib_index,
3190 &pfx,
3191 FIB_SOURCE_CLASSIFY,
3192 FIB_ENTRY_FLAG_NONE, &dpo);
3193 dpo_reset (&dpo);
3194 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003195 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003196 {
3197 fib_table_entry_special_remove (fib_index,
3198 &pfx, FIB_SOURCE_CLASSIFY);
3199 }
3200 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003201
Ed Warnickecb9cada2015-12-08 15:45:58 -07003202 return 0;
3203}
3204
3205static clib_error_t *
3206set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003207 unformat_input_t * input,
3208 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003209{
3210 u32 table_index = ~0;
3211 int table_index_set = 0;
3212 u32 sw_if_index = ~0;
3213 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003214
Dave Barachd7cb1b52016-12-09 09:52:16 -05003215 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3216 {
3217 if (unformat (input, "table-index %d", &table_index))
3218 table_index_set = 1;
3219 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3220 vnet_get_main (), &sw_if_index))
3221 ;
3222 else
3223 break;
3224 }
Dave Barach75fc8542016-10-11 16:16:02 -04003225
Ed Warnickecb9cada2015-12-08 15:45:58 -07003226 if (table_index_set == 0)
3227 return clib_error_return (0, "classify table-index must be specified");
3228
3229 if (sw_if_index == ~0)
3230 return clib_error_return (0, "interface / subif must be specified");
3231
3232 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3233
3234 switch (rv)
3235 {
3236 case 0:
3237 break;
3238
3239 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3240 return clib_error_return (0, "No such interface");
3241
3242 case VNET_API_ERROR_NO_SUCH_ENTRY:
3243 return clib_error_return (0, "No such classifier table");
3244 }
3245 return 0;
3246}
3247
Billy McFall0683c9c2016-10-13 08:27:31 -04003248/*?
3249 * Assign a classification table to an interface. The classification
3250 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3251 * commands. Once the table is create, use this command to filter packets
3252 * on an interface.
3253 *
3254 * @cliexpar
3255 * Example of how to assign a classification table to an interface:
3256 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3257?*/
3258/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003259VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3260{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003261 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003262 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003263 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003264 .function = set_ip_classify_command_fn,
3265};
Billy McFall0683c9c2016-10-13 08:27:31 -04003266/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003267
3268/*
3269 * fd.io coding-style-patch-verification: ON
3270 *
3271 * Local Variables:
3272 * eval: (c-set-style "gnu")
3273 * End:
3274 */