blob: ee17ea8804efc2629151e04b96a3aaf362ca79a7 [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>
Neale Rannsf12a83f2017-04-18 09:09:40 -070052#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010053#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000054#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070055
Billy McFall0683c9c2016-10-13 08:27:31 -040056/**
57 * @file
58 * @brief IPv4 Forwarding.
59 *
60 * This file contains the source code for IPv4 forwarding.
61 */
62
Pierre Pfister0febaf12016-06-08 12:23:21 +010063void
64ip4_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050065 vlib_node_runtime_t * node,
66 vlib_frame_t * frame,
67 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010068
Ed Warnickecb9cada2015-12-08 15:45:58 -070069always_inline uword
70ip4_lookup_inline (vlib_main_t * vm,
71 vlib_node_runtime_t * node,
72 vlib_frame_t * frame,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010073 int lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -070074{
Dave Barachd7cb1b52016-12-09 09:52:16 -050075 ip4_main_t *im = &ip4_main;
76 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
77 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070078 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020079 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070080
81 from = vlib_frame_vector_args (frame);
82 n_left_from = frame->n_vectors;
83 next = node->cached_next_index;
84
85 while (n_left_from > 0)
86 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050087 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070088
Dave Barach670909e2016-10-18 15:25:35 -040089 while (n_left_from >= 8 && n_left_to_next >= 4)
Dave Barachd7cb1b52016-12-09 09:52:16 -050090 {
91 vlib_buffer_t *p0, *p1, *p2, *p3;
92 ip4_header_t *ip0, *ip1, *ip2, *ip3;
Dave Barachd7cb1b52016-12-09 09:52:16 -050093 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;
Neale Ranns340690e2017-03-22 13:27:53 -070098 u32 pi0, fib_index0, lb_index0;
99 u32 pi1, fib_index1, lb_index1;
100 u32 pi2, fib_index2, lb_index2;
101 u32 pi3, fib_index3, lb_index3;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500102 flow_hash_config_t flow_hash_config0, flow_hash_config1;
103 flow_hash_config_t flow_hash_config2, flow_hash_config3;
104 u32 hash_c0, hash_c1, hash_c2, hash_c3;
Dave Barach670909e2016-10-18 15:25:35 -0400105 const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106
Dave Barachd7cb1b52016-12-09 09:52:16 -0500107 /* Prefetch next iteration. */
108 {
109 vlib_buffer_t *p4, *p5, *p6, *p7;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110
Dave Barachd7cb1b52016-12-09 09:52:16 -0500111 p4 = vlib_get_buffer (vm, from[4]);
112 p5 = vlib_get_buffer (vm, from[5]);
113 p6 = vlib_get_buffer (vm, from[6]);
114 p7 = vlib_get_buffer (vm, from[7]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
Dave Barachd7cb1b52016-12-09 09:52:16 -0500116 vlib_prefetch_buffer_header (p4, LOAD);
117 vlib_prefetch_buffer_header (p5, LOAD);
118 vlib_prefetch_buffer_header (p6, LOAD);
119 vlib_prefetch_buffer_header (p7, LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Dave Barachd7cb1b52016-12-09 09:52:16 -0500121 CLIB_PREFETCH (p4->data, sizeof (ip0[0]), LOAD);
122 CLIB_PREFETCH (p5->data, sizeof (ip0[0]), LOAD);
123 CLIB_PREFETCH (p6->data, sizeof (ip0[0]), LOAD);
124 CLIB_PREFETCH (p7->data, sizeof (ip0[0]), LOAD);
125 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Dave Barachd7cb1b52016-12-09 09:52:16 -0500127 pi0 = to_next[0] = from[0];
128 pi1 = to_next[1] = from[1];
129 pi2 = to_next[2] = from[2];
130 pi3 = to_next[3] = from[3];
Dave Barach670909e2016-10-18 15:25:35 -0400131
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 from += 4;
133 to_next += 4;
134 n_left_to_next -= 4;
135 n_left_from -= 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
Dave Barachd7cb1b52016-12-09 09:52:16 -0500137 p0 = vlib_get_buffer (vm, pi0);
138 p1 = vlib_get_buffer (vm, pi1);
139 p2 = vlib_get_buffer (vm, pi2);
140 p3 = vlib_get_buffer (vm, pi3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
Dave Barachd7cb1b52016-12-09 09:52:16 -0500142 ip0 = vlib_buffer_get_current (p0);
143 ip1 = vlib_buffer_get_current (p1);
144 ip2 = vlib_buffer_get_current (p2);
145 ip3 = vlib_buffer_get_current (p3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Dave Barachd7cb1b52016-12-09 09:52:16 -0500147 dst_addr0 = &ip0->dst_address;
148 dst_addr1 = &ip1->dst_address;
149 dst_addr2 = &ip2->dst_address;
150 dst_addr3 = &ip3->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200151
Dave Barachd7cb1b52016-12-09 09:52:16 -0500152 fib_index0 =
153 vec_elt (im->fib_index_by_sw_if_index,
154 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
155 fib_index1 =
156 vec_elt (im->fib_index_by_sw_if_index,
157 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
158 fib_index2 =
159 vec_elt (im->fib_index_by_sw_if_index,
160 vnet_buffer (p2)->sw_if_index[VLIB_RX]);
161 fib_index3 =
162 vec_elt (im->fib_index_by_sw_if_index,
163 vnet_buffer (p3)->sw_if_index[VLIB_RX]);
164 fib_index0 =
165 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
166 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
167 fib_index1 =
168 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
169 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
170 fib_index2 =
171 (vnet_buffer (p2)->sw_if_index[VLIB_TX] ==
172 (u32) ~ 0) ? fib_index2 : vnet_buffer (p2)->sw_if_index[VLIB_TX];
173 fib_index3 =
174 (vnet_buffer (p3)->sw_if_index[VLIB_TX] ==
175 (u32) ~ 0) ? fib_index3 : vnet_buffer (p3)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
177
Dave Barachd7cb1b52016-12-09 09:52:16 -0500178 if (!lookup_for_responses_to_locally_received_packets)
179 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100180 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
181 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Dave Barach670909e2016-10-18 15:25:35 -0400182 mtrie2 = &ip4_fib_get (fib_index2)->mtrie;
183 mtrie3 = &ip4_fib_get (fib_index3)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184
Neale Ranns04a75e32017-03-23 06:46:01 -0700185 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, dst_addr0);
186 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, dst_addr1);
187 leaf2 = ip4_fib_mtrie_lookup_step_one (mtrie2, dst_addr2);
188 leaf3 = ip4_fib_mtrie_lookup_step_one (mtrie3, dst_addr3);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barachd7cb1b52016-12-09 09:52:16 -0500191 if (!lookup_for_responses_to_locally_received_packets)
192 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500193 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
194 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
195 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 2);
196 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 2);
197 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198
Dave Barachd7cb1b52016-12-09 09:52:16 -0500199 if (!lookup_for_responses_to_locally_received_packets)
200 {
201 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
202 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
203 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 3);
204 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 3);
205 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206
Dave Barachd7cb1b52016-12-09 09:52:16 -0500207 if (lookup_for_responses_to_locally_received_packets)
208 {
209 lb_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
210 lb_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
211 lb_index2 = vnet_buffer (p2)->ip.adj_index[VLIB_RX];
212 lb_index3 = vnet_buffer (p3)->ip.adj_index[VLIB_RX];
213 }
214 else
215 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500216 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
217 lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
218 lb_index2 = ip4_fib_mtrie_leaf_get_adj_index (leaf2);
219 lb_index3 = ip4_fib_mtrie_leaf_get_adj_index (leaf3);
220 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
Neale Ranns04a75e32017-03-23 06:46:01 -0700222 ASSERT (lb_index0 && lb_index1 && lb_index2 && lb_index3);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100223 lb0 = load_balance_get (lb_index0);
224 lb1 = load_balance_get (lb_index1);
Dave Barach670909e2016-10-18 15:25:35 -0400225 lb2 = load_balance_get (lb_index2);
226 lb3 = load_balance_get (lb_index3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
Neale Rannsf12a83f2017-04-18 09:09:40 -0700228 ASSERT (lb0->lb_n_buckets > 0);
229 ASSERT (is_pow2 (lb0->lb_n_buckets));
230 ASSERT (lb1->lb_n_buckets > 0);
231 ASSERT (is_pow2 (lb1->lb_n_buckets));
232 ASSERT (lb2->lb_n_buckets > 0);
233 ASSERT (is_pow2 (lb2->lb_n_buckets));
234 ASSERT (lb3->lb_n_buckets > 0);
235 ASSERT (is_pow2 (lb3->lb_n_buckets));
236
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 /* Use flow hash to compute multipath adjacency. */
238 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
239 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
240 hash_c2 = vnet_buffer (p2)->ip.flow_hash = 0;
241 hash_c3 = vnet_buffer (p3)->ip.flow_hash = 0;
242 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
243 {
244 flow_hash_config0 = lb0->lb_hash_config;
245 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
246 ip4_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700247 dpo0 =
248 load_balance_get_fwd_bucket (lb0,
249 (hash_c0 &
250 (lb0->lb_n_buckets_minus_1)));
251 }
252 else
253 {
254 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500255 }
256 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
257 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100258 flow_hash_config1 = lb1->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500259 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
260 ip4_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700261 dpo1 =
262 load_balance_get_fwd_bucket (lb1,
263 (hash_c1 &
264 (lb1->lb_n_buckets_minus_1)));
265 }
266 else
267 {
268 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500269 }
270 if (PREDICT_FALSE (lb2->lb_n_buckets > 1))
271 {
272 flow_hash_config2 = lb2->lb_hash_config;
273 hash_c2 = vnet_buffer (p2)->ip.flow_hash =
274 ip4_compute_flow_hash (ip2, flow_hash_config2);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700275 dpo2 =
276 load_balance_get_fwd_bucket (lb2,
277 (hash_c2 &
278 (lb2->lb_n_buckets_minus_1)));
279 }
280 else
281 {
282 dpo2 = load_balance_get_bucket_i (lb2, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500283 }
284 if (PREDICT_FALSE (lb3->lb_n_buckets > 1))
285 {
Dave Barach670909e2016-10-18 15:25:35 -0400286 flow_hash_config3 = lb3->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500287 hash_c3 = vnet_buffer (p3)->ip.flow_hash =
288 ip4_compute_flow_hash (ip3, flow_hash_config3);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700289 dpo3 =
290 load_balance_get_fwd_bucket (lb3,
291 (hash_c3 &
292 (lb3->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700294 else
295 {
296 dpo3 = load_balance_get_bucket_i (lb3, 0);
297 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100299 next0 = dpo0->dpoi_next_node;
300 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
301 next1 = dpo1->dpoi_next_node;
302 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Dave Barach670909e2016-10-18 15:25:35 -0400303 next2 = dpo2->dpoi_next_node;
304 vnet_buffer (p2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
305 next3 = dpo3->dpoi_next_node;
306 vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200307
Dave Barachd7cb1b52016-12-09 09:52:16 -0500308 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200309 (cm, thread_index, lb_index0, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700310 vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500311 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200312 (cm, thread_index, lb_index1, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700313 vlib_buffer_length_in_chain (vm, p1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500314 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200315 (cm, thread_index, lb_index2, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700316 vlib_buffer_length_in_chain (vm, p2));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200318 (cm, thread_index, lb_index3, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700319 vlib_buffer_length_in_chain (vm, p3));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320
Dave Barach670909e2016-10-18 15:25:35 -0400321 vlib_validate_buffer_enqueue_x4 (vm, node, next,
322 to_next, n_left_to_next,
323 pi0, pi1, pi2, pi3,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500324 next0, next1, next2, next3);
325 }
Dave Barach75fc8542016-10-11 16:16:02 -0400326
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327 while (n_left_from > 0 && n_left_to_next > 0)
328 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329 vlib_buffer_t *p0;
330 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700331 ip_lookup_next_t next0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100332 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500333 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 ip4_fib_mtrie_leaf_t leaf0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500335 ip4_address_t *dst_addr0;
Neale Ranns340690e2017-03-22 13:27:53 -0700336 u32 pi0, fib_index0, lbi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500337 flow_hash_config_t flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100338 const dpo_id_t *dpo0;
339 u32 hash_c0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
341 pi0 = from[0];
342 to_next[0] = pi0;
343
344 p0 = vlib_get_buffer (vm, pi0);
345
346 ip0 = vlib_buffer_get_current (p0);
347
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100348 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200349
Dave Barachd7cb1b52016-12-09 09:52:16 -0500350 fib_index0 =
351 vec_elt (im->fib_index_by_sw_if_index,
352 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
353 fib_index0 =
354 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
355 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356
Dave Barachd7cb1b52016-12-09 09:52:16 -0500357 if (!lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500359 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360
Neale Ranns04a75e32017-03-23 06:46:01 -0700361 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362 }
363
Dave Barachd7cb1b52016-12-09 09:52:16 -0500364 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200365 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
Dave Barachd7cb1b52016-12-09 09:52:16 -0500367 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200368 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369
370 if (lookup_for_responses_to_locally_received_packets)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100371 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372 else
373 {
374 /* Handle default route. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 }
377
Neale Ranns04a75e32017-03-23 06:46:01 -0700378 ASSERT (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100379 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380
Neale Rannsf12a83f2017-04-18 09:09:40 -0700381 ASSERT (lb0->lb_n_buckets > 0);
382 ASSERT (is_pow2 (lb0->lb_n_buckets));
383
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 /* Use flow hash to compute multipath adjacency. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500385 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
386 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
387 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100388 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389
Dave Barachd7cb1b52016-12-09 09:52:16 -0500390 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
391 ip4_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700392 dpo0 =
393 load_balance_get_fwd_bucket (lb0,
394 (hash_c0 &
395 (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500396 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700397 else
398 {
399 dpo0 = load_balance_get_bucket_i (lb0, 0);
400 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100402 next0 = dpo0->dpoi_next_node;
403 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200404
Neale Rannsf12a83f2017-04-18 09:09:40 -0700405 vlib_increment_combined_counter (cm, thread_index, lbi0, 1,
406 vlib_buffer_length_in_chain (vm,
407 p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408
409 from += 1;
410 to_next += 1;
411 n_left_to_next -= 1;
412 n_left_from -= 1;
413
414 if (PREDICT_FALSE (next0 != next))
415 {
416 n_left_to_next += 1;
417 vlib_put_next_frame (vm, node, next, n_left_to_next);
418 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500419 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 to_next[0] = pi0;
421 to_next += 1;
422 n_left_to_next -= 1;
423 }
424 }
425
426 vlib_put_next_frame (vm, node, next, n_left_to_next);
427 }
428
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100429 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500430 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100431
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432 return frame->n_vectors;
433}
434
Chris Luke8e5b0412016-07-26 13:06:10 -0400435/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -0400436 @node ip4-lookup
437
438 This is the main IPv4 lookup dispatch node.
439
440 @param vm vlib_main_t corresponding to the current thread
441 @param node vlib_node_runtime_t
442 @param frame vlib_frame_t whose contents should be dispatched
443
444 @par Graph mechanics: buffer metadata, next index usage
445
446 @em Uses:
447 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
448 - Indicates the @c sw_if_index value of the interface that the
449 packet was received on.
450 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
451 - When the value is @c ~0 then the node performs a longest prefix
452 match (LPM) for the packet destination address in the FIB attached
453 to the receive interface.
454 - Otherwise perform LPM for the packet destination address in the
455 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
456 value (0, 1, ...) and not a VRF id.
457
458 @em Sets:
459 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
460 - The lookup result adjacency index.
461
462 <em>Next Index:</em>
463 - Dispatches the packet to the node index found in
464 ip_adjacency_t @c adj->lookup_next_index
465 (where @c adj is the lookup result adjacency).
466*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467static uword
468ip4_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500469 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470{
Damjan Marionaca64c92016-04-13 09:48:56 +0200471 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 /* lookup_for_responses_to_locally_received_packets */
473 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474
475}
476
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100478
Dave Barachd7cb1b52016-12-09 09:52:16 -0500479VLIB_REGISTER_NODE (ip4_lookup_node) =
480{
481.function = ip4_lookup,.name = "ip4-lookup",.vector_size =
482 sizeof (u32),.format_trace = format_ip4_lookup_trace,.n_next_nodes =
483 IP_LOOKUP_N_NEXT,.next_nodes = IP4_LOOKUP_NEXT_NODES,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484
Dave Barachd7cb1b52016-12-09 09:52:16 -0500485VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100486
487always_inline uword
488ip4_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500489 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500491 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
492 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100493 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200494 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100496 from = vlib_frame_vector_args (frame);
497 n_left_from = frame->n_vectors;
498 next = node->cached_next_index;
499
500 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500501 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100502
503 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700504 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100506
Dave Barach75fc8542016-10-11 16:16:02 -0400507
Neale Ranns2be95c12016-11-19 13:50:04 +0000508 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500509 {
510 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000511 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500512 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000513 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
514 const ip4_header_t *ip0, *ip1;
515 const dpo_id_t *dpo0, *dpo1;
516
Dave Barachd7cb1b52016-12-09 09:52:16 -0500517 /* Prefetch next iteration. */
518 {
519 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000520
521 p2 = vlib_get_buffer (vm, from[2]);
522 p3 = vlib_get_buffer (vm, from[3]);
523
524 vlib_prefetch_buffer_header (p2, STORE);
525 vlib_prefetch_buffer_header (p3, STORE);
526
527 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
528 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000530
531 pi0 = to_next[0] = from[0];
532 pi1 = to_next[1] = from[1];
533
534 from += 2;
535 n_left_from -= 2;
536 to_next += 2;
537 n_left_to_next -= 2;
538
539 p0 = vlib_get_buffer (vm, pi0);
540 p1 = vlib_get_buffer (vm, pi1);
541
542 ip0 = vlib_buffer_get_current (p0);
543 ip1 = vlib_buffer_get_current (p1);
544 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
545 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
546
Dave Barachd7cb1b52016-12-09 09:52:16 -0500547 lb0 = load_balance_get (lbi0);
548 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000549
Dave Barachd7cb1b52016-12-09 09:52:16 -0500550 /*
551 * this node is for via FIBs we can re-use the hash value from the
552 * to node if present.
553 * We don't want to use the same hash value at each level in the recursion
554 * graph as that would lead to polarisation
555 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000556 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000557
Dave Barachd7cb1b52016-12-09 09:52:16 -0500558 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
559 {
560 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
561 {
562 hc0 = vnet_buffer (p0)->ip.flow_hash =
563 vnet_buffer (p0)->ip.flow_hash >> 1;
564 }
565 else
566 {
567 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000568 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500569 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700570 dpo0 = load_balance_get_fwd_bucket
571 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
572 }
573 else
574 {
575 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500576 }
577 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
578 {
579 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
580 {
581 hc1 = vnet_buffer (p1)->ip.flow_hash =
582 vnet_buffer (p1)->ip.flow_hash >> 1;
583 }
584 else
585 {
586 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000587 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700589 dpo1 = load_balance_get_fwd_bucket
590 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500591 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700592 else
593 {
594 dpo1 = load_balance_get_bucket_i (lb1, 0);
595 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000596
597 next0 = dpo0->dpoi_next_node;
598 next1 = dpo1->dpoi_next_node;
599
600 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
601 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
602
603 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200604 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000605 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200606 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000607
608 vlib_validate_buffer_enqueue_x2 (vm, node, next,
609 to_next, n_left_to_next,
610 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500611 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000612
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100613 while (n_left_from > 0 && n_left_to_next > 0)
614 {
615 ip_lookup_next_t next0;
616 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500617 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100618 u32 pi0, lbi0, hc0;
619 const ip4_header_t *ip0;
620 const dpo_id_t *dpo0;
621
622 pi0 = from[0];
623 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000624 from += 1;
625 to_next += 1;
626 n_left_to_next -= 1;
627 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628
629 p0 = vlib_get_buffer (vm, pi0);
630
631 ip0 = vlib_buffer_get_current (p0);
632 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
633
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100635
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000636 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500637 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
638 {
639 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
640 {
641 hc0 = vnet_buffer (p0)->ip.flow_hash =
642 vnet_buffer (p0)->ip.flow_hash >> 1;
643 }
644 else
645 {
646 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000647 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500648 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700649 dpo0 = load_balance_get_fwd_bucket
650 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500651 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700652 else
653 {
654 dpo0 = load_balance_get_bucket_i (lb0, 0);
655 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656
657 next0 = dpo0->dpoi_next_node;
658 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
659
Dave Barach75fc8542016-10-11 16:16:02 -0400660 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200661 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100662
Neale Ranns2be95c12016-11-19 13:50:04 +0000663 vlib_validate_buffer_enqueue_x1 (vm, node, next,
664 to_next, n_left_to_next,
665 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100666 }
667
668 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669 }
670
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100671 return frame->n_vectors;
672}
673
Dave Barachd7cb1b52016-12-09 09:52:16 -0500674VLIB_REGISTER_NODE (ip4_load_balance_node) =
675{
676.function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
677 sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
678 format_ip4_lookup_trace,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100679
Dave Barachd7cb1b52016-12-09 09:52:16 -0500680VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100681
682/* get first interface address */
683ip4_address_t *
684ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500685 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100686{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687 ip_lookup_main_t *lm = &im->lookup_main;
688 ip_interface_address_t *ia = 0;
689 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690
Neale Ranns32e1c012016-11-22 17:07:28 +0000691 /* *INDENT-OFF* */
692 foreach_ip_interface_address
693 (lm, ia, sw_if_index,
694 1 /* honor unnumbered */ ,
695 ({
696 ip4_address_t * a =
697 ip_interface_address_get_address (lm, ia);
698 result = a;
699 break;
700 }));
701 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100702 if (result_ia)
703 *result_ia = result ? ia : 0;
704 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705}
706
707static void
708ip4_add_interface_routes (u32 sw_if_index,
709 ip4_main_t * im, u32 fib_index,
710 ip_interface_address_t * a)
711{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500712 ip_lookup_main_t *lm = &im->lookup_main;
713 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100714 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500715 .fp_len = a->address_length,
716 .fp_proto = FIB_PROTOCOL_IP4,
717 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100718 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
Neale Ranns9a69a602017-03-26 10:56:33 -0700720 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500721 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700722 /* a /30 or shorter - add a glean for the network address */
Neale Ranns7a272742017-05-30 02:08:14 -0700723 fib_table_entry_update_one_path (fib_index, &pfx,
724 FIB_SOURCE_INTERFACE,
725 (FIB_ENTRY_FLAG_CONNECTED |
726 FIB_ENTRY_FLAG_ATTACHED),
727 FIB_PROTOCOL_IP4,
728 /* No next-hop address */
729 NULL,
730 sw_if_index,
731 // invalid FIB index
732 ~0,
733 1,
734 // no out-label stack
735 NULL,
736 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100737
Neale Ranns9a69a602017-03-26 10:56:33 -0700738 /* Add the two broadcast addresses as drop */
739 fib_prefix_t net_pfx = {
740 .fp_len = 32,
741 .fp_proto = FIB_PROTOCOL_IP4,
742 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
743 };
744 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
745 fib_table_entry_special_add(fib_index,
746 &net_pfx,
747 FIB_SOURCE_INTERFACE,
748 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700749 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700750 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
751 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
752 fib_table_entry_special_add(fib_index,
753 &net_pfx,
754 FIB_SOURCE_INTERFACE,
755 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700756 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700757 }
758 else if (pfx.fp_len == 31)
759 {
760 u32 mask = clib_host_to_net_u32(1);
761 fib_prefix_t net_pfx = pfx;
762
763 net_pfx.fp_len = 32;
764 net_pfx.fp_addr.ip4.as_u32 ^= mask;
765
766 /* a /31 - add the other end as an attached host */
767 fib_table_entry_update_one_path (fib_index, &net_pfx,
768 FIB_SOURCE_INTERFACE,
769 (FIB_ENTRY_FLAG_ATTACHED),
770 FIB_PROTOCOL_IP4,
771 &net_pfx.fp_addr,
772 sw_if_index,
773 // invalid FIB index
774 ~0,
775 1,
776 NULL,
777 FIB_ROUTE_PATH_FLAG_NONE);
778 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100779 pfx.fp_len = 32;
780
781 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100783 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 lm->classify_table_index_by_sw_if_index[sw_if_index];
785 if (classify_table_index != (u32) ~ 0)
786 {
787 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100788
Dave Barachd7cb1b52016-12-09 09:52:16 -0500789 dpo_set (&dpo,
790 DPO_CLASSIFY,
791 DPO_PROTO_IP4,
792 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100793
Dave Barachd7cb1b52016-12-09 09:52:16 -0500794 fib_table_entry_special_dpo_add (fib_index,
795 &pfx,
796 FIB_SOURCE_CLASSIFY,
797 FIB_ENTRY_FLAG_NONE, &dpo);
798 dpo_reset (&dpo);
799 }
800 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100801
Neale Ranns32e1c012016-11-22 17:07:28 +0000802 fib_table_entry_update_one_path (fib_index, &pfx,
803 FIB_SOURCE_INTERFACE,
804 (FIB_ENTRY_FLAG_CONNECTED |
805 FIB_ENTRY_FLAG_LOCAL),
806 FIB_PROTOCOL_IP4,
807 &pfx.fp_addr,
808 sw_if_index,
809 // invalid FIB index
810 ~0,
811 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813}
814
815static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100816ip4_del_interface_routes (ip4_main_t * im,
817 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500818 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700819{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500820 fib_prefix_t pfx = {
821 .fp_len = address_length,
822 .fp_proto = FIB_PROTOCOL_IP4,
823 .fp_addr.ip4 = *address,
824 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825
Neale Ranns9a69a602017-03-26 10:56:33 -0700826 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100827 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700828 fib_prefix_t net_pfx = {
829 .fp_len = 32,
830 .fp_proto = FIB_PROTOCOL_IP4,
831 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
832 };
833 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
834 fib_table_entry_special_remove(fib_index,
835 &net_pfx,
836 FIB_SOURCE_INTERFACE);
837 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
838 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
839 fib_table_entry_special_remove(fib_index,
840 &net_pfx,
841 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500842 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100843 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700844 else if (pfx.fp_len == 31)
845 {
846 u32 mask = clib_host_to_net_u32(1);
847 fib_prefix_t net_pfx = pfx;
848
849 net_pfx.fp_len = 32;
850 net_pfx.fp_addr.ip4.as_u32 ^= mask;
851
852 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
853 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854
Dave Barachd7cb1b52016-12-09 09:52:16 -0500855 pfx.fp_len = 32;
856 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857}
858
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100859void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500860ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100861{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100864 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
865
866 /*
867 * enable/disable only on the 1<->0 transition
868 */
869 if (is_enable)
870 {
871 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500872 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100873 }
874 else
875 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500876 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100877 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500878 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100879 }
Damjan Marion4d489932016-12-09 03:21:27 -0800880 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
881 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100882
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100883
Neale Ranns180279b2017-03-16 15:49:09 -0400884 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop",
885 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100886}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700887
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888static clib_error_t *
889ip4_add_del_interface_address_internal (vlib_main_t * vm,
890 u32 sw_if_index,
891 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500892 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500894 vnet_main_t *vnm = vnet_get_main ();
895 ip4_main_t *im = &ip4_main;
896 ip_lookup_main_t *lm = &im->lookup_main;
897 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500899 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900
Pavel Kotucek57808982017-08-02 08:20:19 +0200901 /* local0 interface doesn't support IP addressing */
902 if (sw_if_index == 0)
903 {
904 return
905 clib_error_create ("local0 interface doesn't support IP addressing");
906 }
907
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
909 ip4_addr_fib_init (&ip4_af, address,
910 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
911 vec_add1 (addr_fib, ip4_af);
912
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100913 /* FIXME-LATER
914 * there is no support for adj-fib handling in the presence of overlapping
915 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
916 * most routers do.
917 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000918 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500919 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100921 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922 with an existing address. */
923 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000924 foreach_ip_interface_address
925 (&im->lookup_main, ia, sw_if_index,
926 0 /* honor unnumbered */ ,
927 ({
928 ip4_address_t * x =
929 ip_interface_address_get_address
930 (&im->lookup_main, ia);
931 if (ip4_destination_matches_route
932 (im, address, x, ia->address_length) ||
933 ip4_destination_matches_route (im,
934 x,
935 address,
936 address_length))
937 return
938 clib_error_create
939 ("failed to add %U which conflicts with %U for interface %U",
940 format_ip4_address_and_length, address,
941 address_length,
942 format_ip4_address_and_length, x,
943 ia->address_length,
944 format_vnet_sw_if_index_name, vnm,
945 sw_if_index);
946 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000948 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949
Ed Warnickecb9cada2015-12-08 15:45:58 -0700950 elts_before = pool_elts (lm->if_address_pool);
951
952 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500953 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954 if (error)
955 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400956
Dave Barachd7cb1b52016-12-09 09:52:16 -0500957 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958
959 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100961 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500962 ip4_add_interface_routes (sw_if_index,
963 im, ip4_af.fib_index,
964 pool_elt_at_index
965 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966
967 /* If pool did not grow/shrink: add duplicate address. */
968 if (elts_before != pool_elts (lm->if_address_pool))
969 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500970 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 vec_foreach (cb, im->add_del_interface_address_callbacks)
972 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500973 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974 }
975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977 vec_free (addr_fib);
978 return error;
979}
980
981clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000982ip4_add_del_interface_address (vlib_main_t * vm,
983 u32 sw_if_index,
984 ip4_address_t * address,
985 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986{
987 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500988 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989}
990
Dave Barachd6534602016-06-14 18:38:02 -0400991/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500992/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100993VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
994{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100996 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
997 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
998};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100999
Dave Barachd7cb1b52016-12-09 09:52:16 -05001000VNET_FEATURE_INIT (ip4_flow_classify, static) =
1001{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001002 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -07001003 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001004 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -07001005};
1006
Dave Barachd7cb1b52016-12-09 09:52:16 -05001007VNET_FEATURE_INIT (ip4_inacl, static) =
1008{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001009 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -04001010 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001011 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -04001012};
1013
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014VNET_FEATURE_INIT (ip4_source_check_1, static) =
1015{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001016 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001017 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001018 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -04001019};
1020
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021VNET_FEATURE_INIT (ip4_source_check_2, static) =
1022{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001023 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001024 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001025 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -04001026};
1027
Dave Barachd7cb1b52016-12-09 09:52:16 -05001028VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
1029{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -04001031 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001032 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -04001033};
1034
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035VNET_FEATURE_INIT (ip4_policer_classify, static) =
1036{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001037 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001038 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001039 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001040};
1041
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042VNET_FEATURE_INIT (ip4_ipsec, static) =
1043{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001044 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001045 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001046 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -04001047};
1048
Dave Barachd7cb1b52016-12-09 09:52:16 -05001049VNET_FEATURE_INIT (ip4_vpath, static) =
1050{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001051 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001052 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -05001053 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1054};
1055
Dave Barachd7cb1b52016-12-09 09:52:16 -05001056VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1057{
John Lo37682e12016-11-30 12:51:39 -05001058 .arc_name = "ip4-unicast",
1059 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001060 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001061};
1062
Dave Barachd7cb1b52016-12-09 09:52:16 -05001063VNET_FEATURE_INIT (ip4_drop, static) =
1064{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001065 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001066 .node_name = "ip4-drop",
Neale Ranns180279b2017-03-16 15:49:09 -04001067 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001068};
1069
Neale Ranns180279b2017-03-16 15:49:09 -04001070VNET_FEATURE_INIT (ip4_lookup, static) =
1071{
1072 .arc_name = "ip4-unicast",
1073 .node_name = "ip4-lookup",
1074 .runs_before = 0, /* not before any other features */
1075};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001076
Dave Barachd6534602016-06-14 18:38:02 -04001077/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001078VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1079{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001080 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001081 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
1082 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1083};
1084
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1086{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001087 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001088 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001089 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001090};
1091
Dave Barachd7cb1b52016-12-09 09:52:16 -05001092VNET_FEATURE_INIT (ip4_mc_drop, static) =
1093{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001094 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001095 .node_name = "ip4-drop",
Neale Ranns180279b2017-03-16 15:49:09 -04001096 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1097};
1098
1099VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1100{
1101 .arc_name = "ip4-multicast",
1102 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001103 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001104};
Dave Barach5331c722016-08-17 11:54:30 -04001105
1106/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001107VNET_FEATURE_ARC_INIT (ip4_output, static) =
1108{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001110 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion8b3191e2016-11-09 19:54:20 +01001111 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1112};
Dave Barach5331c722016-08-17 11:54:30 -04001113
Dave Barachd7cb1b52016-12-09 09:52:16 -05001114VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1115{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001116 .arc_name = "ip4-output",
1117 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001118 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1119};
1120
Dave Barachd7cb1b52016-12-09 09:52:16 -05001121VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1122{
Matus Fabian08a6f012016-11-15 06:08:51 -08001123 .arc_name = "ip4-output",
1124 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001125 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001126};
1127
1128/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001129VNET_FEATURE_INIT (ip4_interface_output, static) =
1130{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001131 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001132 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001134};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001135/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001136
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001138ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001140 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001142 /* Fill in lookup tables with default table (0). */
1143 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001144 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001145
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001146 if (!is_add)
1147 {
1148 ip4_main_t *im4 = &ip4_main;
1149 ip_lookup_main_t *lm4 = &im4->lookup_main;
1150 ip_interface_address_t *ia = 0;
1151 ip4_address_t *address;
1152 vlib_main_t *vm = vlib_get_main ();
1153
1154 /* *INDENT-OFF* */
1155 foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* honor unnumbered */,
1156 ({
1157 address = ip_interface_address_get_address (lm4, ia);
1158 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1159 }));
1160 /* *INDENT-ON* */
1161 }
1162
Damjan Marion8b3191e2016-11-09 19:54:20 +01001163 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1164 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165
Damjan Marion8b3191e2016-11-09 19:54:20 +01001166 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1167 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169 return /* no error */ 0;
1170}
1171
1172VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1173
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174/* Global IP4 main. */
1175ip4_main_t ip4_main;
1176
1177clib_error_t *
1178ip4_lookup_init (vlib_main_t * vm)
1179{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001180 ip4_main_t *im = &ip4_main;
1181 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 uword i;
1183
Damjan Marion8b3191e2016-11-09 19:54:20 +01001184 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1185 return error;
1186
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1188 {
1189 u32 m;
1190
1191 if (i < 32)
1192 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001193 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194 m = ~0;
1195 im->fib_masks[i] = clib_host_to_net_u32 (m);
1196 }
1197
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1199
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001200 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001201 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001202 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001203
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001205 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001206 pn = pg_get_node (ip4_lookup_node.index);
1207 pn->unformat_edit = unformat_pg_ip4_header;
1208 }
1209
1210 {
1211 ethernet_arp_header_t h;
1212
1213 memset (&h, 0, sizeof (h));
1214
1215 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001216 memset (h.ip4_over_ethernet[1].ethernet, 0,
1217 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001218
1219#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1220#define _8(f,v) h.f = v;
1221 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1222 _16 (l3_type, ETHERNET_TYPE_IP4);
1223 _8 (n_l2_address_bytes, 6);
1224 _8 (n_l3_address_bytes, 4);
1225 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1226#undef _16
1227#undef _8
1228
Dave Barachd7cb1b52016-12-09 09:52:16 -05001229 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001230 /* data */ &h,
1231 sizeof (h),
1232 /* alloc chunk size */ 8,
1233 "ip4 arp");
1234 }
1235
Dave Barach203c6322016-06-26 10:29:03 -04001236 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237}
1238
1239VLIB_INIT_FUNCTION (ip4_lookup_init);
1240
Dave Barachd7cb1b52016-12-09 09:52:16 -05001241typedef struct
1242{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001244 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245 u32 flow_hash;
1246 u32 fib_index;
1247
1248 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001249 u8 packet_data[64 - 1 * sizeof (u32)];
1250}
1251ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001252
Dave Barachd7cb1b52016-12-09 09:52:16 -05001253u8 *
1254format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001255{
1256 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1257 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001258 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001259 uword indent = format_get_indent (s);
1260 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001261 format_white_space, indent,
1262 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001263 return s;
1264}
1265
Dave Barachd7cb1b52016-12-09 09:52:16 -05001266static u8 *
1267format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001268{
1269 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1270 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001271 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001272 uword indent = format_get_indent (s);
1273
John Loac8146c2016-09-27 17:44:02 -04001274 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001275 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001276 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001277 format_white_space, indent,
1278 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001279 return s;
1280}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281
Dave Barachd7cb1b52016-12-09 09:52:16 -05001282static u8 *
1283format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001284{
1285 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1286 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001287 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001288 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289
Vengada Govindanf1544482016-09-28 02:45:57 -07001290 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001291 t->fib_index, t->dpo_index, format_ip_adjacency,
1292 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001293 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001294 format_white_space, indent,
1295 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001296 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001297 return s;
1298}
1299
1300/* Common trace function for all ip4-forward next nodes. */
1301void
1302ip4_forward_next_trace (vlib_main_t * vm,
1303 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001304 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001306 u32 *from, n_left;
1307 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308
1309 n_left = frame->n_vectors;
1310 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001311
Ed Warnickecb9cada2015-12-08 15:45:58 -07001312 while (n_left >= 4)
1313 {
1314 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001315 vlib_buffer_t *b0, *b1;
1316 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001317
1318 /* Prefetch next iteration. */
1319 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1320 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1321
1322 bi0 = from[0];
1323 bi1 = from[1];
1324
1325 b0 = vlib_get_buffer (vm, bi0);
1326 b1 = vlib_get_buffer (vm, bi1);
1327
1328 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1329 {
1330 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001331 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001333 t0->fib_index =
1334 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1335 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1336 vec_elt (im->fib_index_by_sw_if_index,
1337 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001338
Damjan Marionf1213b82016-03-13 02:22:06 +01001339 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001340 vlib_buffer_get_current (b0),
1341 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342 }
1343 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1344 {
1345 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001346 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001348 t1->fib_index =
1349 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1350 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1351 vec_elt (im->fib_index_by_sw_if_index,
1352 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1353 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1354 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001355 }
1356 from += 2;
1357 n_left -= 2;
1358 }
1359
1360 while (n_left >= 1)
1361 {
1362 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001363 vlib_buffer_t *b0;
1364 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365
1366 bi0 = from[0];
1367
1368 b0 = vlib_get_buffer (vm, bi0);
1369
1370 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1371 {
1372 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001373 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001374 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001375 t0->fib_index =
1376 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1377 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1378 vec_elt (im->fib_index_by_sw_if_index,
1379 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1380 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1381 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382 }
1383 from += 1;
1384 n_left -= 1;
1385 }
1386}
1387
1388static uword
1389ip4_drop_or_punt (vlib_main_t * vm,
1390 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001391 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001393 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 uword n_packets = frame->n_vectors;
1395
Dave Barachd7cb1b52016-12-09 09:52:16 -05001396 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 /* stride */ 1,
1398 n_packets,
1399 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001400 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401
1402 if (node->flags & VLIB_NODE_FLAG_TRACE)
1403 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1404
1405 return n_packets;
1406}
1407
1408static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001409ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1410{
1411 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1412}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413
1414static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001415ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1416{
1417 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1418}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419
Neale Ranns32e1c012016-11-22 17:07:28 +00001420/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001421VLIB_REGISTER_NODE (ip4_drop_node, static) =
1422{
flyingeagle239e355522017-05-03 11:29:53 +08001423 .function = ip4_drop,
1424 .name = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00001425 .vector_size = sizeof (u32),
1426 .format_trace = format_ip4_forward_next_trace,
1427 .n_next_nodes = 1,
1428 .next_nodes = {
1429 [0] = "error-drop",
1430 },
1431};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432
Dave Barachd7cb1b52016-12-09 09:52:16 -05001433VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434
Dave Barachd7cb1b52016-12-09 09:52:16 -05001435VLIB_REGISTER_NODE (ip4_punt_node, static) =
1436{
Neale Ranns32e1c012016-11-22 17:07:28 +00001437 .function = ip4_punt,
1438 .name = "ip4-punt",
1439 .vector_size = sizeof (u32),
1440 .format_trace = format_ip4_forward_next_trace,
1441 .n_next_nodes = 1,
1442 .next_nodes = {
1443 [0] = "error-punt",
1444 },
1445};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001446
Dave Barachd7cb1b52016-12-09 09:52:16 -05001447VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Neale Ranns32e1c012016-11-22 17:07:28 +00001448/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02001449
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450/* Compute TCP/UDP/ICMP4 checksum in software. */
1451u16
1452ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1453 ip4_header_t * ip0)
1454{
1455 ip_csum_t sum0;
1456 u32 ip_header_length, payload_length_host_byte_order;
1457 u32 n_this_buffer, n_bytes_left;
1458 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001459 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001460
Ed Warnickecb9cada2015-12-08 15:45:58 -07001461 /* Initialize checksum with ip header. */
1462 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001463 payload_length_host_byte_order =
1464 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1465 sum0 =
1466 clib_host_to_net_u32 (payload_length_host_byte_order +
1467 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001468
1469 if (BITS (uword) == 32)
1470 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001471 sum0 =
1472 ip_csum_with_carry (sum0,
1473 clib_mem_unaligned (&ip0->src_address, u32));
1474 sum0 =
1475 ip_csum_with_carry (sum0,
1476 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001477 }
1478 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001479 sum0 =
1480 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001481
1482 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1483 data_this_buffer = (void *) ip0 + ip_header_length;
1484 if (n_this_buffer + ip_header_length > p0->current_length)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001485 n_this_buffer =
1486 p0->current_length >
1487 ip_header_length ? p0->current_length - ip_header_length : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488 while (1)
1489 {
1490 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1491 n_bytes_left -= n_this_buffer;
1492 if (n_bytes_left == 0)
1493 break;
1494
1495 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1496 p0 = vlib_get_buffer (vm, p0->next_buffer);
1497 data_this_buffer = vlib_buffer_get_current (p0);
1498 n_this_buffer = p0->current_length;
1499 }
1500
Dave Barachd7cb1b52016-12-09 09:52:16 -05001501 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001502
1503 return sum16;
1504}
1505
John Lo37682e12016-11-30 12:51:39 -05001506u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001507ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1508{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001509 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1510 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001511 u16 sum16;
1512
1513 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1514 || ip0->protocol == IP_PROTOCOL_UDP);
1515
1516 udp0 = (void *) (ip0 + 1);
1517 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1518 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001519 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1520 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001521 return p0->flags;
1522 }
1523
1524 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1525
Damjan Marion213b5aa2017-07-13 21:19:27 +02001526 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1527 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001528
1529 return p0->flags;
1530}
1531
Dave Barach68b0fb02017-02-28 15:15:56 -05001532/* *INDENT-OFF* */
1533VNET_FEATURE_ARC_INIT (ip4_local) =
1534{
1535 .arc_name = "ip4-local",
1536 .start_nodes = VNET_FEATURES ("ip4-local"),
1537};
1538/* *INDENT-ON* */
1539
1540static inline uword
1541ip4_local_inline (vlib_main_t * vm,
1542 vlib_node_runtime_t * node,
1543 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001544{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001545 ip4_main_t *im = &ip4_main;
1546 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001547 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001548 u32 *from, *to_next, n_left_from, n_left_to_next;
1549 vlib_node_runtime_t *error_node =
1550 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001551 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001552
1553 from = vlib_frame_vector_args (frame);
1554 n_left_from = frame->n_vectors;
1555 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001556
Ed Warnickecb9cada2015-12-08 15:45:58 -07001557 if (node->flags & VLIB_NODE_FLAG_TRACE)
1558 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1559
1560 while (n_left_from > 0)
1561 {
1562 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1563
1564 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001565 {
1566 vlib_buffer_t *p0, *p1;
1567 ip4_header_t *ip0, *ip1;
1568 udp_header_t *udp0, *udp1;
1569 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1570 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1571 const dpo_id_t *dpo0, *dpo1;
1572 const load_balance_t *lb0, *lb1;
1573 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1574 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1575 i32 len_diff0, len_diff1;
1576 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1577 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001578 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001579
Dave Barachd7cb1b52016-12-09 09:52:16 -05001580 pi0 = to_next[0] = from[0];
1581 pi1 = to_next[1] = from[1];
1582 from += 2;
1583 n_left_from -= 2;
1584 to_next += 2;
1585 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001586
Dave Barach68b0fb02017-02-28 15:15:56 -05001587 next0 = next1 = IP_LOCAL_NEXT_DROP;
1588
Ed Warnickecb9cada2015-12-08 15:45:58 -07001589 p0 = vlib_get_buffer (vm, pi0);
1590 p1 = vlib_get_buffer (vm, pi1);
1591
1592 ip0 = vlib_buffer_get_current (p0);
1593 ip1 = vlib_buffer_get_current (p1);
1594
Damjan Marion072401e2017-07-13 18:53:27 +02001595 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1596 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001597
Dave Barach68b0fb02017-02-28 15:15:56 -05001598 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1599 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1600
1601 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1602 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1603
1604 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001605 fib_index0 =
1606 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1607 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001608
Dave Barach68b0fb02017-02-28 15:15:56 -05001609 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001610 fib_index1 =
1611 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1612 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001614 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1615 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616
Neale Ranns04a75e32017-03-23 06:46:01 -07001617 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1618 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001619
John Lo3419d0b2016-06-02 09:28:37 -04001620 /* Treat IP frag packets as "experimental" protocol for now
1621 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001622 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1623 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001624
1625 if (head_of_feature_arc == 0)
1626 {
1627 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1628 goto skip_checks;
1629 }
1630
Ed Warnickecb9cada2015-12-08 15:45:58 -07001631 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1632 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1633 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1634 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1635
1636 flags0 = p0->flags;
1637 flags1 = p1->flags;
1638
Damjan Marion213b5aa2017-07-13 21:19:27 +02001639 good_tcp_udp0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1640 good_tcp_udp1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641
1642 udp0 = ip4_next_header (ip0);
1643 udp1 = ip4_next_header (ip1);
1644
1645 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1646 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1647 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1648
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649 /* Verify UDP length. */
1650 ip_len0 = clib_net_to_host_u16 (ip0->length);
1651 ip_len1 = clib_net_to_host_u16 (ip1->length);
1652 udp_len0 = clib_net_to_host_u16 (udp0->length);
1653 udp_len1 = clib_net_to_host_u16 (udp1->length);
1654
1655 len_diff0 = ip_len0 - udp_len0;
1656 len_diff1 = ip_len1 - udp_len1;
1657
1658 len_diff0 = is_udp0 ? len_diff0 : 0;
1659 len_diff1 = is_udp1 ? len_diff1 : 0;
1660
Dave Barachd7cb1b52016-12-09 09:52:16 -05001661 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1662 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663 {
1664 if (is_tcp_udp0)
1665 {
1666 if (is_tcp_udp0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001667 && !(flags0 & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001668 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1669 good_tcp_udp0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001670 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001671 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1672 }
1673 if (is_tcp_udp1)
1674 {
1675 if (is_tcp_udp1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001676 && !(flags1 & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001677 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1678 good_tcp_udp1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001679 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001680 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1681 }
1682 }
1683
1684 good_tcp_udp0 &= len_diff0 >= 0;
1685 good_tcp_udp1 &= len_diff1 >= 0;
1686
Dave Barachd7cb1b52016-12-09 09:52:16 -05001687 leaf0 =
1688 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1689 leaf1 =
1690 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001691
1692 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1693
1694 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1695 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1696
1697 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001698 error0 = (is_tcp_udp0 && !good_tcp_udp0
1699 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1700 error1 = (is_tcp_udp1 && !good_tcp_udp1
1701 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001702
Dave Barachd7cb1b52016-12-09 09:52:16 -05001703 leaf0 =
1704 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1705 leaf1 =
1706 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001707
Dave Barachd7cb1b52016-12-09 09:52:16 -05001708 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1709 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1710 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001711
Dave Barachd7cb1b52016-12-09 09:52:16 -05001712 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1713 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1714 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001715
Dave Barachd7cb1b52016-12-09 09:52:16 -05001716 lb0 = load_balance_get (lbi0);
1717 lb1 = load_balance_get (lbi1);
1718 dpo0 = load_balance_get_bucket_i (lb0, 0);
1719 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001720
Dave Barach75fc8542016-10-11 16:16:02 -04001721 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001722 * Must have a route to source otherwise we drop the packet.
1723 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001724 *
1725 * The checks are:
1726 * - the source is a recieve => it's from us => bogus, do this
1727 * first since it sets a different error code.
1728 * - uRPF check for any route to source - accept if passes.
1729 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001730 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001731 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001732 dpo0->dpoi_type == DPO_RECEIVE) ?
1733 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1734 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1735 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001736 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001737 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001738 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001739 dpo1->dpoi_type == DPO_RECEIVE) ?
1740 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1741 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1742 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001743 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001744 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001745
Florin Corasa0b34a72017-03-07 01:20:52 -08001746 skip_checks:
1747
Ed Warnickecb9cada2015-12-08 15:45:58 -07001748 next0 = lm->local_next_by_ip_protocol[proto0];
1749 next1 = lm->local_next_by_ip_protocol[proto1];
1750
Dave Barachd7cb1b52016-12-09 09:52:16 -05001751 next0 =
1752 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1753 next1 =
1754 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001755
1756 p0->error = error0 ? error_node->errors[error0] : 0;
1757 p1->error = error1 ? error_node->errors[error1] : 0;
1758
Dave Barach68b0fb02017-02-28 15:15:56 -05001759 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001760 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001761 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1762 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1763 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1764 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001766
1767 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1768 n_left_to_next, pi0, pi1,
1769 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001770 }
1771
1772 while (n_left_from > 0 && n_left_to_next > 0)
1773 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001774 vlib_buffer_t *p0;
1775 ip4_header_t *ip0;
1776 udp_header_t *udp0;
1777 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001779 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001780 i32 len_diff0;
1781 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001782 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001783 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001784 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001785
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786 pi0 = to_next[0] = from[0];
1787 from += 1;
1788 n_left_from -= 1;
1789 to_next += 1;
1790 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001791
Dave Barach68b0fb02017-02-28 15:15:56 -05001792 next0 = IP_LOCAL_NEXT_DROP;
1793
Ed Warnickecb9cada2015-12-08 15:45:58 -07001794 p0 = vlib_get_buffer (vm, pi0);
1795
1796 ip0 = vlib_buffer_get_current (p0);
1797
Damjan Marion072401e2017-07-13 18:53:27 +02001798 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001799
Dave Barach68b0fb02017-02-28 15:15:56 -05001800 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1801
1802 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1803
Neale Ranns32e1c012016-11-22 17:07:28 +00001804 fib_index0 =
1805 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1806 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001807
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001808 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001809
Neale Ranns04a75e32017-03-23 06:46:01 -07001810 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811
John Lo3419d0b2016-06-02 09:28:37 -04001812 /* Treat IP frag packets as "experimental" protocol for now
1813 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001814 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001815
1816 if (head_of_feature_arc == 0)
1817 {
1818 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1819 goto skip_check;
1820 }
1821
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1823 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1824
1825 flags0 = p0->flags;
1826
Damjan Marion213b5aa2017-07-13 21:19:27 +02001827 good_tcp_udp0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001828
1829 udp0 = ip4_next_header (ip0);
1830
1831 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1832 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1833
Ed Warnickecb9cada2015-12-08 15:45:58 -07001834 /* Verify UDP length. */
1835 ip_len0 = clib_net_to_host_u16 (ip0->length);
1836 udp_len0 = clib_net_to_host_u16 (udp0->length);
1837
1838 len_diff0 = ip_len0 - udp_len0;
1839
1840 len_diff0 = is_udp0 ? len_diff0 : 0;
1841
Dave Barachd7cb1b52016-12-09 09:52:16 -05001842 if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843 {
1844 if (is_tcp_udp0)
1845 {
1846 if (is_tcp_udp0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001847 && !(flags0 & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001848 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1849 good_tcp_udp0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001850 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1852 }
1853 }
1854
1855 good_tcp_udp0 &= len_diff0 >= 0;
1856
Dave Barachd7cb1b52016-12-09 09:52:16 -05001857 leaf0 =
1858 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859
1860 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1861
1862 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1863
1864 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001865 error0 = (is_tcp_udp0 && !good_tcp_udp0
1866 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001867
Dave Barachd7cb1b52016-12-09 09:52:16 -05001868 leaf0 =
1869 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001871 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001872 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873
Dave Barachd7cb1b52016-12-09 09:52:16 -05001874 lb0 = load_balance_get (lbi0);
1875 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001876
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001877 vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001878 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879
Neale Ranns3ee44042016-10-03 13:05:48 +01001880 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001881 dpo0->dpoi_type == DPO_RECEIVE) ?
1882 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1883 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1884 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001885 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001886 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887
Dave Barach68b0fb02017-02-28 15:15:56 -05001888 skip_check:
1889
Ed Warnickecb9cada2015-12-08 15:45:58 -07001890 next0 = lm->local_next_by_ip_protocol[proto0];
1891
Dave Barachd7cb1b52016-12-09 09:52:16 -05001892 next0 =
1893 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001894
Dave Barachd7cb1b52016-12-09 09:52:16 -05001895 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896
Dave Barach68b0fb02017-02-28 15:15:56 -05001897 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001898 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001899 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1900 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001902
1903 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1904 n_left_to_next, pi0, next0);
1905
Ed Warnickecb9cada2015-12-08 15:45:58 -07001906 }
Dave Barach75fc8542016-10-11 16:16:02 -04001907
Ed Warnickecb9cada2015-12-08 15:45:58 -07001908 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1909 }
1910
1911 return frame->n_vectors;
1912}
1913
Dave Barach68b0fb02017-02-28 15:15:56 -05001914static uword
1915ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1916{
1917 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1918}
1919
1920/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001921VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001922{
Dave Barach68b0fb02017-02-28 15:15:56 -05001923 .function = ip4_local,
1924 .name = "ip4-local",
1925 .vector_size = sizeof (u32),
1926 .format_trace = format_ip4_forward_next_trace,
1927 .n_next_nodes = IP_LOCAL_N_NEXT,
1928 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001929 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001930 [IP_LOCAL_NEXT_DROP] = "error-drop",
1931 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1932 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1933 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",},
1934};
1935/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936
1937VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1938
Dave Barach68b0fb02017-02-28 15:15:56 -05001939static uword
1940ip4_local_end_of_arc (vlib_main_t * vm,
1941 vlib_node_runtime_t * node, vlib_frame_t * frame)
1942{
1943 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1944}
1945
1946/* *INDENT-OFF* */
1947VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1948 .function = ip4_local_end_of_arc,
1949 .name = "ip4-local-end-of-arc",
1950 .vector_size = sizeof (u32),
1951
1952 .format_trace = format_ip4_forward_next_trace,
1953 .sibling_of = "ip4-local",
1954};
1955
1956VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1957
1958VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1959 .arc_name = "ip4-local",
1960 .node_name = "ip4-local-end-of-arc",
1961 .runs_before = 0, /* not before any other features */
1962};
1963/* *INDENT-ON* */
1964
Dave Barachd7cb1b52016-12-09 09:52:16 -05001965void
1966ip4_register_protocol (u32 protocol, u32 node_index)
1967{
1968 vlib_main_t *vm = vlib_get_main ();
1969 ip4_main_t *im = &ip4_main;
1970 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001971
1972 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001973 lm->local_next_by_ip_protocol[protocol] =
1974 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975}
1976
1977static clib_error_t *
1978show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001979 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001980{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981 ip4_main_t *im = &ip4_main;
1982 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983 int i;
1984
1985 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001986 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987 {
1988 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001989 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001990 }
1991 return 0;
1992}
1993
1994
1995
Billy McFall0683c9c2016-10-13 08:27:31 -04001996/*?
1997 * Display the set of protocols handled by the local IPv4 stack.
1998 *
1999 * @cliexpar
2000 * Example of how to display local protocol table:
2001 * @cliexstart{show ip local}
2002 * Protocols handled by ip4_local
2003 * 1
2004 * 17
2005 * 47
2006 * @cliexend
2007?*/
2008/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002009VLIB_CLI_COMMAND (show_ip_local, static) =
2010{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011 .path = "show ip local",
2012 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04002013 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002014};
Billy McFall0683c9c2016-10-13 08:27:31 -04002015/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002017always_inline uword
2018ip4_arp_inline (vlib_main_t * vm,
2019 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002020 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002021{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002022 vnet_main_t *vnm = vnet_get_main ();
2023 ip4_main_t *im = &ip4_main;
2024 ip_lookup_main_t *lm = &im->lookup_main;
2025 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002026 uword n_left_from, n_left_to_next_drop, next_index;
2027 static f64 time_last_seed_change = -1e100;
2028 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04002029 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002030 f64 time_now;
2031
2032 if (node->flags & VLIB_NODE_FLAG_TRACE)
2033 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2034
2035 time_now = vlib_time_now (vm);
2036 if (time_now - time_last_seed_change > 1e-3)
2037 {
2038 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002039 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
2040 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2042 hash_seeds[i] = r[i];
2043
2044 /* Mark all hash keys as been no-seen before. */
2045 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2046 hash_bitmap[i] = 0;
2047
2048 time_last_seed_change = time_now;
2049 }
2050
2051 from = vlib_frame_vector_args (frame);
2052 n_left_from = frame->n_vectors;
2053 next_index = node->cached_next_index;
2054 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002055 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002056
2057 while (n_left_from > 0)
2058 {
2059 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2060 to_next_drop, n_left_to_next_drop);
2061
2062 while (n_left_from > 0 && n_left_to_next_drop > 0)
2063 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002064 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002065 ip_adjacency_t *adj0;
2066 vlib_buffer_t *p0;
2067 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002068 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069
2070 pi0 = from[0];
2071
2072 p0 = vlib_get_buffer (vm, pi0);
2073
2074 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002075 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002076 ip0 = vlib_buffer_get_current (p0);
2077
Ed Warnickecb9cada2015-12-08 15:45:58 -07002078 a0 = hash_seeds[0];
2079 b0 = hash_seeds[1];
2080 c0 = hash_seeds[2];
2081
2082 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2083 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2084
Dave Barachd7cb1b52016-12-09 09:52:16 -05002085 if (is_glean)
2086 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002087 /*
2088 * this is the Glean case, so we are ARPing for the
2089 * packet's destination
2090 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002091 a0 ^= ip0->dst_address.data_u32;
2092 }
2093 else
2094 {
2095 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2096 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097 b0 ^= sw_if_index0;
2098
2099 hash_v3_finalize32 (a0, b0, c0);
2100
2101 c0 &= BITS (hash_bitmap) - 1;
2102 c0 = c0 / BITS (uword);
2103 m0 = (uword) 1 << (c0 % BITS (uword));
2104
2105 bm0 = hash_bitmap[c0];
2106 drop0 = (bm0 & m0) != 0;
2107
2108 /* Mark it as seen. */
2109 hash_bitmap[c0] = bm0 | m0;
2110
2111 from += 1;
2112 n_left_from -= 1;
2113 to_next_drop[0] = pi0;
2114 to_next_drop += 1;
2115 n_left_to_next_drop -= 1;
2116
Dave Barachd7cb1b52016-12-09 09:52:16 -05002117 p0->error =
2118 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2119 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002120
Neale Rannsb80c5362016-10-08 13:03:40 +01002121 /*
2122 * the adj has been updated to a rewrite but the node the DPO that got
2123 * us here hasn't - yet. no big deal. we'll drop while we wait.
2124 */
2125 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2126 continue;
2127
Ed Warnickecb9cada2015-12-08 15:45:58 -07002128 if (drop0)
2129 continue;
2130
Dave Barachd7cb1b52016-12-09 09:52:16 -05002131 /*
2132 * Can happen if the control-plane is programming tables
2133 * with traffic flowing; at least that's today's lame excuse.
2134 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002135 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2136 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002137 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002138 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002139 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002140 else
2141 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002142 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002143 u32 bi0 = 0;
2144 vlib_buffer_t *b0;
2145 ethernet_arp_header_t *h0;
2146 vnet_hw_interface_t *hw_if0;
2147
2148 h0 =
2149 vlib_packet_template_get_packet (vm,
2150 &im->ip4_arp_request_packet_template,
2151 &bi0);
2152
2153 /* Add rewrite/encap string for ARP packet. */
2154 vnet_rewrite_one_header (adj0[0], h0,
2155 sizeof (ethernet_header_t));
2156
2157 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2158
2159 /* Src ethernet address in ARP header. */
2160 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2161 hw_if0->hw_address,
2162 sizeof (h0->ip4_over_ethernet[0].ethernet));
2163
2164 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002165 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002166 /* The interface's source address is stashed in the Glean Adj */
2167 h0->ip4_over_ethernet[0].ip4 =
2168 adj0->sub_type.glean.receive_addr.ip4;
2169
2170 /* Copy in destination address we are requesting. This is the
2171 * glean case, so it's the packet's destination.*/
2172 h0->ip4_over_ethernet[1].ip4.data_u32 =
2173 ip0->dst_address.data_u32;
2174 }
2175 else
2176 {
2177 /* Src IP address in ARP header. */
2178 if (ip4_src_address_for_packet (lm, sw_if_index0,
2179 &h0->
2180 ip4_over_ethernet[0].ip4))
2181 {
2182 /* No source address available */
2183 p0->error =
2184 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2185 vlib_buffer_free (vm, &bi0, 1);
2186 continue;
2187 }
2188
2189 /* Copy in destination address we are requesting from the
2190 incomplete adj */
2191 h0->ip4_over_ethernet[1].ip4.data_u32 =
2192 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002193 }
2194
Dave Barachd7cb1b52016-12-09 09:52:16 -05002195 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2196 b0 = vlib_get_buffer (vm, bi0);
2197 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2198
2199 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2200
2201 vlib_set_next_frame_buffer (vm, node,
2202 adj0->rewrite_header.next_index,
2203 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002204 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002205 }
2206
2207 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2208 }
2209
2210 return frame->n_vectors;
2211}
2212
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002213static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002214ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002215{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002216 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002217}
2218
2219static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002220ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002221{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002222 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002223}
2224
Dave Barachd7cb1b52016-12-09 09:52:16 -05002225static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002226 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2227 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2228 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2229 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2230 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002231 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002232};
2233
Dave Barachd7cb1b52016-12-09 09:52:16 -05002234VLIB_REGISTER_NODE (ip4_arp_node) =
2235{
2236 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2237 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2238 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2239 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2240 {
2241 [IP4_ARP_NEXT_DROP] = "error-drop",}
2242,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243
Dave Barachd7cb1b52016-12-09 09:52:16 -05002244VLIB_REGISTER_NODE (ip4_glean_node) =
2245{
2246 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2247 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2248 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2249 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2250 {
2251 [IP4_ARP_NEXT_DROP] = "error-drop",}
2252,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002253
Ed Warnickecb9cada2015-12-08 15:45:58 -07002254#define foreach_notrace_ip4_arp_error \
2255_(DROP) \
2256_(REQUEST_SENT) \
2257_(REPLICATE_DROP) \
2258_(REPLICATE_FAIL)
2259
Dave Barachd7cb1b52016-12-09 09:52:16 -05002260clib_error_t *
2261arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002262{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002263 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002264
2265 /* don't trace ARP request packets */
2266#define _(a) \
2267 vnet_pcap_drop_trace_filter_add_del \
2268 (rt->errors[IP4_ARP_ERROR_##a], \
2269 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002270 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002271#undef _
2272 return 0;
2273}
2274
Dave Barachd7cb1b52016-12-09 09:52:16 -05002275VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002276
2277
2278/* Send an ARP request to see if given destination is reachable on given interface. */
2279clib_error_t *
2280ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2281{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002282 vnet_main_t *vnm = vnet_get_main ();
2283 ip4_main_t *im = &ip4_main;
2284 ethernet_arp_header_t *h;
2285 ip4_address_t *src;
2286 ip_interface_address_t *ia;
2287 ip_adjacency_t *adj;
2288 vnet_hw_interface_t *hi;
2289 vnet_sw_interface_t *si;
2290 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002291 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 u32 bi = 0;
2293
2294 si = vnet_get_sw_interface (vnm, sw_if_index);
2295
2296 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2297 {
2298 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002299 format_ip4_address, dst,
2300 format_vnet_sw_if_index_name, vnm,
2301 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002302 }
2303
Dave Barachd7cb1b52016-12-09 09:52:16 -05002304 src =
2305 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2306 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002307 {
2308 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002309 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002310 (0,
2311 "no matching interface address for destination %U (interface %U)",
2312 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2313 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002314 }
2315
Neale Ranns7a272742017-05-30 02:08:14 -07002316 ip46_address_t nh = {
2317 .ip4 = *dst,
2318 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07002319
Neale Ranns7a272742017-05-30 02:08:14 -07002320 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2321 VNET_LINK_IP4, &nh, sw_if_index);
2322 adj = adj_get (ai);
2323
2324 h = vlib_packet_template_get_packet (vm,
2325 &im->ip4_arp_request_packet_template,
2326 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002327
2328 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002329 if (PREDICT_FALSE (!hi->hw_address))
2330 {
2331 return clib_error_return (0, "%U: interface %U do not support ip probe",
2332 format_ip4_address, dst,
2333 format_vnet_sw_if_index_name, vnm,
2334 sw_if_index);
2335 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002336
Dave Barachd7cb1b52016-12-09 09:52:16 -05002337 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2338 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002339
2340 h->ip4_over_ethernet[0].ip4 = src[0];
2341 h->ip4_over_ethernet[1].ip4 = dst[0];
2342
2343 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002344 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2345 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346
2347 /* Add encapsulation string for software interface (e.g. ethernet header). */
2348 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2349 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2350
2351 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002352 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2353 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002354 to_next[0] = bi;
2355 f->n_vectors = 1;
2356 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2357 }
2358
Neale Ranns7a272742017-05-30 02:08:14 -07002359 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 return /* no error */ 0;
2361}
2362
Dave Barachd7cb1b52016-12-09 09:52:16 -05002363typedef enum
2364{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002366 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367} ip4_rewrite_next_t;
2368
2369always_inline uword
2370ip4_rewrite_inline (vlib_main_t * vm,
2371 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002372 vlib_frame_t * frame,
2373 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002374{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002375 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2376 u32 *from = vlib_frame_vector_args (frame);
2377 u32 n_left_from, n_left_to_next, *to_next, next_index;
2378 vlib_node_runtime_t *error_node =
2379 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380
2381 n_left_from = frame->n_vectors;
2382 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002383 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002384
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385 while (n_left_from > 0)
2386 {
2387 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2388
2389 while (n_left_from >= 4 && n_left_to_next >= 2)
2390 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002391 ip_adjacency_t *adj0, *adj1;
2392 vlib_buffer_t *p0, *p1;
2393 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002394 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2395 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002396 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002397
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398 /* Prefetch next iteration. */
2399 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002400 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401
2402 p2 = vlib_get_buffer (vm, from[2]);
2403 p3 = vlib_get_buffer (vm, from[3]);
2404
2405 vlib_prefetch_buffer_header (p2, STORE);
2406 vlib_prefetch_buffer_header (p3, STORE);
2407
2408 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2409 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2410 }
2411
2412 pi0 = to_next[0] = from[0];
2413 pi1 = to_next[1] = from[1];
2414
2415 from += 2;
2416 n_left_from -= 2;
2417 to_next += 2;
2418 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002419
Ed Warnickecb9cada2015-12-08 15:45:58 -07002420 p0 = vlib_get_buffer (vm, pi0);
2421 p1 = vlib_get_buffer (vm, pi1);
2422
Neale Rannsf06aea52016-11-29 06:51:37 -08002423 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2424 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002425
Neale Ranns1bd01092017-03-15 15:41:17 -04002426 /*
2427 * pre-fetch the per-adjacency counters
2428 */
2429 if (do_counters)
2430 {
2431 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002432 thread_index, adj_index0);
Neale Ranns1bd01092017-03-15 15:41:17 -04002433 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002434 thread_index, adj_index1);
Neale Ranns1bd01092017-03-15 15:41:17 -04002435 }
2436
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437 ip0 = vlib_buffer_get_current (p0);
2438 ip1 = vlib_buffer_get_current (p1);
2439
2440 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002441 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002442
2443 /* Decrement TTL & update checksum.
2444 Works either endian, so no need for byte swap. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002445 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002446 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002447 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002448
2449 /* Input node should have reject packets with ttl 0. */
2450 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002451
2452 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002454
2455 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002457 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002458
Dave Barachd7cb1b52016-12-09 09:52:16 -05002459 /*
2460 * If the ttl drops below 1 when forwarding, generate
2461 * an ICMP response.
2462 */
2463 if (PREDICT_FALSE (ttl0 <= 0))
2464 {
2465 error0 = IP4_ERROR_TIME_EXPIRED;
2466 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2467 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2468 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2469 0);
2470 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2471 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002472
2473 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002474 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002475 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Neale Rannsf06aea52016-11-29 06:51:37 -08002476 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002477 else
2478 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002479 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002480 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002481 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002482 {
2483 i32 ttl1 = ip1->ttl;
2484
2485 /* Input node should have reject packets with ttl 0. */
2486 ASSERT (ip1->ttl > 0);
2487
2488 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2489 checksum1 += checksum1 >= 0xffff;
2490
2491 ip1->checksum = checksum1;
2492 ttl1 -= 1;
2493 ip1->ttl = ttl1;
2494
Dave Barachd7cb1b52016-12-09 09:52:16 -05002495 /*
2496 * If the ttl drops below 1 when forwarding, generate
2497 * an ICMP response.
2498 */
2499 if (PREDICT_FALSE (ttl1 <= 0))
2500 {
2501 error1 = IP4_ERROR_TIME_EXPIRED;
2502 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2503 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2504 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2505 0);
2506 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2507 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002508
2509 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002510 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002511 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002512 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002513 else
2514 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002515 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002516 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002517
2518 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002519 adj0 = adj_get (adj_index0);
2520 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002521
Dave Barachd7cb1b52016-12-09 09:52:16 -05002522 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002523 rw_len0 = adj0[0].rewrite_header.data_bytes;
2524 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002525 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2526 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002527
Dave Barachd7cb1b52016-12-09 09:52:16 -05002528 /* Check MTU of outgoing interface. */
2529 error0 =
2530 (vlib_buffer_length_in_chain (vm, p0) >
2531 adj0[0].
2532 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2533 error0);
2534 error1 =
2535 (vlib_buffer_length_in_chain (vm, p1) >
2536 adj1[0].
2537 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2538 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002539
Dave Barachd7cb1b52016-12-09 09:52:16 -05002540 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2541 * to see the IP headerr */
2542 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2543 {
Damjan Marion892e0762016-12-09 18:52:05 +01002544 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002545 p0->current_data -= rw_len0;
2546 p0->current_length += rw_len0;
2547 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2548 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002549
Neale Rannsb069a692017-03-15 12:34:25 -04002550 if (PREDICT_FALSE
2551 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2552 vnet_feature_arc_start (lm->output_feature_arc_index,
2553 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002554 }
2555 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2556 {
Damjan Marion892e0762016-12-09 18:52:05 +01002557 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002558 p1->current_data -= rw_len1;
2559 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002560
Dave Barachd7cb1b52016-12-09 09:52:16 -05002561 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2562 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002563
Neale Rannsb069a692017-03-15 12:34:25 -04002564 if (PREDICT_FALSE
2565 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2566 vnet_feature_arc_start (lm->output_feature_arc_index,
2567 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002568 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002569
2570 /* Guess we are only writing on simple Ethernet header. */
2571 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002573
Neale Ranns044183f2017-01-24 01:34:25 -08002574 /*
2575 * Bump the per-adjacency counters
2576 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002577 if (do_counters)
2578 {
2579 vlib_increment_combined_counter
2580 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002581 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002582 adj_index0, 1,
2583 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002584
Neale Ranns9c6a6132017-02-21 05:33:14 -08002585 vlib_increment_combined_counter
2586 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002587 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002588 adj_index1, 1,
2589 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2590 }
Neale Ranns044183f2017-01-24 01:34:25 -08002591
Neale Ranns5e575b12016-10-03 09:40:25 +01002592 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002593 {
2594 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2595 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2596 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002597 if (is_mcast)
2598 {
2599 /*
2600 * copy bytes from the IP address into the MAC rewrite
2601 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002602 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2603 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002604 }
Dave Barach75fc8542016-10-11 16:16:02 -04002605
Ed Warnickecb9cada2015-12-08 15:45:58 -07002606 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2607 to_next, n_left_to_next,
2608 pi0, pi1, next0, next1);
2609 }
2610
2611 while (n_left_from > 0 && n_left_to_next > 0)
2612 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002613 ip_adjacency_t *adj0;
2614 vlib_buffer_t *p0;
2615 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002616 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002617 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002618
Ed Warnickecb9cada2015-12-08 15:45:58 -07002619 pi0 = to_next[0] = from[0];
2620
2621 p0 = vlib_get_buffer (vm, pi0);
2622
Neale Rannsf06aea52016-11-29 06:51:37 -08002623 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002624
Neale Ranns107e7d42017-04-11 09:55:19 -07002625 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002626
Ed Warnickecb9cada2015-12-08 15:45:58 -07002627 ip0 = vlib_buffer_get_current (p0);
2628
2629 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002630 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002631
2632 /* Decrement TTL & update checksum. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002633 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634 {
2635 i32 ttl0 = ip0->ttl;
2636
2637 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2638
2639 checksum0 += checksum0 >= 0xffff;
2640
2641 ip0->checksum = checksum0;
2642
2643 ASSERT (ip0->ttl > 0);
2644
2645 ttl0 -= 1;
2646
2647 ip0->ttl = ttl0;
2648
Dave Barach2c0a4f42017-06-29 09:30:15 -04002649 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002650 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002651
Dave Barachd7cb1b52016-12-09 09:52:16 -05002652 if (PREDICT_FALSE (ttl0 <= 0))
2653 {
2654 /*
2655 * If the ttl drops below 1 when forwarding, generate
2656 * an ICMP response.
2657 */
2658 error0 = IP4_ERROR_TIME_EXPIRED;
2659 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2660 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2661 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2662 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2663 0);
2664 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002665 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002666 else
2667 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002668 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002669 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002670
Neale Ranns1bd01092017-03-15 15:41:17 -04002671 if (do_counters)
2672 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002673 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002674
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002676 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002677 if (is_mcast)
2678 {
2679 /*
2680 * copy bytes from the IP address into the MAC rewrite
2681 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002682 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002683 }
Dave Barach75fc8542016-10-11 16:16:02 -04002684
Dave Barachd7cb1b52016-12-09 09:52:16 -05002685 /* Update packet buffer attributes/set output interface. */
2686 rw_len0 = adj0[0].rewrite_header.data_bytes;
2687 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002688
Neale Ranns1bd01092017-03-15 15:41:17 -04002689 if (do_counters)
2690 vlib_increment_combined_counter
2691 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002692 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002693 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002694
Dave Barachd7cb1b52016-12-09 09:52:16 -05002695 /* Check MTU of outgoing interface. */
2696 error0 = (vlib_buffer_length_in_chain (vm, p0)
2697 > adj0[0].rewrite_header.max_l3_packet_bytes
2698 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002699
Ed Warnickecb9cada2015-12-08 15:45:58 -07002700 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002701
Dave Barachd7cb1b52016-12-09 09:52:16 -05002702 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2703 * to see the IP headerr */
2704 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2705 {
2706 p0->current_data -= rw_len0;
2707 p0->current_length += rw_len0;
2708 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002709
Dave Barachd7cb1b52016-12-09 09:52:16 -05002710 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2711 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002712
Neale Ranns5e575b12016-10-03 09:40:25 +01002713 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002714 {
2715 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002716 }
2717
Neale Rannsb069a692017-03-15 12:34:25 -04002718 if (PREDICT_FALSE
2719 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2720 vnet_feature_arc_start (lm->output_feature_arc_index,
2721 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002722
Dave Barachd7cb1b52016-12-09 09:52:16 -05002723 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002724
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725 from += 1;
2726 n_left_from -= 1;
2727 to_next += 1;
2728 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002729
Ed Warnickecb9cada2015-12-08 15:45:58 -07002730 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2731 to_next, n_left_to_next,
2732 pi0, next0);
2733 }
Dave Barach75fc8542016-10-11 16:16:02 -04002734
Ed Warnickecb9cada2015-12-08 15:45:58 -07002735 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2736 }
2737
2738 /* Need to do trace after rewrites to pick up new packet data. */
2739 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002740 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741
2742 return frame->n_vectors;
2743}
2744
Dave Barach132d51d2016-07-07 10:10:17 -04002745
Neale Rannsf06aea52016-11-29 06:51:37 -08002746/** @brief IPv4 rewrite node.
2747 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002748
2749 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2750 header checksum, fetch the ip adjacency, check the outbound mtu,
2751 apply the adjacency rewrite, and send pkts to the adjacency
2752 rewrite header's rewrite_next_index.
2753
2754 @param vm vlib_main_t corresponding to the current thread
2755 @param node vlib_node_runtime_t
2756 @param frame vlib_frame_t whose contents should be dispatched
2757
2758 @par Graph mechanics: buffer metadata, next index usage
2759
2760 @em Uses:
2761 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2762 - the rewrite adjacency index
2763 - <code>adj->lookup_next_index</code>
2764 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002765 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002766 - <code>adj->rewrite_header</code>
2767 - Rewrite string length, rewrite string, next_index
2768
2769 @em Sets:
2770 - <code>b->current_data, b->current_length</code>
2771 - Updated net of applying the rewrite string
2772
2773 <em>Next Indices:</em>
2774 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002775 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002776*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002777static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002778ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002779 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002780{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002781 if (adj_are_counters_enabled ())
2782 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2783 else
2784 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002785}
2786
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002787static uword
2788ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002789 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002790{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002791 if (adj_are_counters_enabled ())
2792 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2793 else
2794 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002795}
2796
Neale Ranns32e1c012016-11-22 17:07:28 +00002797static uword
2798ip4_rewrite_mcast (vlib_main_t * vm,
2799 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002800{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002801 if (adj_are_counters_enabled ())
2802 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2803 else
2804 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002805}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002806
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002807static uword
2808ip4_mcast_midchain (vlib_main_t * vm,
2809 vlib_node_runtime_t * node, vlib_frame_t * frame)
2810{
2811 if (adj_are_counters_enabled ())
2812 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2813 else
2814 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2815}
2816
Neale Ranns32e1c012016-11-22 17:07:28 +00002817/* *INDENT-OFF* */
2818VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2819 .function = ip4_rewrite,
2820 .name = "ip4-rewrite",
2821 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002822
Neale Ranns32e1c012016-11-22 17:07:28 +00002823 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002824
Neale Ranns32e1c012016-11-22 17:07:28 +00002825 .n_next_nodes = 2,
2826 .next_nodes = {
2827 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2828 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2829 },
2830};
2831VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2832
2833VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2834 .function = ip4_rewrite_mcast,
2835 .name = "ip4-rewrite-mcast",
2836 .vector_size = sizeof (u32),
2837
2838 .format_trace = format_ip4_rewrite_trace,
2839 .sibling_of = "ip4-rewrite",
2840};
2841VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2842
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002843VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2844 .function = ip4_mcast_midchain,
2845 .name = "ip4-mcast-midchain",
2846 .vector_size = sizeof (u32),
2847
2848 .format_trace = format_ip4_rewrite_trace,
2849 .sibling_of = "ip4-rewrite",
2850};
2851VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2852
Neale Ranns32e1c012016-11-22 17:07:28 +00002853VLIB_REGISTER_NODE (ip4_midchain_node) = {
2854 .function = ip4_midchain,
2855 .name = "ip4-midchain",
2856 .vector_size = sizeof (u32),
2857 .format_trace = format_ip4_forward_next_trace,
2858 .sibling_of = "ip4-rewrite",
2859};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002861/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002862
Ed Warnickecb9cada2015-12-08 15:45:58 -07002863static clib_error_t *
2864add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002865 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002867 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002868 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002869 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002870 u32 sw_if_index, table_id;
2871
2872 sw_if_index = ~0;
2873
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002875 {
2876 error = clib_error_return (0, "unknown interface `%U'",
2877 format_unformat_error, input);
2878 goto done;
2879 }
2880
2881 if (unformat (input, "%d", &table_id))
2882 ;
2883 else
2884 {
2885 error = clib_error_return (0, "expected table id `%U'",
2886 format_unformat_error, input);
2887 goto done;
2888 }
2889
Neale Ranns4008ac92017-02-13 23:20:04 -08002890 /*
2891 * If the interface already has in IP address, then a change int
2892 * VRF is not allowed. The IP address applied must first be removed.
2893 * We do not do that automatically here, since VPP has no knowledge
2894 * of whether thoses subnets are valid in the destination VRF.
2895 */
2896 /* *INDENT-OFF* */
2897 foreach_ip_interface_address (&ip4_main.lookup_main,
2898 ia, sw_if_index,
2899 1 /* honor unnumbered */,
2900 ({
2901 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002902
Neale Ranns4008ac92017-02-13 23:20:04 -08002903 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2904 error = clib_error_return (0, "interface %U has address %U",
2905 format_vnet_sw_if_index_name, vnm,
2906 sw_if_index,
2907 format_ip4_address, a);
2908 goto done;
2909 }));
2910 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002911
Neale Ranns4008ac92017-02-13 23:20:04 -08002912{
2913 ip4_main_t *im = &ip4_main;
2914 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002915
Neale Ranns4008ac92017-02-13 23:20:04 -08002916 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2917
2918 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2919 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2920
2921 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2922 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2923 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2924}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925
Dave Barachd7cb1b52016-12-09 09:52:16 -05002926done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002927return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928}
2929
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002930/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002931 * Place the indicated interface into the supplied IPv4 FIB table (also known
2932 * as a VRF). If the FIB table does not exist, this command creates it. To
2933 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2934 * FIB table will only be displayed if a route has been added to the table, or
2935 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002936 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002937 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002938 * @note IP addresses added after setting the interface IP table are added to
2939 * the indicated FIB table. If an IP address is added prior to changing the
2940 * table then this is an error. The control plane must remove these addresses
2941 * first and then change the table. VPP will not automatically move the
2942 * addresses from the old to the new table as it does not know the validity
2943 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002944 *
2945 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002946 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2947 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002948 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002949/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002950VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2951{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002952 .path = "set interface ip table",
2953 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002954 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002955};
Billy McFall0683c9c2016-10-13 08:27:31 -04002956/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957
Dave Barachd7cb1b52016-12-09 09:52:16 -05002958int
2959ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2960{
2961 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002962 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002963 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002964
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002965 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002966
Neale Ranns04a75e32017-03-23 06:46:01 -07002967 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002968 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2969 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002970
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002971 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002972
Dave Barachd7cb1b52016-12-09 09:52:16 -05002973 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002974}
Dave Barach75fc8542016-10-11 16:16:02 -04002975
Ed Warnickecb9cada2015-12-08 15:45:58 -07002976static clib_error_t *
2977test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002978 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002979{
Billy McFall309fe062016-10-14 07:37:33 -04002980 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002981 u32 table_id = 0;
2982 f64 count = 1;
2983 u32 n;
2984 int i;
2985 ip4_address_t ip4_base_address;
2986 u64 errors = 0;
2987
Dave Barachd7cb1b52016-12-09 09:52:16 -05002988 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2989 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002990 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002991 {
2992 /* Make sure the entry exists. */
2993 fib = ip4_fib_get (table_id);
2994 if ((fib) && (fib->index != table_id))
2995 return clib_error_return (0, "<fib-index> %d does not exist",
2996 table_id);
2997 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002998 else if (unformat (input, "count %f", &count))
2999 ;
3000
3001 else if (unformat (input, "%U",
3002 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003003 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003004 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003005 return clib_error_return (0, "unknown input `%U'",
3006 format_unformat_error, input);
3007 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008
3009 n = count;
3010
3011 for (i = 0; i < n; i++)
3012 {
3013 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003014 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003015
Dave Barach75fc8542016-10-11 16:16:02 -04003016 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05003017 clib_host_to_net_u32 (1 +
3018 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019 }
3020
Dave Barach75fc8542016-10-11 16:16:02 -04003021 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3023 else
3024 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3025
3026 return 0;
3027}
3028
Billy McFall0683c9c2016-10-13 08:27:31 -04003029/*?
3030 * Perform a lookup of an IPv4 Address (or range of addresses) in the
3031 * given FIB table to determine if there is a conflict with the
3032 * adjacency table. The fib-id can be determined by using the
3033 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
3034 * of 0 is used.
3035 *
3036 * @todo This command uses fib-id, other commands use table-id (not
3037 * just a name, they are different indexes). Would like to change this
3038 * to table-id for consistency.
3039 *
3040 * @cliexpar
3041 * Example of how to run the test lookup command:
3042 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3043 * No errors in 2 lookups
3044 * @cliexend
3045?*/
3046/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003047VLIB_CLI_COMMAND (lookup_test_command, static) =
3048{
3049 .path = "test lookup",
3050 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3051 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052};
Billy McFall0683c9c2016-10-13 08:27:31 -04003053/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003054
Dave Barachd7cb1b52016-12-09 09:52:16 -05003055int
3056vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003057{
Neale Ranns107e7d42017-04-11 09:55:19 -07003058 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003059
Neale Ranns107e7d42017-04-11 09:55:19 -07003060 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
3061
3062 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003063 return VNET_API_ERROR_NO_SUCH_FIB;
3064
Neale Ranns227038a2017-04-21 01:07:59 -07003065 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3066 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003067
Ed Warnickecb9cada2015-12-08 15:45:58 -07003068 return 0;
3069}
Dave Barach75fc8542016-10-11 16:16:02 -04003070
Ed Warnickecb9cada2015-12-08 15:45:58 -07003071static clib_error_t *
3072set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003073 unformat_input_t * input,
3074 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003075{
3076 int matched = 0;
3077 u32 table_id = 0;
3078 u32 flow_hash_config = 0;
3079 int rv;
3080
Dave Barachd7cb1b52016-12-09 09:52:16 -05003081 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3082 {
3083 if (unformat (input, "table %d", &table_id))
3084 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003085#define _(a,v) \
3086 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003087 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003088#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003089 else
3090 break;
3091 }
Dave Barach75fc8542016-10-11 16:16:02 -04003092
Ed Warnickecb9cada2015-12-08 15:45:58 -07003093 if (matched == 0)
3094 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003095 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003096
Ed Warnickecb9cada2015-12-08 15:45:58 -07003097 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3098 switch (rv)
3099 {
3100 case 0:
3101 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003102
Ed Warnickecb9cada2015-12-08 15:45:58 -07003103 case VNET_API_ERROR_NO_SUCH_FIB:
3104 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003105
Ed Warnickecb9cada2015-12-08 15:45:58 -07003106 default:
3107 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3108 break;
3109 }
Dave Barach75fc8542016-10-11 16:16:02 -04003110
Ed Warnickecb9cada2015-12-08 15:45:58 -07003111 return 0;
3112}
Dave Barach75fc8542016-10-11 16:16:02 -04003113
Billy McFall0683c9c2016-10-13 08:27:31 -04003114/*?
3115 * Configure the set of IPv4 fields used by the flow hash.
3116 *
3117 * @cliexpar
3118 * Example of how to set the flow hash on a given table:
3119 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3120 * Example of display the configured flow hash:
3121 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003122 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3123 * 0.0.0.0/0
3124 * unicast-ip4-chain
3125 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3126 * [0] [@0]: dpo-drop ip6
3127 * 0.0.0.0/32
3128 * unicast-ip4-chain
3129 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3130 * [0] [@0]: dpo-drop ip6
3131 * 224.0.0.0/8
3132 * unicast-ip4-chain
3133 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3134 * [0] [@0]: dpo-drop ip6
3135 * 6.0.1.2/32
3136 * unicast-ip4-chain
3137 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3138 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3139 * 7.0.0.1/32
3140 * unicast-ip4-chain
3141 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3142 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3143 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3144 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3145 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3146 * 240.0.0.0/8
3147 * unicast-ip4-chain
3148 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3149 * [0] [@0]: dpo-drop ip6
3150 * 255.255.255.255/32
3151 * unicast-ip4-chain
3152 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3153 * [0] [@0]: dpo-drop ip6
3154 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3155 * 0.0.0.0/0
3156 * unicast-ip4-chain
3157 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3158 * [0] [@0]: dpo-drop ip6
3159 * 0.0.0.0/32
3160 * unicast-ip4-chain
3161 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3162 * [0] [@0]: dpo-drop ip6
3163 * 172.16.1.0/24
3164 * unicast-ip4-chain
3165 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3166 * [0] [@4]: ipv4-glean: af_packet0
3167 * 172.16.1.1/32
3168 * unicast-ip4-chain
3169 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3170 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3171 * 172.16.1.2/32
3172 * unicast-ip4-chain
3173 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3174 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3175 * 172.16.2.0/24
3176 * unicast-ip4-chain
3177 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3178 * [0] [@4]: ipv4-glean: af_packet1
3179 * 172.16.2.1/32
3180 * unicast-ip4-chain
3181 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3182 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3183 * 224.0.0.0/8
3184 * unicast-ip4-chain
3185 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3186 * [0] [@0]: dpo-drop ip6
3187 * 240.0.0.0/8
3188 * unicast-ip4-chain
3189 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3190 * [0] [@0]: dpo-drop ip6
3191 * 255.255.255.255/32
3192 * unicast-ip4-chain
3193 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3194 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003195 * @cliexend
3196?*/
3197/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003198VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3199{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003200 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003201 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003202 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003203 .function = set_ip_flow_hash_command_fn,
3204};
Billy McFall0683c9c2016-10-13 08:27:31 -04003205/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003206
Dave Barachd7cb1b52016-12-09 09:52:16 -05003207int
3208vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3209 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003210{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003211 vnet_main_t *vnm = vnet_get_main ();
3212 vnet_interface_main_t *im = &vnm->interface_main;
3213 ip4_main_t *ipm = &ip4_main;
3214 ip_lookup_main_t *lm = &ipm->lookup_main;
3215 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003216 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003217
3218 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3219 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3220
3221 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3222 return VNET_API_ERROR_NO_SUCH_ENTRY;
3223
3224 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003225 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003226
Neale Rannsdf089a82016-10-02 16:39:06 +01003227 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3228
3229 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003230 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003231 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003232 .fp_len = 32,
3233 .fp_proto = FIB_PROTOCOL_IP4,
3234 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003235 };
3236 u32 fib_index;
3237
Dave Barachd7cb1b52016-12-09 09:52:16 -05003238 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3239 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003240
3241
Dave Barachd7cb1b52016-12-09 09:52:16 -05003242 if (table_index != (u32) ~ 0)
3243 {
3244 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003245
Dave Barachd7cb1b52016-12-09 09:52:16 -05003246 dpo_set (&dpo,
3247 DPO_CLASSIFY,
3248 DPO_PROTO_IP4,
3249 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003250
Dave Barachd7cb1b52016-12-09 09:52:16 -05003251 fib_table_entry_special_dpo_add (fib_index,
3252 &pfx,
3253 FIB_SOURCE_CLASSIFY,
3254 FIB_ENTRY_FLAG_NONE, &dpo);
3255 dpo_reset (&dpo);
3256 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003257 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003258 {
3259 fib_table_entry_special_remove (fib_index,
3260 &pfx, FIB_SOURCE_CLASSIFY);
3261 }
3262 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003263
Ed Warnickecb9cada2015-12-08 15:45:58 -07003264 return 0;
3265}
3266
3267static clib_error_t *
3268set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003269 unformat_input_t * input,
3270 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003271{
3272 u32 table_index = ~0;
3273 int table_index_set = 0;
3274 u32 sw_if_index = ~0;
3275 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003276
Dave Barachd7cb1b52016-12-09 09:52:16 -05003277 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3278 {
3279 if (unformat (input, "table-index %d", &table_index))
3280 table_index_set = 1;
3281 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3282 vnet_get_main (), &sw_if_index))
3283 ;
3284 else
3285 break;
3286 }
Dave Barach75fc8542016-10-11 16:16:02 -04003287
Ed Warnickecb9cada2015-12-08 15:45:58 -07003288 if (table_index_set == 0)
3289 return clib_error_return (0, "classify table-index must be specified");
3290
3291 if (sw_if_index == ~0)
3292 return clib_error_return (0, "interface / subif must be specified");
3293
3294 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3295
3296 switch (rv)
3297 {
3298 case 0:
3299 break;
3300
3301 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3302 return clib_error_return (0, "No such interface");
3303
3304 case VNET_API_ERROR_NO_SUCH_ENTRY:
3305 return clib_error_return (0, "No such classifier table");
3306 }
3307 return 0;
3308}
3309
Billy McFall0683c9c2016-10-13 08:27:31 -04003310/*?
3311 * Assign a classification table to an interface. The classification
3312 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3313 * commands. Once the table is create, use this command to filter packets
3314 * on an interface.
3315 *
3316 * @cliexpar
3317 * Example of how to assign a classification table to an interface:
3318 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3319?*/
3320/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003321VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3322{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003323 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003324 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003325 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003326 .function = set_ip_classify_command_fn,
3327};
Billy McFall0683c9c2016-10-13 08:27:31 -04003328/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003329
3330/*
3331 * fd.io coding-style-patch-verification: ON
3332 *
3333 * Local Variables:
3334 * eval: (c-set-style "gnu")
3335 * End:
3336 */