blob: 2d48e8a9ab5af3f37f4065df002558caf4de942e [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),
Neale Rannsda78f952017-05-24 09:15:43 -0700727 DPO_PROTO_IP4,
Neale Ranns7a272742017-05-30 02:08:14 -0700728 /* 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),
Neale Rannsda78f952017-05-24 09:15:43 -0700770 DPO_PROTO_IP4,
Neale Ranns9a69a602017-03-26 10:56:33 -0700771 &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),
Neale Rannsda78f952017-05-24 09:15:43 -0700806 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000807 &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;
Florin Corasb2215d62017-08-01 16:56:58 -07001457 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458 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;
Florin Corasb2215d62017-08-01 16:56:58 -07001484 n_ip_bytes_this_buffer = p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1485 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1486 {
1487 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
1488 n_ip_bytes_this_buffer - ip_header_length : 0;
1489 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490 while (1)
1491 {
1492 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1493 n_bytes_left -= n_this_buffer;
1494 if (n_bytes_left == 0)
1495 break;
1496
1497 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1498 p0 = vlib_get_buffer (vm, p0->next_buffer);
1499 data_this_buffer = vlib_buffer_get_current (p0);
1500 n_this_buffer = p0->current_length;
1501 }
1502
Dave Barachd7cb1b52016-12-09 09:52:16 -05001503 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001504
1505 return sum16;
1506}
1507
John Lo37682e12016-11-30 12:51:39 -05001508u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001509ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1510{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001511 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1512 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513 u16 sum16;
1514
1515 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1516 || ip0->protocol == IP_PROTOCOL_UDP);
1517
1518 udp0 = (void *) (ip0 + 1);
1519 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1520 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001521 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1522 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001523 return p0->flags;
1524 }
1525
1526 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1527
Damjan Marion213b5aa2017-07-13 21:19:27 +02001528 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1529 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001530
1531 return p0->flags;
1532}
1533
Dave Barach68b0fb02017-02-28 15:15:56 -05001534/* *INDENT-OFF* */
1535VNET_FEATURE_ARC_INIT (ip4_local) =
1536{
1537 .arc_name = "ip4-local",
1538 .start_nodes = VNET_FEATURES ("ip4-local"),
1539};
1540/* *INDENT-ON* */
1541
Florin Coras20a14b92017-08-15 22:47:22 -07001542static inline void
1543ip4_local_validate_l4 (vlib_main_t * vm, vlib_buffer_t * p, ip4_header_t * ip,
1544 u8 is_udp, u8 * error, u8 * good_tcp_udp)
1545{
1546 u32 flags0;
1547 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1548 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1549 if (is_udp)
1550 {
1551 udp_header_t *udp;
1552 u32 ip_len, udp_len;
1553 i32 len_diff;
1554 udp = ip4_next_header (ip);
1555 /* Verify UDP length. */
1556 ip_len = clib_net_to_host_u16 (ip->length);
1557 udp_len = clib_net_to_host_u16 (udp->length);
1558
1559 len_diff = ip_len - udp_len;
1560 *good_tcp_udp &= len_diff >= 0;
1561 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1562 }
1563}
1564
1565#define ip4_local_do_l4_check(is_tcp_udp, flags) \
1566 (is_tcp_udp && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED))
1567
Dave Barach68b0fb02017-02-28 15:15:56 -05001568static inline uword
1569ip4_local_inline (vlib_main_t * vm,
1570 vlib_node_runtime_t * node,
1571 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001572{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001573 ip4_main_t *im = &ip4_main;
1574 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001575 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001576 u32 *from, *to_next, n_left_from, n_left_to_next;
1577 vlib_node_runtime_t *error_node =
1578 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001579 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001580
1581 from = vlib_frame_vector_args (frame);
1582 n_left_from = frame->n_vectors;
1583 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001584
Ed Warnickecb9cada2015-12-08 15:45:58 -07001585 if (node->flags & VLIB_NODE_FLAG_TRACE)
1586 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1587
1588 while (n_left_from > 0)
1589 {
1590 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1591
1592 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001593 {
1594 vlib_buffer_t *p0, *p1;
1595 ip4_header_t *ip0, *ip1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001596 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1597 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1598 const dpo_id_t *dpo0, *dpo1;
1599 const load_balance_t *lb0, *lb1;
Florin Coras20a14b92017-08-15 22:47:22 -07001600 u32 pi0, next0, fib_index0, lbi0;
1601 u32 pi1, next1, fib_index1, lbi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001602 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1603 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001604 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001605
Dave Barachd7cb1b52016-12-09 09:52:16 -05001606 pi0 = to_next[0] = from[0];
1607 pi1 = to_next[1] = from[1];
1608 from += 2;
1609 n_left_from -= 2;
1610 to_next += 2;
1611 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001612
Dave Barach68b0fb02017-02-28 15:15:56 -05001613 next0 = next1 = IP_LOCAL_NEXT_DROP;
Florin Coras20a14b92017-08-15 22:47:22 -07001614 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
Dave Barach68b0fb02017-02-28 15:15:56 -05001615
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616 p0 = vlib_get_buffer (vm, pi0);
1617 p1 = vlib_get_buffer (vm, pi1);
1618
1619 ip0 = vlib_buffer_get_current (p0);
1620 ip1 = vlib_buffer_get_current (p1);
1621
Damjan Marion072401e2017-07-13 18:53:27 +02001622 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1623 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001624
Dave Barach68b0fb02017-02-28 15:15:56 -05001625 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1626 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1627
Florin Coras20a14b92017-08-15 22:47:22 -07001628 /* Treat IP frag packets as "experimental" protocol for now
1629 until support of IP frag reassembly is implemented */
1630 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1631 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
1632
1633 if (head_of_feature_arc == 0)
1634 goto skip_checks;
1635
1636 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1637 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1638 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1639 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1640
1641 good_tcp_udp0 =
1642 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1643 good_tcp_udp1 =
1644 (p1->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1645
1646 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)
1647 || ip4_local_do_l4_check (is_tcp_udp1,
1648 p1->flags)))
1649 {
1650 if (is_tcp_udp0)
1651 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1652 &good_tcp_udp0);
1653 if (is_tcp_udp1)
1654 ip4_local_validate_l4 (vm, p1, ip1, is_udp1, &error1,
1655 &good_tcp_udp1);
1656 }
1657
1658 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1659 error0 = (is_tcp_udp0 && !good_tcp_udp0
1660 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1661 error1 = (is_tcp_udp1 && !good_tcp_udp1
1662 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Dave Barach68b0fb02017-02-28 15:15:56 -05001663
1664 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001665 fib_index0 =
1666 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1667 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001668
Dave Barach68b0fb02017-02-28 15:15:56 -05001669 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001670 fib_index1 =
1671 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1672 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001673
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001674 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1675 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001676
Neale Ranns04a75e32017-03-23 06:46:01 -07001677 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1678 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
Florin Coras20a14b92017-08-15 22:47:22 -07001679 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1680 2);
1681 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1682 2);
1683 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1684 3);
1685 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1686 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001687
Dave Barachd7cb1b52016-12-09 09:52:16 -05001688 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1689 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1690 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001691
Dave Barachd7cb1b52016-12-09 09:52:16 -05001692 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1693 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1694 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001695
Dave Barachd7cb1b52016-12-09 09:52:16 -05001696 lb0 = load_balance_get (lbi0);
1697 lb1 = load_balance_get (lbi1);
1698 dpo0 = load_balance_get_bucket_i (lb0, 0);
1699 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001700
Dave Barach75fc8542016-10-11 16:16:02 -04001701 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 * Must have a route to source otherwise we drop the packet.
1703 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001704 *
1705 * The checks are:
1706 * - the source is a recieve => it's from us => bogus, do this
1707 * first since it sets a different error code.
1708 * - uRPF check for any route to source - accept if passes.
1709 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001710 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001711 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001712 dpo0->dpoi_type == DPO_RECEIVE) ?
1713 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1714 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1715 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001716 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001717 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001718 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001719 dpo1->dpoi_type == DPO_RECEIVE) ?
1720 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1721 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1722 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001723 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001724 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001725
Florin Corasa0b34a72017-03-07 01:20:52 -08001726 skip_checks:
1727
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 next0 = lm->local_next_by_ip_protocol[proto0];
1729 next1 = lm->local_next_by_ip_protocol[proto1];
1730
Dave Barachd7cb1b52016-12-09 09:52:16 -05001731 next0 =
1732 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1733 next1 =
1734 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001735
1736 p0->error = error0 ? error_node->errors[error0] : 0;
1737 p1->error = error1 ? error_node->errors[error1] : 0;
1738
Dave Barach68b0fb02017-02-28 15:15:56 -05001739 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001740 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001741 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1742 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1743 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1744 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001745 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001746
1747 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1748 n_left_to_next, pi0, pi1,
1749 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750 }
1751
1752 while (n_left_from > 0 && n_left_to_next > 0)
1753 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001754 vlib_buffer_t *p0;
1755 ip4_header_t *ip0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001756 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001757 ip4_fib_mtrie_leaf_t leaf0;
Florin Coras20a14b92017-08-15 22:47:22 -07001758 u32 pi0, next0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001761 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001762 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001763
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764 pi0 = to_next[0] = from[0];
1765 from += 1;
1766 n_left_from -= 1;
1767 to_next += 1;
1768 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001769
Dave Barach68b0fb02017-02-28 15:15:56 -05001770 next0 = IP_LOCAL_NEXT_DROP;
Florin Coras20a14b92017-08-15 22:47:22 -07001771 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
Dave Barach68b0fb02017-02-28 15:15:56 -05001772
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774 ip0 = vlib_buffer_get_current (p0);
Damjan Marion072401e2017-07-13 18:53:27 +02001775 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Dave Barach68b0fb02017-02-28 15:15:56 -05001776 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1777
John Lo3419d0b2016-06-02 09:28:37 -04001778 /* Treat IP frag packets as "experimental" protocol for now
1779 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001780 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001781
1782 if (head_of_feature_arc == 0)
Florin Coras20a14b92017-08-15 22:47:22 -07001783 goto skip_check;
Dave Barach68b0fb02017-02-28 15:15:56 -05001784
Ed Warnickecb9cada2015-12-08 15:45:58 -07001785 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1786 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
Florin Coras20a14b92017-08-15 22:47:22 -07001787 good_tcp_udp0 =
1788 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001789
Florin Coras20a14b92017-08-15 22:47:22 -07001790 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001791 {
Florin Coras20a14b92017-08-15 22:47:22 -07001792 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1793 &good_tcp_udp0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001794 }
1795
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001797 error0 = (is_tcp_udp0 && !good_tcp_udp0
1798 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001799
Florin Coras20a14b92017-08-15 22:47:22 -07001800 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1801 fib_index0 =
1802 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1803 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1804 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1805 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1806 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1807 2);
1808 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1809 3);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001810 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001811 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras20a14b92017-08-15 22:47:22 -07001812 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813
Dave Barachd7cb1b52016-12-09 09:52:16 -05001814 lb0 = load_balance_get (lbi0);
1815 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001816
Neale Ranns3ee44042016-10-03 13:05:48 +01001817 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001818 dpo0->dpoi_type == DPO_RECEIVE) ?
1819 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1820 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1821 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001822 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824
Dave Barach68b0fb02017-02-28 15:15:56 -05001825 skip_check:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001826 next0 = lm->local_next_by_ip_protocol[proto0];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001827 next0 =
1828 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829
Dave Barachd7cb1b52016-12-09 09:52:16 -05001830 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001831
Dave Barach68b0fb02017-02-28 15:15:56 -05001832 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001834 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1835 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001837
1838 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1839 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001840 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1842 }
1843
1844 return frame->n_vectors;
1845}
1846
Dave Barach68b0fb02017-02-28 15:15:56 -05001847static uword
1848ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1849{
1850 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1851}
1852
1853/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001854VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001855{
Dave Barach68b0fb02017-02-28 15:15:56 -05001856 .function = ip4_local,
1857 .name = "ip4-local",
1858 .vector_size = sizeof (u32),
1859 .format_trace = format_ip4_forward_next_trace,
1860 .n_next_nodes = IP_LOCAL_N_NEXT,
1861 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001862 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001863 [IP_LOCAL_NEXT_DROP] = "error-drop",
1864 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1865 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001866 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1867 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001868};
1869/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001870
1871VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1872
Dave Barach68b0fb02017-02-28 15:15:56 -05001873static uword
1874ip4_local_end_of_arc (vlib_main_t * vm,
1875 vlib_node_runtime_t * node, vlib_frame_t * frame)
1876{
1877 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1878}
1879
1880/* *INDENT-OFF* */
1881VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1882 .function = ip4_local_end_of_arc,
1883 .name = "ip4-local-end-of-arc",
1884 .vector_size = sizeof (u32),
1885
1886 .format_trace = format_ip4_forward_next_trace,
1887 .sibling_of = "ip4-local",
1888};
1889
1890VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1891
1892VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1893 .arc_name = "ip4-local",
1894 .node_name = "ip4-local-end-of-arc",
1895 .runs_before = 0, /* not before any other features */
1896};
1897/* *INDENT-ON* */
1898
Dave Barachd7cb1b52016-12-09 09:52:16 -05001899void
1900ip4_register_protocol (u32 protocol, u32 node_index)
1901{
1902 vlib_main_t *vm = vlib_get_main ();
1903 ip4_main_t *im = &ip4_main;
1904 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905
1906 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001907 lm->local_next_by_ip_protocol[protocol] =
1908 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909}
1910
1911static clib_error_t *
1912show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001913 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001914{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001915 ip4_main_t *im = &ip4_main;
1916 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001917 int i;
1918
1919 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001920 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921 {
1922 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001923 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001924 }
1925 return 0;
1926}
1927
1928
1929
Billy McFall0683c9c2016-10-13 08:27:31 -04001930/*?
1931 * Display the set of protocols handled by the local IPv4 stack.
1932 *
1933 * @cliexpar
1934 * Example of how to display local protocol table:
1935 * @cliexstart{show ip local}
1936 * Protocols handled by ip4_local
1937 * 1
1938 * 17
1939 * 47
1940 * @cliexend
1941?*/
1942/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001943VLIB_CLI_COMMAND (show_ip_local, static) =
1944{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001945 .path = "show ip local",
1946 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001947 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948};
Billy McFall0683c9c2016-10-13 08:27:31 -04001949/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001950
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001951always_inline uword
1952ip4_arp_inline (vlib_main_t * vm,
1953 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001954 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001955{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001956 vnet_main_t *vnm = vnet_get_main ();
1957 ip4_main_t *im = &ip4_main;
1958 ip_lookup_main_t *lm = &im->lookup_main;
1959 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001960 uword n_left_from, n_left_to_next_drop, next_index;
1961 static f64 time_last_seed_change = -1e100;
1962 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001963 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001964 f64 time_now;
1965
1966 if (node->flags & VLIB_NODE_FLAG_TRACE)
1967 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1968
1969 time_now = vlib_time_now (vm);
1970 if (time_now - time_last_seed_change > 1e-3)
1971 {
1972 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001973 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1974 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1976 hash_seeds[i] = r[i];
1977
1978 /* Mark all hash keys as been no-seen before. */
1979 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1980 hash_bitmap[i] = 0;
1981
1982 time_last_seed_change = time_now;
1983 }
1984
1985 from = vlib_frame_vector_args (frame);
1986 n_left_from = frame->n_vectors;
1987 next_index = node->cached_next_index;
1988 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001989 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001990
1991 while (n_left_from > 0)
1992 {
1993 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1994 to_next_drop, n_left_to_next_drop);
1995
1996 while (n_left_from > 0 && n_left_to_next_drop > 0)
1997 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001998 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001999 ip_adjacency_t *adj0;
2000 vlib_buffer_t *p0;
2001 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002003
2004 pi0 = from[0];
2005
2006 p0 = vlib_get_buffer (vm, pi0);
2007
2008 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002009 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002010 ip0 = vlib_buffer_get_current (p0);
2011
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 a0 = hash_seeds[0];
2013 b0 = hash_seeds[1];
2014 c0 = hash_seeds[2];
2015
2016 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2017 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2018
Dave Barachd7cb1b52016-12-09 09:52:16 -05002019 if (is_glean)
2020 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002021 /*
2022 * this is the Glean case, so we are ARPing for the
2023 * packet's destination
2024 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002025 a0 ^= ip0->dst_address.data_u32;
2026 }
2027 else
2028 {
2029 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2030 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 b0 ^= sw_if_index0;
2032
2033 hash_v3_finalize32 (a0, b0, c0);
2034
2035 c0 &= BITS (hash_bitmap) - 1;
2036 c0 = c0 / BITS (uword);
2037 m0 = (uword) 1 << (c0 % BITS (uword));
2038
2039 bm0 = hash_bitmap[c0];
2040 drop0 = (bm0 & m0) != 0;
2041
2042 /* Mark it as seen. */
2043 hash_bitmap[c0] = bm0 | m0;
2044
2045 from += 1;
2046 n_left_from -= 1;
2047 to_next_drop[0] = pi0;
2048 to_next_drop += 1;
2049 n_left_to_next_drop -= 1;
2050
Dave Barachd7cb1b52016-12-09 09:52:16 -05002051 p0->error =
2052 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2053 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054
Neale Rannsb80c5362016-10-08 13:03:40 +01002055 /*
2056 * the adj has been updated to a rewrite but the node the DPO that got
2057 * us here hasn't - yet. no big deal. we'll drop while we wait.
2058 */
2059 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2060 continue;
2061
Ed Warnickecb9cada2015-12-08 15:45:58 -07002062 if (drop0)
2063 continue;
2064
Dave Barachd7cb1b52016-12-09 09:52:16 -05002065 /*
2066 * Can happen if the control-plane is programming tables
2067 * with traffic flowing; at least that's today's lame excuse.
2068 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002069 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2070 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002071 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002072 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002073 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002074 else
2075 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002076 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002077 u32 bi0 = 0;
2078 vlib_buffer_t *b0;
2079 ethernet_arp_header_t *h0;
2080 vnet_hw_interface_t *hw_if0;
2081
2082 h0 =
2083 vlib_packet_template_get_packet (vm,
2084 &im->ip4_arp_request_packet_template,
2085 &bi0);
2086
2087 /* Add rewrite/encap string for ARP packet. */
2088 vnet_rewrite_one_header (adj0[0], h0,
2089 sizeof (ethernet_header_t));
2090
2091 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2092
2093 /* Src ethernet address in ARP header. */
2094 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2095 hw_if0->hw_address,
2096 sizeof (h0->ip4_over_ethernet[0].ethernet));
2097
2098 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002099 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002100 /* The interface's source address is stashed in the Glean Adj */
2101 h0->ip4_over_ethernet[0].ip4 =
2102 adj0->sub_type.glean.receive_addr.ip4;
2103
2104 /* Copy in destination address we are requesting. This is the
2105 * glean case, so it's the packet's destination.*/
2106 h0->ip4_over_ethernet[1].ip4.data_u32 =
2107 ip0->dst_address.data_u32;
2108 }
2109 else
2110 {
2111 /* Src IP address in ARP header. */
2112 if (ip4_src_address_for_packet (lm, sw_if_index0,
2113 &h0->
2114 ip4_over_ethernet[0].ip4))
2115 {
2116 /* No source address available */
2117 p0->error =
2118 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2119 vlib_buffer_free (vm, &bi0, 1);
2120 continue;
2121 }
2122
2123 /* Copy in destination address we are requesting from the
2124 incomplete adj */
2125 h0->ip4_over_ethernet[1].ip4.data_u32 =
2126 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002127 }
2128
Dave Barachd7cb1b52016-12-09 09:52:16 -05002129 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2130 b0 = vlib_get_buffer (vm, bi0);
2131 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2132
2133 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2134
2135 vlib_set_next_frame_buffer (vm, node,
2136 adj0->rewrite_header.next_index,
2137 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002138 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002139 }
2140
2141 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2142 }
2143
2144 return frame->n_vectors;
2145}
2146
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002147static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002148ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002149{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002150 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002151}
2152
2153static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002154ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002155{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002156 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002157}
2158
Dave Barachd7cb1b52016-12-09 09:52:16 -05002159static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002160 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2161 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2162 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2163 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2164 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002165 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002166};
2167
Dave Barachd7cb1b52016-12-09 09:52:16 -05002168VLIB_REGISTER_NODE (ip4_arp_node) =
2169{
2170 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2171 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2172 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2173 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2174 {
2175 [IP4_ARP_NEXT_DROP] = "error-drop",}
2176,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002177
Dave Barachd7cb1b52016-12-09 09:52:16 -05002178VLIB_REGISTER_NODE (ip4_glean_node) =
2179{
2180 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2181 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2182 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2183 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2184 {
2185 [IP4_ARP_NEXT_DROP] = "error-drop",}
2186,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002187
Ed Warnickecb9cada2015-12-08 15:45:58 -07002188#define foreach_notrace_ip4_arp_error \
2189_(DROP) \
2190_(REQUEST_SENT) \
2191_(REPLICATE_DROP) \
2192_(REPLICATE_FAIL)
2193
Dave Barachd7cb1b52016-12-09 09:52:16 -05002194clib_error_t *
2195arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002196{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002197 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198
2199 /* don't trace ARP request packets */
2200#define _(a) \
2201 vnet_pcap_drop_trace_filter_add_del \
2202 (rt->errors[IP4_ARP_ERROR_##a], \
2203 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002204 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002205#undef _
2206 return 0;
2207}
2208
Dave Barachd7cb1b52016-12-09 09:52:16 -05002209VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002210
2211
2212/* Send an ARP request to see if given destination is reachable on given interface. */
2213clib_error_t *
2214ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2215{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002216 vnet_main_t *vnm = vnet_get_main ();
2217 ip4_main_t *im = &ip4_main;
2218 ethernet_arp_header_t *h;
2219 ip4_address_t *src;
2220 ip_interface_address_t *ia;
2221 ip_adjacency_t *adj;
2222 vnet_hw_interface_t *hi;
2223 vnet_sw_interface_t *si;
2224 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002225 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002226 u32 bi = 0;
2227
2228 si = vnet_get_sw_interface (vnm, sw_if_index);
2229
2230 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2231 {
2232 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002233 format_ip4_address, dst,
2234 format_vnet_sw_if_index_name, vnm,
2235 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236 }
2237
Dave Barachd7cb1b52016-12-09 09:52:16 -05002238 src =
2239 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2240 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002241 {
2242 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002243 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002244 (0,
2245 "no matching interface address for destination %U (interface %U)",
2246 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2247 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248 }
2249
Neale Ranns7a272742017-05-30 02:08:14 -07002250 ip46_address_t nh = {
2251 .ip4 = *dst,
2252 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07002253
Neale Ranns7a272742017-05-30 02:08:14 -07002254 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2255 VNET_LINK_IP4, &nh, sw_if_index);
2256 adj = adj_get (ai);
2257
2258 h = vlib_packet_template_get_packet (vm,
2259 &im->ip4_arp_request_packet_template,
2260 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002261
2262 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002263 if (PREDICT_FALSE (!hi->hw_address))
2264 {
2265 return clib_error_return (0, "%U: interface %U do not support ip probe",
2266 format_ip4_address, dst,
2267 format_vnet_sw_if_index_name, vnm,
2268 sw_if_index);
2269 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270
Dave Barachd7cb1b52016-12-09 09:52:16 -05002271 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2272 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002273
2274 h->ip4_over_ethernet[0].ip4 = src[0];
2275 h->ip4_over_ethernet[1].ip4 = dst[0];
2276
2277 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002278 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2279 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280
2281 /* Add encapsulation string for software interface (e.g. ethernet header). */
2282 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2283 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2284
2285 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002286 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2287 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 to_next[0] = bi;
2289 f->n_vectors = 1;
2290 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2291 }
2292
Neale Ranns7a272742017-05-30 02:08:14 -07002293 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294 return /* no error */ 0;
2295}
2296
Dave Barachd7cb1b52016-12-09 09:52:16 -05002297typedef enum
2298{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002300 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301} ip4_rewrite_next_t;
2302
2303always_inline uword
2304ip4_rewrite_inline (vlib_main_t * vm,
2305 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002306 vlib_frame_t * frame,
2307 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002308{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002309 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2310 u32 *from = vlib_frame_vector_args (frame);
2311 u32 n_left_from, n_left_to_next, *to_next, next_index;
2312 vlib_node_runtime_t *error_node =
2313 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002314
2315 n_left_from = frame->n_vectors;
2316 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002317 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002318
Ed Warnickecb9cada2015-12-08 15:45:58 -07002319 while (n_left_from > 0)
2320 {
2321 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2322
2323 while (n_left_from >= 4 && n_left_to_next >= 2)
2324 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002325 ip_adjacency_t *adj0, *adj1;
2326 vlib_buffer_t *p0, *p1;
2327 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002328 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2329 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002331
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332 /* Prefetch next iteration. */
2333 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002334 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002335
2336 p2 = vlib_get_buffer (vm, from[2]);
2337 p3 = vlib_get_buffer (vm, from[3]);
2338
2339 vlib_prefetch_buffer_header (p2, STORE);
2340 vlib_prefetch_buffer_header (p3, STORE);
2341
2342 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2343 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2344 }
2345
2346 pi0 = to_next[0] = from[0];
2347 pi1 = to_next[1] = from[1];
2348
2349 from += 2;
2350 n_left_from -= 2;
2351 to_next += 2;
2352 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002353
Ed Warnickecb9cada2015-12-08 15:45:58 -07002354 p0 = vlib_get_buffer (vm, pi0);
2355 p1 = vlib_get_buffer (vm, pi1);
2356
Neale Rannsf06aea52016-11-29 06:51:37 -08002357 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2358 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002359
Neale Ranns1bd01092017-03-15 15:41:17 -04002360 /*
2361 * pre-fetch the per-adjacency counters
2362 */
2363 if (do_counters)
2364 {
2365 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002366 thread_index, adj_index0);
Neale Ranns1bd01092017-03-15 15:41:17 -04002367 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002368 thread_index, adj_index1);
Neale Ranns1bd01092017-03-15 15:41:17 -04002369 }
2370
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371 ip0 = vlib_buffer_get_current (p0);
2372 ip1 = vlib_buffer_get_current (p1);
2373
2374 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002375 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002376
2377 /* Decrement TTL & update checksum.
2378 Works either endian, so no need for byte swap. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002379 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002381 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382
2383 /* Input node should have reject packets with ttl 0. */
2384 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385
2386 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388
2389 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392
Dave Barachd7cb1b52016-12-09 09:52:16 -05002393 /*
2394 * If the ttl drops below 1 when forwarding, generate
2395 * an ICMP response.
2396 */
2397 if (PREDICT_FALSE (ttl0 <= 0))
2398 {
2399 error0 = IP4_ERROR_TIME_EXPIRED;
2400 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2401 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2402 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2403 0);
2404 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2405 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002406
2407 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002408 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002409 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Neale Rannsf06aea52016-11-29 06:51:37 -08002410 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002411 else
2412 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002413 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002414 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002415 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002416 {
2417 i32 ttl1 = ip1->ttl;
2418
2419 /* Input node should have reject packets with ttl 0. */
2420 ASSERT (ip1->ttl > 0);
2421
2422 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2423 checksum1 += checksum1 >= 0xffff;
2424
2425 ip1->checksum = checksum1;
2426 ttl1 -= 1;
2427 ip1->ttl = ttl1;
2428
Dave Barachd7cb1b52016-12-09 09:52:16 -05002429 /*
2430 * If the ttl drops below 1 when forwarding, generate
2431 * an ICMP response.
2432 */
2433 if (PREDICT_FALSE (ttl1 <= 0))
2434 {
2435 error1 = IP4_ERROR_TIME_EXPIRED;
2436 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2437 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2438 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2439 0);
2440 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2441 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002442
2443 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002444 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002445 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002446 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002447 else
2448 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002449 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002450 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002451
2452 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002453 adj0 = adj_get (adj_index0);
2454 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002455
Dave Barachd7cb1b52016-12-09 09:52:16 -05002456 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002457 rw_len0 = adj0[0].rewrite_header.data_bytes;
2458 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002459 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2460 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002461
Dave Barachd7cb1b52016-12-09 09:52:16 -05002462 /* Check MTU of outgoing interface. */
2463 error0 =
2464 (vlib_buffer_length_in_chain (vm, p0) >
2465 adj0[0].
2466 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2467 error0);
2468 error1 =
2469 (vlib_buffer_length_in_chain (vm, p1) >
2470 adj1[0].
2471 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2472 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002473
Dave Barachd7cb1b52016-12-09 09:52:16 -05002474 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2475 * to see the IP headerr */
2476 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2477 {
Damjan Marion892e0762016-12-09 18:52:05 +01002478 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002479 p0->current_data -= rw_len0;
2480 p0->current_length += rw_len0;
2481 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2482 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002483
Neale Rannsb069a692017-03-15 12:34:25 -04002484 if (PREDICT_FALSE
2485 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2486 vnet_feature_arc_start (lm->output_feature_arc_index,
2487 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002488 }
2489 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2490 {
Damjan Marion892e0762016-12-09 18:52:05 +01002491 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002492 p1->current_data -= rw_len1;
2493 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002494
Dave Barachd7cb1b52016-12-09 09:52:16 -05002495 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2496 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002497
Neale Rannsb069a692017-03-15 12:34:25 -04002498 if (PREDICT_FALSE
2499 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2500 vnet_feature_arc_start (lm->output_feature_arc_index,
2501 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002502 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002503
2504 /* Guess we are only writing on simple Ethernet header. */
2505 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002506 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002507
Neale Ranns044183f2017-01-24 01:34:25 -08002508 /*
2509 * Bump the per-adjacency counters
2510 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002511 if (do_counters)
2512 {
2513 vlib_increment_combined_counter
2514 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002515 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002516 adj_index0, 1,
2517 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002518
Neale Ranns9c6a6132017-02-21 05:33:14 -08002519 vlib_increment_combined_counter
2520 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002521 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002522 adj_index1, 1,
2523 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2524 }
Neale Ranns044183f2017-01-24 01:34:25 -08002525
Neale Ranns5e575b12016-10-03 09:40:25 +01002526 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002527 {
2528 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2529 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2530 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002531 if (is_mcast)
2532 {
2533 /*
2534 * copy bytes from the IP address into the MAC rewrite
2535 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002536 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2537 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002538 }
Dave Barach75fc8542016-10-11 16:16:02 -04002539
Ed Warnickecb9cada2015-12-08 15:45:58 -07002540 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2541 to_next, n_left_to_next,
2542 pi0, pi1, next0, next1);
2543 }
2544
2545 while (n_left_from > 0 && n_left_to_next > 0)
2546 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002547 ip_adjacency_t *adj0;
2548 vlib_buffer_t *p0;
2549 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002550 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002551 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002552
Ed Warnickecb9cada2015-12-08 15:45:58 -07002553 pi0 = to_next[0] = from[0];
2554
2555 p0 = vlib_get_buffer (vm, pi0);
2556
Neale Rannsf06aea52016-11-29 06:51:37 -08002557 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558
Neale Ranns107e7d42017-04-11 09:55:19 -07002559 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002560
Ed Warnickecb9cada2015-12-08 15:45:58 -07002561 ip0 = vlib_buffer_get_current (p0);
2562
2563 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002564 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565
2566 /* Decrement TTL & update checksum. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002567 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002568 {
2569 i32 ttl0 = ip0->ttl;
2570
2571 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2572
2573 checksum0 += checksum0 >= 0xffff;
2574
2575 ip0->checksum = checksum0;
2576
2577 ASSERT (ip0->ttl > 0);
2578
2579 ttl0 -= 1;
2580
2581 ip0->ttl = ttl0;
2582
Dave Barach2c0a4f42017-06-29 09:30:15 -04002583 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002584 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002585
Dave Barachd7cb1b52016-12-09 09:52:16 -05002586 if (PREDICT_FALSE (ttl0 <= 0))
2587 {
2588 /*
2589 * If the ttl drops below 1 when forwarding, generate
2590 * an ICMP response.
2591 */
2592 error0 = IP4_ERROR_TIME_EXPIRED;
2593 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2594 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2595 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2596 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2597 0);
2598 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002599 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002600 else
2601 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002602 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002603 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002604
Neale Ranns1bd01092017-03-15 15:41:17 -04002605 if (do_counters)
2606 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002607 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002608
Ed Warnickecb9cada2015-12-08 15:45:58 -07002609 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002610 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002611 if (is_mcast)
2612 {
2613 /*
2614 * copy bytes from the IP address into the MAC rewrite
2615 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002616 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002617 }
Dave Barach75fc8542016-10-11 16:16:02 -04002618
Dave Barachd7cb1b52016-12-09 09:52:16 -05002619 /* Update packet buffer attributes/set output interface. */
2620 rw_len0 = adj0[0].rewrite_header.data_bytes;
2621 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002622
Neale Ranns1bd01092017-03-15 15:41:17 -04002623 if (do_counters)
2624 vlib_increment_combined_counter
2625 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002626 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002627 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002628
Dave Barachd7cb1b52016-12-09 09:52:16 -05002629 /* Check MTU of outgoing interface. */
2630 error0 = (vlib_buffer_length_in_chain (vm, p0)
2631 > adj0[0].rewrite_header.max_l3_packet_bytes
2632 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002633
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002635
Dave Barachd7cb1b52016-12-09 09:52:16 -05002636 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2637 * to see the IP headerr */
2638 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2639 {
2640 p0->current_data -= rw_len0;
2641 p0->current_length += rw_len0;
2642 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002643
Dave Barachd7cb1b52016-12-09 09:52:16 -05002644 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2645 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002646
Neale Ranns5e575b12016-10-03 09:40:25 +01002647 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002648 {
2649 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002650 }
2651
Neale Rannsb069a692017-03-15 12:34:25 -04002652 if (PREDICT_FALSE
2653 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2654 vnet_feature_arc_start (lm->output_feature_arc_index,
2655 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002656
Dave Barachd7cb1b52016-12-09 09:52:16 -05002657 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002658
Ed Warnickecb9cada2015-12-08 15:45:58 -07002659 from += 1;
2660 n_left_from -= 1;
2661 to_next += 1;
2662 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002663
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2665 to_next, n_left_to_next,
2666 pi0, next0);
2667 }
Dave Barach75fc8542016-10-11 16:16:02 -04002668
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2670 }
2671
2672 /* Need to do trace after rewrites to pick up new packet data. */
2673 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002674 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675
2676 return frame->n_vectors;
2677}
2678
Dave Barach132d51d2016-07-07 10:10:17 -04002679
Neale Rannsf06aea52016-11-29 06:51:37 -08002680/** @brief IPv4 rewrite node.
2681 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002682
2683 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2684 header checksum, fetch the ip adjacency, check the outbound mtu,
2685 apply the adjacency rewrite, and send pkts to the adjacency
2686 rewrite header's rewrite_next_index.
2687
2688 @param vm vlib_main_t corresponding to the current thread
2689 @param node vlib_node_runtime_t
2690 @param frame vlib_frame_t whose contents should be dispatched
2691
2692 @par Graph mechanics: buffer metadata, next index usage
2693
2694 @em Uses:
2695 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2696 - the rewrite adjacency index
2697 - <code>adj->lookup_next_index</code>
2698 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002699 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002700 - <code>adj->rewrite_header</code>
2701 - Rewrite string length, rewrite string, next_index
2702
2703 @em Sets:
2704 - <code>b->current_data, b->current_length</code>
2705 - Updated net of applying the rewrite string
2706
2707 <em>Next Indices:</em>
2708 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002709 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002710*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002711static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002712ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002713 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002714{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002715 if (adj_are_counters_enabled ())
2716 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2717 else
2718 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002719}
2720
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002721static uword
2722ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002723 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002724{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002725 if (adj_are_counters_enabled ())
2726 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2727 else
2728 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002729}
2730
Neale Ranns32e1c012016-11-22 17:07:28 +00002731static uword
2732ip4_rewrite_mcast (vlib_main_t * vm,
2733 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002734{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002735 if (adj_are_counters_enabled ())
2736 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2737 else
2738 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002739}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002740
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002741static uword
2742ip4_mcast_midchain (vlib_main_t * vm,
2743 vlib_node_runtime_t * node, vlib_frame_t * frame)
2744{
2745 if (adj_are_counters_enabled ())
2746 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2747 else
2748 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2749}
2750
Neale Ranns32e1c012016-11-22 17:07:28 +00002751/* *INDENT-OFF* */
2752VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2753 .function = ip4_rewrite,
2754 .name = "ip4-rewrite",
2755 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002756
Neale Ranns32e1c012016-11-22 17:07:28 +00002757 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002758
Neale Ranns32e1c012016-11-22 17:07:28 +00002759 .n_next_nodes = 2,
2760 .next_nodes = {
2761 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2762 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2763 },
2764};
2765VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2766
2767VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2768 .function = ip4_rewrite_mcast,
2769 .name = "ip4-rewrite-mcast",
2770 .vector_size = sizeof (u32),
2771
2772 .format_trace = format_ip4_rewrite_trace,
2773 .sibling_of = "ip4-rewrite",
2774};
2775VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2776
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002777VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2778 .function = ip4_mcast_midchain,
2779 .name = "ip4-mcast-midchain",
2780 .vector_size = sizeof (u32),
2781
2782 .format_trace = format_ip4_rewrite_trace,
2783 .sibling_of = "ip4-rewrite",
2784};
2785VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2786
Neale Ranns32e1c012016-11-22 17:07:28 +00002787VLIB_REGISTER_NODE (ip4_midchain_node) = {
2788 .function = ip4_midchain,
2789 .name = "ip4-midchain",
2790 .vector_size = sizeof (u32),
2791 .format_trace = format_ip4_forward_next_trace,
2792 .sibling_of = "ip4-rewrite",
2793};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002794VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002795/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002796
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797static clib_error_t *
2798add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002799 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002801 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002802 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002803 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002804 u32 sw_if_index, table_id;
2805
2806 sw_if_index = ~0;
2807
Dave Barachd7cb1b52016-12-09 09:52:16 -05002808 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002809 {
2810 error = clib_error_return (0, "unknown interface `%U'",
2811 format_unformat_error, input);
2812 goto done;
2813 }
2814
2815 if (unformat (input, "%d", &table_id))
2816 ;
2817 else
2818 {
2819 error = clib_error_return (0, "expected table id `%U'",
2820 format_unformat_error, input);
2821 goto done;
2822 }
2823
Neale Ranns4008ac92017-02-13 23:20:04 -08002824 /*
2825 * If the interface already has in IP address, then a change int
2826 * VRF is not allowed. The IP address applied must first be removed.
2827 * We do not do that automatically here, since VPP has no knowledge
2828 * of whether thoses subnets are valid in the destination VRF.
2829 */
2830 /* *INDENT-OFF* */
2831 foreach_ip_interface_address (&ip4_main.lookup_main,
2832 ia, sw_if_index,
2833 1 /* honor unnumbered */,
2834 ({
2835 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002836
Neale Ranns4008ac92017-02-13 23:20:04 -08002837 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2838 error = clib_error_return (0, "interface %U has address %U",
2839 format_vnet_sw_if_index_name, vnm,
2840 sw_if_index,
2841 format_ip4_address, a);
2842 goto done;
2843 }));
2844 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002845
Neale Ranns4008ac92017-02-13 23:20:04 -08002846{
2847 ip4_main_t *im = &ip4_main;
2848 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002849
Neale Ranns4008ac92017-02-13 23:20:04 -08002850 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2851
2852 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2853 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2854
2855 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2856 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2857 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2858}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002859
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002861return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002862}
2863
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002864/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002865 * Place the indicated interface into the supplied IPv4 FIB table (also known
2866 * as a VRF). If the FIB table does not exist, this command creates it. To
2867 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2868 * FIB table will only be displayed if a route has been added to the table, or
2869 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002870 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002871 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002872 * @note IP addresses added after setting the interface IP table are added to
2873 * the indicated FIB table. If an IP address is added prior to changing the
2874 * table then this is an error. The control plane must remove these addresses
2875 * first and then change the table. VPP will not automatically move the
2876 * addresses from the old to the new table as it does not know the validity
2877 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002878 *
2879 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002880 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2881 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002882 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002883/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002884VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2885{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002886 .path = "set interface ip table",
2887 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002888 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889};
Billy McFall0683c9c2016-10-13 08:27:31 -04002890/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002891
Dave Barachd7cb1b52016-12-09 09:52:16 -05002892int
2893ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2894{
2895 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002896 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002897 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002898
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002899 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002900
Neale Ranns04a75e32017-03-23 06:46:01 -07002901 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002902 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2903 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002904
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002905 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002906
Dave Barachd7cb1b52016-12-09 09:52:16 -05002907 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002908}
Dave Barach75fc8542016-10-11 16:16:02 -04002909
Ed Warnickecb9cada2015-12-08 15:45:58 -07002910static clib_error_t *
2911test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002912 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002913{
Billy McFall309fe062016-10-14 07:37:33 -04002914 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002915 u32 table_id = 0;
2916 f64 count = 1;
2917 u32 n;
2918 int i;
2919 ip4_address_t ip4_base_address;
2920 u64 errors = 0;
2921
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2923 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002924 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002925 {
2926 /* Make sure the entry exists. */
2927 fib = ip4_fib_get (table_id);
2928 if ((fib) && (fib->index != table_id))
2929 return clib_error_return (0, "<fib-index> %d does not exist",
2930 table_id);
2931 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002932 else if (unformat (input, "count %f", &count))
2933 ;
2934
2935 else if (unformat (input, "%U",
2936 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002937 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002938 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002939 return clib_error_return (0, "unknown input `%U'",
2940 format_unformat_error, input);
2941 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002942
2943 n = count;
2944
2945 for (i = 0; i < n; i++)
2946 {
2947 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002948 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002949
Dave Barach75fc8542016-10-11 16:16:02 -04002950 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002951 clib_host_to_net_u32 (1 +
2952 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002953 }
2954
Dave Barach75fc8542016-10-11 16:16:02 -04002955 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002956 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2957 else
2958 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2959
2960 return 0;
2961}
2962
Billy McFall0683c9c2016-10-13 08:27:31 -04002963/*?
2964 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2965 * given FIB table to determine if there is a conflict with the
2966 * adjacency table. The fib-id can be determined by using the
2967 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2968 * of 0 is used.
2969 *
2970 * @todo This command uses fib-id, other commands use table-id (not
2971 * just a name, they are different indexes). Would like to change this
2972 * to table-id for consistency.
2973 *
2974 * @cliexpar
2975 * Example of how to run the test lookup command:
2976 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2977 * No errors in 2 lookups
2978 * @cliexend
2979?*/
2980/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002981VLIB_CLI_COMMAND (lookup_test_command, static) =
2982{
2983 .path = "test lookup",
2984 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2985 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002986};
Billy McFall0683c9c2016-10-13 08:27:31 -04002987/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002988
Dave Barachd7cb1b52016-12-09 09:52:16 -05002989int
2990vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991{
Neale Ranns107e7d42017-04-11 09:55:19 -07002992 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002993
Neale Ranns107e7d42017-04-11 09:55:19 -07002994 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2995
2996 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002997 return VNET_API_ERROR_NO_SUCH_FIB;
2998
Neale Ranns227038a2017-04-21 01:07:59 -07002999 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3000 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003001
Ed Warnickecb9cada2015-12-08 15:45:58 -07003002 return 0;
3003}
Dave Barach75fc8542016-10-11 16:16:02 -04003004
Ed Warnickecb9cada2015-12-08 15:45:58 -07003005static clib_error_t *
3006set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003007 unformat_input_t * input,
3008 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003009{
3010 int matched = 0;
3011 u32 table_id = 0;
3012 u32 flow_hash_config = 0;
3013 int rv;
3014
Dave Barachd7cb1b52016-12-09 09:52:16 -05003015 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3016 {
3017 if (unformat (input, "table %d", &table_id))
3018 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019#define _(a,v) \
3020 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003021 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003023 else
3024 break;
3025 }
Dave Barach75fc8542016-10-11 16:16:02 -04003026
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027 if (matched == 0)
3028 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003029 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003030
Ed Warnickecb9cada2015-12-08 15:45:58 -07003031 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3032 switch (rv)
3033 {
3034 case 0:
3035 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003036
Ed Warnickecb9cada2015-12-08 15:45:58 -07003037 case VNET_API_ERROR_NO_SUCH_FIB:
3038 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003039
Ed Warnickecb9cada2015-12-08 15:45:58 -07003040 default:
3041 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3042 break;
3043 }
Dave Barach75fc8542016-10-11 16:16:02 -04003044
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045 return 0;
3046}
Dave Barach75fc8542016-10-11 16:16:02 -04003047
Billy McFall0683c9c2016-10-13 08:27:31 -04003048/*?
3049 * Configure the set of IPv4 fields used by the flow hash.
3050 *
3051 * @cliexpar
3052 * Example of how to set the flow hash on a given table:
3053 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3054 * Example of display the configured flow hash:
3055 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003056 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3057 * 0.0.0.0/0
3058 * unicast-ip4-chain
3059 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3060 * [0] [@0]: dpo-drop ip6
3061 * 0.0.0.0/32
3062 * unicast-ip4-chain
3063 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3064 * [0] [@0]: dpo-drop ip6
3065 * 224.0.0.0/8
3066 * unicast-ip4-chain
3067 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3068 * [0] [@0]: dpo-drop ip6
3069 * 6.0.1.2/32
3070 * unicast-ip4-chain
3071 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3072 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3073 * 7.0.0.1/32
3074 * unicast-ip4-chain
3075 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3076 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3077 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3078 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3079 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3080 * 240.0.0.0/8
3081 * unicast-ip4-chain
3082 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3083 * [0] [@0]: dpo-drop ip6
3084 * 255.255.255.255/32
3085 * unicast-ip4-chain
3086 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3087 * [0] [@0]: dpo-drop ip6
3088 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3089 * 0.0.0.0/0
3090 * unicast-ip4-chain
3091 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3092 * [0] [@0]: dpo-drop ip6
3093 * 0.0.0.0/32
3094 * unicast-ip4-chain
3095 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3096 * [0] [@0]: dpo-drop ip6
3097 * 172.16.1.0/24
3098 * unicast-ip4-chain
3099 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3100 * [0] [@4]: ipv4-glean: af_packet0
3101 * 172.16.1.1/32
3102 * unicast-ip4-chain
3103 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3104 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3105 * 172.16.1.2/32
3106 * unicast-ip4-chain
3107 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3108 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3109 * 172.16.2.0/24
3110 * unicast-ip4-chain
3111 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3112 * [0] [@4]: ipv4-glean: af_packet1
3113 * 172.16.2.1/32
3114 * unicast-ip4-chain
3115 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3116 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3117 * 224.0.0.0/8
3118 * unicast-ip4-chain
3119 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3120 * [0] [@0]: dpo-drop ip6
3121 * 240.0.0.0/8
3122 * unicast-ip4-chain
3123 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3124 * [0] [@0]: dpo-drop ip6
3125 * 255.255.255.255/32
3126 * unicast-ip4-chain
3127 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3128 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003129 * @cliexend
3130?*/
3131/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003132VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3133{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003135 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003136 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003137 .function = set_ip_flow_hash_command_fn,
3138};
Billy McFall0683c9c2016-10-13 08:27:31 -04003139/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003140
Dave Barachd7cb1b52016-12-09 09:52:16 -05003141int
3142vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3143 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003144{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003145 vnet_main_t *vnm = vnet_get_main ();
3146 vnet_interface_main_t *im = &vnm->interface_main;
3147 ip4_main_t *ipm = &ip4_main;
3148 ip_lookup_main_t *lm = &ipm->lookup_main;
3149 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003150 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003151
3152 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3153 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3154
3155 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3156 return VNET_API_ERROR_NO_SUCH_ENTRY;
3157
3158 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003159 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003160
Neale Rannsdf089a82016-10-02 16:39:06 +01003161 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3162
3163 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003164 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003165 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003166 .fp_len = 32,
3167 .fp_proto = FIB_PROTOCOL_IP4,
3168 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003169 };
3170 u32 fib_index;
3171
Dave Barachd7cb1b52016-12-09 09:52:16 -05003172 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3173 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003174
3175
Dave Barachd7cb1b52016-12-09 09:52:16 -05003176 if (table_index != (u32) ~ 0)
3177 {
3178 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003179
Dave Barachd7cb1b52016-12-09 09:52:16 -05003180 dpo_set (&dpo,
3181 DPO_CLASSIFY,
3182 DPO_PROTO_IP4,
3183 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003184
Dave Barachd7cb1b52016-12-09 09:52:16 -05003185 fib_table_entry_special_dpo_add (fib_index,
3186 &pfx,
3187 FIB_SOURCE_CLASSIFY,
3188 FIB_ENTRY_FLAG_NONE, &dpo);
3189 dpo_reset (&dpo);
3190 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003191 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003192 {
3193 fib_table_entry_special_remove (fib_index,
3194 &pfx, FIB_SOURCE_CLASSIFY);
3195 }
3196 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003197
Ed Warnickecb9cada2015-12-08 15:45:58 -07003198 return 0;
3199}
3200
3201static clib_error_t *
3202set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003203 unformat_input_t * input,
3204 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003205{
3206 u32 table_index = ~0;
3207 int table_index_set = 0;
3208 u32 sw_if_index = ~0;
3209 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003210
Dave Barachd7cb1b52016-12-09 09:52:16 -05003211 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3212 {
3213 if (unformat (input, "table-index %d", &table_index))
3214 table_index_set = 1;
3215 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3216 vnet_get_main (), &sw_if_index))
3217 ;
3218 else
3219 break;
3220 }
Dave Barach75fc8542016-10-11 16:16:02 -04003221
Ed Warnickecb9cada2015-12-08 15:45:58 -07003222 if (table_index_set == 0)
3223 return clib_error_return (0, "classify table-index must be specified");
3224
3225 if (sw_if_index == ~0)
3226 return clib_error_return (0, "interface / subif must be specified");
3227
3228 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3229
3230 switch (rv)
3231 {
3232 case 0:
3233 break;
3234
3235 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3236 return clib_error_return (0, "No such interface");
3237
3238 case VNET_API_ERROR_NO_SUCH_ENTRY:
3239 return clib_error_return (0, "No such classifier table");
3240 }
3241 return 0;
3242}
3243
Billy McFall0683c9c2016-10-13 08:27:31 -04003244/*?
3245 * Assign a classification table to an interface. The classification
3246 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3247 * commands. Once the table is create, use this command to filter packets
3248 * on an interface.
3249 *
3250 * @cliexpar
3251 * Example of how to assign a classification table to an interface:
3252 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3253?*/
3254/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003255VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3256{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003257 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003258 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003259 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003260 .function = set_ip_classify_command_fn,
3261};
Billy McFall0683c9c2016-10-13 08:27:31 -04003262/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003263
3264/*
3265 * fd.io coding-style-patch-verification: ON
3266 *
3267 * Local Variables:
3268 * eval: (c-set-style "gnu")
3269 * End:
3270 */