blob: d86f22ca984084c8d17a2b08e206a4bc16641f70 [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
720 a->neighbor_probe_adj_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721
Neale Ranns9a69a602017-03-26 10:56:33 -0700722 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500723 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700724 /* a /30 or shorter - add a glean for the network address */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100725 fib_node_index_t fei;
726
Neale Ranns32e1c012016-11-22 17:07:28 +0000727 fei = fib_table_entry_update_one_path (fib_index, &pfx,
728 FIB_SOURCE_INTERFACE,
729 (FIB_ENTRY_FLAG_CONNECTED |
730 FIB_ENTRY_FLAG_ATTACHED),
731 FIB_PROTOCOL_IP4,
732 /* No next-hop address */
733 NULL,
734 sw_if_index,
735 // invalid FIB index
736 ~0,
737 1,
738 // no out-label stack
739 NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500740 FIB_ROUTE_PATH_FLAG_NONE);
741 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100742
Neale Ranns9a69a602017-03-26 10:56:33 -0700743 /* Add the two broadcast addresses as drop */
744 fib_prefix_t net_pfx = {
745 .fp_len = 32,
746 .fp_proto = FIB_PROTOCOL_IP4,
747 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
748 };
749 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
750 fib_table_entry_special_add(fib_index,
751 &net_pfx,
752 FIB_SOURCE_INTERFACE,
753 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700754 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700755 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
756 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
757 fib_table_entry_special_add(fib_index,
758 &net_pfx,
759 FIB_SOURCE_INTERFACE,
760 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700761 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700762 }
763 else if (pfx.fp_len == 31)
764 {
765 u32 mask = clib_host_to_net_u32(1);
766 fib_prefix_t net_pfx = pfx;
767
768 net_pfx.fp_len = 32;
769 net_pfx.fp_addr.ip4.as_u32 ^= mask;
770
771 /* a /31 - add the other end as an attached host */
772 fib_table_entry_update_one_path (fib_index, &net_pfx,
773 FIB_SOURCE_INTERFACE,
774 (FIB_ENTRY_FLAG_ATTACHED),
775 FIB_PROTOCOL_IP4,
776 &net_pfx.fp_addr,
777 sw_if_index,
778 // invalid FIB index
779 ~0,
780 1,
781 NULL,
782 FIB_ROUTE_PATH_FLAG_NONE);
783 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100784 pfx.fp_len = 32;
785
786 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500787 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100788 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500789 lm->classify_table_index_by_sw_if_index[sw_if_index];
790 if (classify_table_index != (u32) ~ 0)
791 {
792 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100793
Dave Barachd7cb1b52016-12-09 09:52:16 -0500794 dpo_set (&dpo,
795 DPO_CLASSIFY,
796 DPO_PROTO_IP4,
797 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100798
Dave Barachd7cb1b52016-12-09 09:52:16 -0500799 fib_table_entry_special_dpo_add (fib_index,
800 &pfx,
801 FIB_SOURCE_CLASSIFY,
802 FIB_ENTRY_FLAG_NONE, &dpo);
803 dpo_reset (&dpo);
804 }
805 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100806
Neale Ranns32e1c012016-11-22 17:07:28 +0000807 fib_table_entry_update_one_path (fib_index, &pfx,
808 FIB_SOURCE_INTERFACE,
809 (FIB_ENTRY_FLAG_CONNECTED |
810 FIB_ENTRY_FLAG_LOCAL),
811 FIB_PROTOCOL_IP4,
812 &pfx.fp_addr,
813 sw_if_index,
814 // invalid FIB index
815 ~0,
816 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500817 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700818}
819
820static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100821ip4_del_interface_routes (ip4_main_t * im,
822 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500825 fib_prefix_t pfx = {
826 .fp_len = address_length,
827 .fp_proto = FIB_PROTOCOL_IP4,
828 .fp_addr.ip4 = *address,
829 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Neale Ranns9a69a602017-03-26 10:56:33 -0700831 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100832 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700833 fib_prefix_t net_pfx = {
834 .fp_len = 32,
835 .fp_proto = FIB_PROTOCOL_IP4,
836 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
837 };
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);
842 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
843 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
844 fib_table_entry_special_remove(fib_index,
845 &net_pfx,
846 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500847 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100848 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700849 else if (pfx.fp_len == 31)
850 {
851 u32 mask = clib_host_to_net_u32(1);
852 fib_prefix_t net_pfx = pfx;
853
854 net_pfx.fp_len = 32;
855 net_pfx.fp_addr.ip4.as_u32 ^= mask;
856
857 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
858 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859
Dave Barachd7cb1b52016-12-09 09:52:16 -0500860 pfx.fp_len = 32;
861 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862}
863
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100864void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500865ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100866{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500867 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100869 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
870
871 /*
872 * enable/disable only on the 1<->0 transition
873 */
874 if (is_enable)
875 {
876 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500877 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100878 }
879 else
880 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500881 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100882 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500883 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100884 }
Damjan Marion4d489932016-12-09 03:21:27 -0800885 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
886 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100887
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100888
Neale Ranns180279b2017-03-16 15:49:09 -0400889 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop",
890 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100891}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700892
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893static clib_error_t *
894ip4_add_del_interface_address_internal (vlib_main_t * vm,
895 u32 sw_if_index,
896 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500897 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500899 vnet_main_t *vnm = vnet_get_main ();
900 ip4_main_t *im = &ip4_main;
901 ip_lookup_main_t *lm = &im->lookup_main;
902 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500904 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700905
906 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
907 ip4_addr_fib_init (&ip4_af, address,
908 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
909 vec_add1 (addr_fib, ip4_af);
910
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100911 /* FIXME-LATER
912 * there is no support for adj-fib handling in the presence of overlapping
913 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
914 * most routers do.
915 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000916 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100919 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500920 with an existing address. */
921 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000922 foreach_ip_interface_address
923 (&im->lookup_main, ia, sw_if_index,
924 0 /* honor unnumbered */ ,
925 ({
926 ip4_address_t * x =
927 ip_interface_address_get_address
928 (&im->lookup_main, ia);
929 if (ip4_destination_matches_route
930 (im, address, x, ia->address_length) ||
931 ip4_destination_matches_route (im,
932 x,
933 address,
934 address_length))
935 return
936 clib_error_create
937 ("failed to add %U which conflicts with %U for interface %U",
938 format_ip4_address_and_length, address,
939 address_length,
940 format_ip4_address_and_length, x,
941 ia->address_length,
942 format_vnet_sw_if_index_name, vnm,
943 sw_if_index);
944 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700945 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000946 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948 elts_before = pool_elts (lm->if_address_pool);
949
950 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500951 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952 if (error)
953 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400954
Dave Barachd7cb1b52016-12-09 09:52:16 -0500955 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100956
957 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500958 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100959 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960 ip4_add_interface_routes (sw_if_index,
961 im, ip4_af.fib_index,
962 pool_elt_at_index
963 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700964
965 /* If pool did not grow/shrink: add duplicate address. */
966 if (elts_before != pool_elts (lm->if_address_pool))
967 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500968 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969 vec_foreach (cb, im->add_del_interface_address_callbacks)
970 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500971 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972 }
973
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 vec_free (addr_fib);
976 return error;
977}
978
979clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000980ip4_add_del_interface_address (vlib_main_t * vm,
981 u32 sw_if_index,
982 ip4_address_t * address,
983 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984{
985 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500986 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700987}
988
Dave Barachd6534602016-06-14 18:38:02 -0400989/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500990/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100991VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
992{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500993 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100994 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
995 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
996};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100997
Dave Barachd7cb1b52016-12-09 09:52:16 -0500998VNET_FEATURE_INIT (ip4_flow_classify, static) =
999{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -07001001 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001002 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -07001003};
1004
Dave Barachd7cb1b52016-12-09 09:52:16 -05001005VNET_FEATURE_INIT (ip4_inacl, static) =
1006{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001007 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -04001008 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001009 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -04001010};
1011
Dave Barachd7cb1b52016-12-09 09:52:16 -05001012VNET_FEATURE_INIT (ip4_source_check_1, static) =
1013{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001014 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001015 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001016 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -04001017};
1018
Dave Barachd7cb1b52016-12-09 09:52:16 -05001019VNET_FEATURE_INIT (ip4_source_check_2, static) =
1020{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001021 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001022 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001023 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -04001024};
1025
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
1027{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001028 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -04001029 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -04001031};
1032
Dave Barachd7cb1b52016-12-09 09:52:16 -05001033VNET_FEATURE_INIT (ip4_policer_classify, static) =
1034{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001035 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001036 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001037 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001038};
1039
Dave Barachd7cb1b52016-12-09 09:52:16 -05001040VNET_FEATURE_INIT (ip4_ipsec, static) =
1041{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001042 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001043 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001044 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -04001045};
1046
Dave Barachd7cb1b52016-12-09 09:52:16 -05001047VNET_FEATURE_INIT (ip4_vpath, static) =
1048{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001049 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001050 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -05001051 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1052};
1053
Dave Barachd7cb1b52016-12-09 09:52:16 -05001054VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1055{
John Lo37682e12016-11-30 12:51:39 -05001056 .arc_name = "ip4-unicast",
1057 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001058 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001059};
1060
Dave Barachd7cb1b52016-12-09 09:52:16 -05001061VNET_FEATURE_INIT (ip4_drop, static) =
1062{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001063 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001064 .node_name = "ip4-drop",
Neale Ranns180279b2017-03-16 15:49:09 -04001065 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001066};
1067
Neale Ranns180279b2017-03-16 15:49:09 -04001068VNET_FEATURE_INIT (ip4_lookup, static) =
1069{
1070 .arc_name = "ip4-unicast",
1071 .node_name = "ip4-lookup",
1072 .runs_before = 0, /* not before any other features */
1073};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001074
Dave Barachd6534602016-06-14 18:38:02 -04001075/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001076VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1077{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001078 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001079 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
1080 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1081};
1082
Dave Barachd7cb1b52016-12-09 09:52:16 -05001083VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1084{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001085 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001086 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001087 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001088};
1089
Dave Barachd7cb1b52016-12-09 09:52:16 -05001090VNET_FEATURE_INIT (ip4_mc_drop, static) =
1091{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001092 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001093 .node_name = "ip4-drop",
Neale Ranns180279b2017-03-16 15:49:09 -04001094 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1095};
1096
1097VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1098{
1099 .arc_name = "ip4-multicast",
1100 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001101 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001102};
Dave Barach5331c722016-08-17 11:54:30 -04001103
1104/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001105VNET_FEATURE_ARC_INIT (ip4_output, static) =
1106{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001107 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001108 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion8b3191e2016-11-09 19:54:20 +01001109 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1110};
Dave Barach5331c722016-08-17 11:54:30 -04001111
Dave Barachd7cb1b52016-12-09 09:52:16 -05001112VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1113{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001114 .arc_name = "ip4-output",
1115 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001116 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1117};
1118
Dave Barachd7cb1b52016-12-09 09:52:16 -05001119VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1120{
Matus Fabian08a6f012016-11-15 06:08:51 -08001121 .arc_name = "ip4-output",
1122 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001123 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001124};
1125
1126/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001127VNET_FEATURE_INIT (ip4_interface_output, static) =
1128{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001129 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001130 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001131 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001132};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001134
Ed Warnickecb9cada2015-12-08 15:45:58 -07001135static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001136ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001138 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001140 /* Fill in lookup tables with default table (0). */
1141 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001142 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001143
Damjan Marion8b3191e2016-11-09 19:54:20 +01001144 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1145 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146
Damjan Marion8b3191e2016-11-09 19:54:20 +01001147 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1148 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150 return /* no error */ 0;
1151}
1152
1153VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1154
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155/* Global IP4 main. */
1156ip4_main_t ip4_main;
1157
1158clib_error_t *
1159ip4_lookup_init (vlib_main_t * vm)
1160{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001161 ip4_main_t *im = &ip4_main;
1162 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163 uword i;
1164
Damjan Marion8b3191e2016-11-09 19:54:20 +01001165 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1166 return error;
1167
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1169 {
1170 u32 m;
1171
1172 if (i < 32)
1173 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001174 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175 m = ~0;
1176 im->fib_masks[i] = clib_host_to_net_u32 (m);
1177 }
1178
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1180
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001181 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001182 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001183 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001184
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001186 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 pn = pg_get_node (ip4_lookup_node.index);
1188 pn->unformat_edit = unformat_pg_ip4_header;
1189 }
1190
1191 {
1192 ethernet_arp_header_t h;
1193
1194 memset (&h, 0, sizeof (h));
1195
1196 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001197 memset (h.ip4_over_ethernet[1].ethernet, 0,
1198 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
1200#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1201#define _8(f,v) h.f = v;
1202 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1203 _16 (l3_type, ETHERNET_TYPE_IP4);
1204 _8 (n_l2_address_bytes, 6);
1205 _8 (n_l3_address_bytes, 4);
1206 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1207#undef _16
1208#undef _8
1209
Dave Barachd7cb1b52016-12-09 09:52:16 -05001210 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 /* data */ &h,
1212 sizeof (h),
1213 /* alloc chunk size */ 8,
1214 "ip4 arp");
1215 }
1216
Dave Barach203c6322016-06-26 10:29:03 -04001217 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001218}
1219
1220VLIB_INIT_FUNCTION (ip4_lookup_init);
1221
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222typedef struct
1223{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001224 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001225 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001226 u32 flow_hash;
1227 u32 fib_index;
1228
1229 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001230 u8 packet_data[64 - 1 * sizeof (u32)];
1231}
1232ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001233
Dave Barachd7cb1b52016-12-09 09:52:16 -05001234u8 *
1235format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236{
1237 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1238 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001239 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001240 uword indent = format_get_indent (s);
1241 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001242 format_white_space, indent,
1243 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001244 return s;
1245}
1246
Dave Barachd7cb1b52016-12-09 09:52:16 -05001247static u8 *
1248format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001249{
1250 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1251 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001252 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253 uword indent = format_get_indent (s);
1254
John Loac8146c2016-09-27 17:44:02 -04001255 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001256 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001257 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001258 format_white_space, indent,
1259 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001260 return s;
1261}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001262
Dave Barachd7cb1b52016-12-09 09:52:16 -05001263static u8 *
1264format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001265{
1266 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1267 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001268 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001269 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001270
Vengada Govindanf1544482016-09-28 02:45:57 -07001271 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 t->fib_index, t->dpo_index, format_ip_adjacency,
1273 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001274 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001275 format_white_space, indent,
1276 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001277 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001278 return s;
1279}
1280
1281/* Common trace function for all ip4-forward next nodes. */
1282void
1283ip4_forward_next_trace (vlib_main_t * vm,
1284 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001285 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001287 u32 *from, n_left;
1288 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289
1290 n_left = frame->n_vectors;
1291 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001292
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293 while (n_left >= 4)
1294 {
1295 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001296 vlib_buffer_t *b0, *b1;
1297 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298
1299 /* Prefetch next iteration. */
1300 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1301 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1302
1303 bi0 = from[0];
1304 bi1 = from[1];
1305
1306 b0 = vlib_get_buffer (vm, bi0);
1307 b1 = vlib_get_buffer (vm, bi1);
1308
1309 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1310 {
1311 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001312 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001314 t0->fib_index =
1315 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1316 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1317 vec_elt (im->fib_index_by_sw_if_index,
1318 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001319
Damjan Marionf1213b82016-03-13 02:22:06 +01001320 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001321 vlib_buffer_get_current (b0),
1322 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 }
1324 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1325 {
1326 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001327 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001329 t1->fib_index =
1330 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1331 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1332 vec_elt (im->fib_index_by_sw_if_index,
1333 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1334 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1335 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001336 }
1337 from += 2;
1338 n_left -= 2;
1339 }
1340
1341 while (n_left >= 1)
1342 {
1343 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001344 vlib_buffer_t *b0;
1345 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346
1347 bi0 = from[0];
1348
1349 b0 = vlib_get_buffer (vm, bi0);
1350
1351 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1352 {
1353 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001354 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001355 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001356 t0->fib_index =
1357 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1358 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1359 vec_elt (im->fib_index_by_sw_if_index,
1360 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1361 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1362 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363 }
1364 from += 1;
1365 n_left -= 1;
1366 }
1367}
1368
1369static uword
1370ip4_drop_or_punt (vlib_main_t * vm,
1371 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001372 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001373{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001374 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001375 uword n_packets = frame->n_vectors;
1376
Dave Barachd7cb1b52016-12-09 09:52:16 -05001377 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001378 /* stride */ 1,
1379 n_packets,
1380 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001381 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382
1383 if (node->flags & VLIB_NODE_FLAG_TRACE)
1384 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1385
1386 return n_packets;
1387}
1388
1389static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001390ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1391{
1392 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1393}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394
1395static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001396ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1397{
1398 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1399}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400
Neale Ranns32e1c012016-11-22 17:07:28 +00001401/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001402VLIB_REGISTER_NODE (ip4_drop_node, static) =
1403{
flyingeagle239e355522017-05-03 11:29:53 +08001404 .function = ip4_drop,
1405 .name = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00001406 .vector_size = sizeof (u32),
1407 .format_trace = format_ip4_forward_next_trace,
1408 .n_next_nodes = 1,
1409 .next_nodes = {
1410 [0] = "error-drop",
1411 },
1412};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413
Dave Barachd7cb1b52016-12-09 09:52:16 -05001414VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001415
Dave Barachd7cb1b52016-12-09 09:52:16 -05001416VLIB_REGISTER_NODE (ip4_punt_node, static) =
1417{
Neale Ranns32e1c012016-11-22 17:07:28 +00001418 .function = ip4_punt,
1419 .name = "ip4-punt",
1420 .vector_size = sizeof (u32),
1421 .format_trace = format_ip4_forward_next_trace,
1422 .n_next_nodes = 1,
1423 .next_nodes = {
1424 [0] = "error-punt",
1425 },
1426};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001427
Dave Barachd7cb1b52016-12-09 09:52:16 -05001428VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Neale Ranns32e1c012016-11-22 17:07:28 +00001429/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02001430
Ed Warnickecb9cada2015-12-08 15:45:58 -07001431/* Compute TCP/UDP/ICMP4 checksum in software. */
1432u16
1433ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1434 ip4_header_t * ip0)
1435{
1436 ip_csum_t sum0;
1437 u32 ip_header_length, payload_length_host_byte_order;
1438 u32 n_this_buffer, n_bytes_left;
1439 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001440 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001441
Ed Warnickecb9cada2015-12-08 15:45:58 -07001442 /* Initialize checksum with ip header. */
1443 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001444 payload_length_host_byte_order =
1445 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1446 sum0 =
1447 clib_host_to_net_u32 (payload_length_host_byte_order +
1448 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001449
1450 if (BITS (uword) == 32)
1451 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001452 sum0 =
1453 ip_csum_with_carry (sum0,
1454 clib_mem_unaligned (&ip0->src_address, u32));
1455 sum0 =
1456 ip_csum_with_carry (sum0,
1457 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458 }
1459 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001460 sum0 =
1461 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001462
1463 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1464 data_this_buffer = (void *) ip0 + ip_header_length;
1465 if (n_this_buffer + ip_header_length > p0->current_length)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001466 n_this_buffer =
1467 p0->current_length >
1468 ip_header_length ? p0->current_length - ip_header_length : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001469 while (1)
1470 {
1471 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1472 n_bytes_left -= n_this_buffer;
1473 if (n_bytes_left == 0)
1474 break;
1475
1476 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1477 p0 = vlib_get_buffer (vm, p0->next_buffer);
1478 data_this_buffer = vlib_buffer_get_current (p0);
1479 n_this_buffer = p0->current_length;
1480 }
1481
Dave Barachd7cb1b52016-12-09 09:52:16 -05001482 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001483
1484 return sum16;
1485}
1486
John Lo37682e12016-11-30 12:51:39 -05001487u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1489{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001490 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1491 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492 u16 sum16;
1493
1494 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1495 || ip0->protocol == IP_PROTOCOL_UDP);
1496
1497 udp0 = (void *) (ip0 + 1);
1498 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1499 {
1500 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1501 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1502 return p0->flags;
1503 }
1504
1505 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1506
1507 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1508 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1509
1510 return p0->flags;
1511}
1512
Dave Barach68b0fb02017-02-28 15:15:56 -05001513/* *INDENT-OFF* */
1514VNET_FEATURE_ARC_INIT (ip4_local) =
1515{
1516 .arc_name = "ip4-local",
1517 .start_nodes = VNET_FEATURES ("ip4-local"),
1518};
1519/* *INDENT-ON* */
1520
1521static inline uword
1522ip4_local_inline (vlib_main_t * vm,
1523 vlib_node_runtime_t * node,
1524 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001526 ip4_main_t *im = &ip4_main;
1527 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001528 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001529 u32 *from, *to_next, n_left_from, n_left_to_next;
1530 vlib_node_runtime_t *error_node =
1531 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001532 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533
1534 from = vlib_frame_vector_args (frame);
1535 n_left_from = frame->n_vectors;
1536 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001537
Ed Warnickecb9cada2015-12-08 15:45:58 -07001538 if (node->flags & VLIB_NODE_FLAG_TRACE)
1539 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1540
1541 while (n_left_from > 0)
1542 {
1543 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1544
1545 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001546 {
1547 vlib_buffer_t *p0, *p1;
1548 ip4_header_t *ip0, *ip1;
1549 udp_header_t *udp0, *udp1;
1550 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1551 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1552 const dpo_id_t *dpo0, *dpo1;
1553 const load_balance_t *lb0, *lb1;
1554 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1555 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1556 i32 len_diff0, len_diff1;
1557 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1558 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001559 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001560
Dave Barachd7cb1b52016-12-09 09:52:16 -05001561 pi0 = to_next[0] = from[0];
1562 pi1 = to_next[1] = from[1];
1563 from += 2;
1564 n_left_from -= 2;
1565 to_next += 2;
1566 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001567
Dave Barach68b0fb02017-02-28 15:15:56 -05001568 next0 = next1 = IP_LOCAL_NEXT_DROP;
1569
Ed Warnickecb9cada2015-12-08 15:45:58 -07001570 p0 = vlib_get_buffer (vm, pi0);
1571 p1 = vlib_get_buffer (vm, pi1);
1572
1573 ip0 = vlib_buffer_get_current (p0);
1574 ip1 = vlib_buffer_get_current (p1);
1575
Dave Barachd7cb1b52016-12-09 09:52:16 -05001576 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1577 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001578
Dave Barach68b0fb02017-02-28 15:15:56 -05001579 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1580 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1581
1582 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1583 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1584
1585 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001586 fib_index0 =
1587 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1588 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001589
Dave Barach68b0fb02017-02-28 15:15:56 -05001590 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001591 fib_index1 =
1592 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1593 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001594
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001595 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1596 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597
Neale Ranns04a75e32017-03-23 06:46:01 -07001598 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1599 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600
John Lo3419d0b2016-06-02 09:28:37 -04001601 /* Treat IP frag packets as "experimental" protocol for now
1602 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001603 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1604 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001605
1606 if (head_of_feature_arc == 0)
1607 {
1608 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1609 goto skip_checks;
1610 }
1611
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1613 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1614 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1615 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1616
1617 flags0 = p0->flags;
1618 flags1 = p1->flags;
1619
1620 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1621 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1622
1623 udp0 = ip4_next_header (ip0);
1624 udp1 = ip4_next_header (ip1);
1625
1626 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1627 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1628 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1629
Ed Warnickecb9cada2015-12-08 15:45:58 -07001630 /* Verify UDP length. */
1631 ip_len0 = clib_net_to_host_u16 (ip0->length);
1632 ip_len1 = clib_net_to_host_u16 (ip1->length);
1633 udp_len0 = clib_net_to_host_u16 (udp0->length);
1634 udp_len1 = clib_net_to_host_u16 (udp1->length);
1635
1636 len_diff0 = ip_len0 - udp_len0;
1637 len_diff1 = ip_len1 - udp_len1;
1638
1639 len_diff0 = is_udp0 ? len_diff0 : 0;
1640 len_diff1 = is_udp1 ? len_diff1 : 0;
1641
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1643 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001644 {
1645 if (is_tcp_udp0)
1646 {
1647 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001648 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1650 good_tcp_udp0 =
1651 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1652 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1653 }
1654 if (is_tcp_udp1)
1655 {
1656 if (is_tcp_udp1
Dave Barachd7cb1b52016-12-09 09:52:16 -05001657 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001658 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1659 good_tcp_udp1 =
1660 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1661 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1662 }
1663 }
1664
1665 good_tcp_udp0 &= len_diff0 >= 0;
1666 good_tcp_udp1 &= len_diff1 >= 0;
1667
Dave Barachd7cb1b52016-12-09 09:52:16 -05001668 leaf0 =
1669 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1670 leaf1 =
1671 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001672
1673 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1674
1675 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1676 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1677
1678 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679 error0 = (is_tcp_udp0 && !good_tcp_udp0
1680 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1681 error1 = (is_tcp_udp1 && !good_tcp_udp1
1682 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001683
Dave Barachd7cb1b52016-12-09 09:52:16 -05001684 leaf0 =
1685 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1686 leaf1 =
1687 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001688
Dave Barachd7cb1b52016-12-09 09:52:16 -05001689 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1690 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1691 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001692
Dave Barachd7cb1b52016-12-09 09:52:16 -05001693 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1694 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1695 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001696
Dave Barachd7cb1b52016-12-09 09:52:16 -05001697 lb0 = load_balance_get (lbi0);
1698 lb1 = load_balance_get (lbi1);
1699 dpo0 = load_balance_get_bucket_i (lb0, 0);
1700 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001701
Dave Barach75fc8542016-10-11 16:16:02 -04001702 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001703 * Must have a route to source otherwise we drop the packet.
1704 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001705 *
1706 * The checks are:
1707 * - the source is a recieve => it's from us => bogus, do this
1708 * first since it sets a different error code.
1709 * - uRPF check for any route to source - accept if passes.
1710 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001711 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001712 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001713 dpo0->dpoi_type == DPO_RECEIVE) ?
1714 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1715 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1716 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001717 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001718 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001719 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001720 dpo1->dpoi_type == DPO_RECEIVE) ?
1721 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1722 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1723 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001724 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001725 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001726
Florin Corasa0b34a72017-03-07 01:20:52 -08001727 skip_checks:
1728
Ed Warnickecb9cada2015-12-08 15:45:58 -07001729 next0 = lm->local_next_by_ip_protocol[proto0];
1730 next1 = lm->local_next_by_ip_protocol[proto1];
1731
Dave Barachd7cb1b52016-12-09 09:52:16 -05001732 next0 =
1733 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1734 next1 =
1735 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001736
1737 p0->error = error0 ? error_node->errors[error0] : 0;
1738 p1->error = error1 ? error_node->errors[error1] : 0;
1739
Dave Barach68b0fb02017-02-28 15:15:56 -05001740 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001741 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001742 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1743 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1744 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1745 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001746 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001747
1748 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1749 n_left_to_next, pi0, pi1,
1750 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751 }
1752
1753 while (n_left_from > 0 && n_left_to_next > 0)
1754 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001755 vlib_buffer_t *p0;
1756 ip4_header_t *ip0;
1757 udp_header_t *udp0;
1758 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001760 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 i32 len_diff0;
1762 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001763 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001764 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001765 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001766
Ed Warnickecb9cada2015-12-08 15:45:58 -07001767 pi0 = to_next[0] = from[0];
1768 from += 1;
1769 n_left_from -= 1;
1770 to_next += 1;
1771 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001772
Dave Barach68b0fb02017-02-28 15:15:56 -05001773 next0 = IP_LOCAL_NEXT_DROP;
1774
Ed Warnickecb9cada2015-12-08 15:45:58 -07001775 p0 = vlib_get_buffer (vm, pi0);
1776
1777 ip0 = vlib_buffer_get_current (p0);
1778
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001780
Dave Barach68b0fb02017-02-28 15:15:56 -05001781 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1782
1783 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1784
Neale Ranns32e1c012016-11-22 17:07:28 +00001785 fib_index0 =
1786 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1787 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001789 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001790
Neale Ranns04a75e32017-03-23 06:46:01 -07001791 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001792
John Lo3419d0b2016-06-02 09:28:37 -04001793 /* Treat IP frag packets as "experimental" protocol for now
1794 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001795 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001796
1797 if (head_of_feature_arc == 0)
1798 {
1799 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1800 goto skip_check;
1801 }
1802
Ed Warnickecb9cada2015-12-08 15:45:58 -07001803 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1804 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1805
1806 flags0 = p0->flags;
1807
1808 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1809
1810 udp0 = ip4_next_header (ip0);
1811
1812 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1813 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1814
Ed Warnickecb9cada2015-12-08 15:45:58 -07001815 /* Verify UDP length. */
1816 ip_len0 = clib_net_to_host_u16 (ip0->length);
1817 udp_len0 = clib_net_to_host_u16 (udp0->length);
1818
1819 len_diff0 = ip_len0 - udp_len0;
1820
1821 len_diff0 = is_udp0 ? len_diff0 : 0;
1822
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824 {
1825 if (is_tcp_udp0)
1826 {
1827 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001828 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1830 good_tcp_udp0 =
1831 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1832 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1833 }
1834 }
1835
1836 good_tcp_udp0 &= len_diff0 >= 0;
1837
Dave Barachd7cb1b52016-12-09 09:52:16 -05001838 leaf0 =
1839 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001840
1841 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1842
1843 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1844
1845 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001846 error0 = (is_tcp_udp0 && !good_tcp_udp0
1847 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001848
Dave Barachd7cb1b52016-12-09 09:52:16 -05001849 leaf0 =
1850 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001852 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001853 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001854
Dave Barachd7cb1b52016-12-09 09:52:16 -05001855 lb0 = load_balance_get (lbi0);
1856 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001858 vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001859 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001860
Neale Ranns3ee44042016-10-03 13:05:48 +01001861 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001862 dpo0->dpoi_type == DPO_RECEIVE) ?
1863 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1864 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1865 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001866 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868
Dave Barach68b0fb02017-02-28 15:15:56 -05001869 skip_check:
1870
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871 next0 = lm->local_next_by_ip_protocol[proto0];
1872
Dave Barachd7cb1b52016-12-09 09:52:16 -05001873 next0 =
1874 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001875
Dave Barachd7cb1b52016-12-09 09:52:16 -05001876 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001877
Dave Barach68b0fb02017-02-28 15:15:56 -05001878 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001880 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1881 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001883
1884 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1885 n_left_to_next, pi0, next0);
1886
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887 }
Dave Barach75fc8542016-10-11 16:16:02 -04001888
Ed Warnickecb9cada2015-12-08 15:45:58 -07001889 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1890 }
1891
1892 return frame->n_vectors;
1893}
1894
Dave Barach68b0fb02017-02-28 15:15:56 -05001895static uword
1896ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1897{
1898 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1899}
1900
1901/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001902VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001903{
Dave Barach68b0fb02017-02-28 15:15:56 -05001904 .function = ip4_local,
1905 .name = "ip4-local",
1906 .vector_size = sizeof (u32),
1907 .format_trace = format_ip4_forward_next_trace,
1908 .n_next_nodes = IP_LOCAL_N_NEXT,
1909 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001910 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001911 [IP_LOCAL_NEXT_DROP] = "error-drop",
1912 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1913 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1914 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",},
1915};
1916/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917
1918VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1919
Dave Barach68b0fb02017-02-28 15:15:56 -05001920static uword
1921ip4_local_end_of_arc (vlib_main_t * vm,
1922 vlib_node_runtime_t * node, vlib_frame_t * frame)
1923{
1924 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1925}
1926
1927/* *INDENT-OFF* */
1928VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1929 .function = ip4_local_end_of_arc,
1930 .name = "ip4-local-end-of-arc",
1931 .vector_size = sizeof (u32),
1932
1933 .format_trace = format_ip4_forward_next_trace,
1934 .sibling_of = "ip4-local",
1935};
1936
1937VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1938
1939VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1940 .arc_name = "ip4-local",
1941 .node_name = "ip4-local-end-of-arc",
1942 .runs_before = 0, /* not before any other features */
1943};
1944/* *INDENT-ON* */
1945
Dave Barachd7cb1b52016-12-09 09:52:16 -05001946void
1947ip4_register_protocol (u32 protocol, u32 node_index)
1948{
1949 vlib_main_t *vm = vlib_get_main ();
1950 ip4_main_t *im = &ip4_main;
1951 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001952
1953 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001954 lm->local_next_by_ip_protocol[protocol] =
1955 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956}
1957
1958static clib_error_t *
1959show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001960 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001962 ip4_main_t *im = &ip4_main;
1963 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001964 int i;
1965
1966 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001967 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 {
1969 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001970 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001971 }
1972 return 0;
1973}
1974
1975
1976
Billy McFall0683c9c2016-10-13 08:27:31 -04001977/*?
1978 * Display the set of protocols handled by the local IPv4 stack.
1979 *
1980 * @cliexpar
1981 * Example of how to display local protocol table:
1982 * @cliexstart{show ip local}
1983 * Protocols handled by ip4_local
1984 * 1
1985 * 17
1986 * 47
1987 * @cliexend
1988?*/
1989/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001990VLIB_CLI_COMMAND (show_ip_local, static) =
1991{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992 .path = "show ip local",
1993 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001994 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995};
Billy McFall0683c9c2016-10-13 08:27:31 -04001996/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001997
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001998always_inline uword
1999ip4_arp_inline (vlib_main_t * vm,
2000 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002001 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002003 vnet_main_t *vnm = vnet_get_main ();
2004 ip4_main_t *im = &ip4_main;
2005 ip_lookup_main_t *lm = &im->lookup_main;
2006 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002007 uword n_left_from, n_left_to_next_drop, next_index;
2008 static f64 time_last_seed_change = -1e100;
2009 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04002010 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011 f64 time_now;
2012
2013 if (node->flags & VLIB_NODE_FLAG_TRACE)
2014 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2015
2016 time_now = vlib_time_now (vm);
2017 if (time_now - time_last_seed_change > 1e-3)
2018 {
2019 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002020 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
2021 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002022 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2023 hash_seeds[i] = r[i];
2024
2025 /* Mark all hash keys as been no-seen before. */
2026 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2027 hash_bitmap[i] = 0;
2028
2029 time_last_seed_change = time_now;
2030 }
2031
2032 from = vlib_frame_vector_args (frame);
2033 n_left_from = frame->n_vectors;
2034 next_index = node->cached_next_index;
2035 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002036 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002037
2038 while (n_left_from > 0)
2039 {
2040 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2041 to_next_drop, n_left_to_next_drop);
2042
2043 while (n_left_from > 0 && n_left_to_next_drop > 0)
2044 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002045 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002046 ip_adjacency_t *adj0;
2047 vlib_buffer_t *p0;
2048 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002049 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002050
2051 pi0 = from[0];
2052
2053 p0 = vlib_get_buffer (vm, pi0);
2054
2055 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002056 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002057 ip0 = vlib_buffer_get_current (p0);
2058
Ed Warnickecb9cada2015-12-08 15:45:58 -07002059 a0 = hash_seeds[0];
2060 b0 = hash_seeds[1];
2061 c0 = hash_seeds[2];
2062
2063 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2064 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2065
Dave Barachd7cb1b52016-12-09 09:52:16 -05002066 if (is_glean)
2067 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002068 /*
2069 * this is the Glean case, so we are ARPing for the
2070 * packet's destination
2071 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002072 a0 ^= ip0->dst_address.data_u32;
2073 }
2074 else
2075 {
2076 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2077 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002078 b0 ^= sw_if_index0;
2079
2080 hash_v3_finalize32 (a0, b0, c0);
2081
2082 c0 &= BITS (hash_bitmap) - 1;
2083 c0 = c0 / BITS (uword);
2084 m0 = (uword) 1 << (c0 % BITS (uword));
2085
2086 bm0 = hash_bitmap[c0];
2087 drop0 = (bm0 & m0) != 0;
2088
2089 /* Mark it as seen. */
2090 hash_bitmap[c0] = bm0 | m0;
2091
2092 from += 1;
2093 n_left_from -= 1;
2094 to_next_drop[0] = pi0;
2095 to_next_drop += 1;
2096 n_left_to_next_drop -= 1;
2097
Dave Barachd7cb1b52016-12-09 09:52:16 -05002098 p0->error =
2099 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2100 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002101
Neale Rannsb80c5362016-10-08 13:03:40 +01002102 /*
2103 * the adj has been updated to a rewrite but the node the DPO that got
2104 * us here hasn't - yet. no big deal. we'll drop while we wait.
2105 */
2106 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2107 continue;
2108
Ed Warnickecb9cada2015-12-08 15:45:58 -07002109 if (drop0)
2110 continue;
2111
Dave Barachd7cb1b52016-12-09 09:52:16 -05002112 /*
2113 * Can happen if the control-plane is programming tables
2114 * with traffic flowing; at least that's today's lame excuse.
2115 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002116 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2117 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002118 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002119 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002120 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002121 else
2122 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002123 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002124 u32 bi0 = 0;
2125 vlib_buffer_t *b0;
2126 ethernet_arp_header_t *h0;
2127 vnet_hw_interface_t *hw_if0;
2128
2129 h0 =
2130 vlib_packet_template_get_packet (vm,
2131 &im->ip4_arp_request_packet_template,
2132 &bi0);
2133
2134 /* Add rewrite/encap string for ARP packet. */
2135 vnet_rewrite_one_header (adj0[0], h0,
2136 sizeof (ethernet_header_t));
2137
2138 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2139
2140 /* Src ethernet address in ARP header. */
2141 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2142 hw_if0->hw_address,
2143 sizeof (h0->ip4_over_ethernet[0].ethernet));
2144
2145 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002146 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002147 /* The interface's source address is stashed in the Glean Adj */
2148 h0->ip4_over_ethernet[0].ip4 =
2149 adj0->sub_type.glean.receive_addr.ip4;
2150
2151 /* Copy in destination address we are requesting. This is the
2152 * glean case, so it's the packet's destination.*/
2153 h0->ip4_over_ethernet[1].ip4.data_u32 =
2154 ip0->dst_address.data_u32;
2155 }
2156 else
2157 {
2158 /* Src IP address in ARP header. */
2159 if (ip4_src_address_for_packet (lm, sw_if_index0,
2160 &h0->
2161 ip4_over_ethernet[0].ip4))
2162 {
2163 /* No source address available */
2164 p0->error =
2165 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2166 vlib_buffer_free (vm, &bi0, 1);
2167 continue;
2168 }
2169
2170 /* Copy in destination address we are requesting from the
2171 incomplete adj */
2172 h0->ip4_over_ethernet[1].ip4.data_u32 =
2173 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002174 }
2175
Dave Barachd7cb1b52016-12-09 09:52:16 -05002176 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2177 b0 = vlib_get_buffer (vm, bi0);
2178 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2179
2180 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2181
2182 vlib_set_next_frame_buffer (vm, node,
2183 adj0->rewrite_header.next_index,
2184 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002185 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002186 }
2187
2188 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2189 }
2190
2191 return frame->n_vectors;
2192}
2193
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002194static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002195ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002196{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002197 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002198}
2199
2200static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002201ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002202{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002203 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002204}
2205
Dave Barachd7cb1b52016-12-09 09:52:16 -05002206static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002207 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2208 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2209 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2210 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2211 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002212 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002213};
2214
Dave Barachd7cb1b52016-12-09 09:52:16 -05002215VLIB_REGISTER_NODE (ip4_arp_node) =
2216{
2217 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2218 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2219 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2220 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2221 {
2222 [IP4_ARP_NEXT_DROP] = "error-drop",}
2223,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002224
Dave Barachd7cb1b52016-12-09 09:52:16 -05002225VLIB_REGISTER_NODE (ip4_glean_node) =
2226{
2227 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2228 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2229 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2230 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2231 {
2232 [IP4_ARP_NEXT_DROP] = "error-drop",}
2233,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002234
Ed Warnickecb9cada2015-12-08 15:45:58 -07002235#define foreach_notrace_ip4_arp_error \
2236_(DROP) \
2237_(REQUEST_SENT) \
2238_(REPLICATE_DROP) \
2239_(REPLICATE_FAIL)
2240
Dave Barachd7cb1b52016-12-09 09:52:16 -05002241clib_error_t *
2242arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002244 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002245
2246 /* don't trace ARP request packets */
2247#define _(a) \
2248 vnet_pcap_drop_trace_filter_add_del \
2249 (rt->errors[IP4_ARP_ERROR_##a], \
2250 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002251 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002252#undef _
2253 return 0;
2254}
2255
Dave Barachd7cb1b52016-12-09 09:52:16 -05002256VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002257
2258
2259/* Send an ARP request to see if given destination is reachable on given interface. */
2260clib_error_t *
2261ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2262{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002263 vnet_main_t *vnm = vnet_get_main ();
2264 ip4_main_t *im = &ip4_main;
2265 ethernet_arp_header_t *h;
2266 ip4_address_t *src;
2267 ip_interface_address_t *ia;
2268 ip_adjacency_t *adj;
2269 vnet_hw_interface_t *hi;
2270 vnet_sw_interface_t *si;
2271 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 u32 bi = 0;
2273
2274 si = vnet_get_sw_interface (vnm, sw_if_index);
2275
2276 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2277 {
2278 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002279 format_ip4_address, dst,
2280 format_vnet_sw_if_index_name, vnm,
2281 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282 }
2283
Dave Barachd7cb1b52016-12-09 09:52:16 -05002284 src =
2285 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2286 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002287 {
2288 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002289 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002290 (0,
2291 "no matching interface address for destination %U (interface %U)",
2292 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2293 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294 }
2295
Neale Ranns107e7d42017-04-11 09:55:19 -07002296 adj = adj_get (ia->neighbor_probe_adj_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297
Dave Barachd7cb1b52016-12-09 09:52:16 -05002298 h =
Neale Ranns32e1c012016-11-22 17:07:28 +00002299 vlib_packet_template_get_packet (vm,
2300 &im->ip4_arp_request_packet_template,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002301 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002302
2303 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2304
Dave Barachd7cb1b52016-12-09 09:52:16 -05002305 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2306 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002307
2308 h->ip4_over_ethernet[0].ip4 = src[0];
2309 h->ip4_over_ethernet[1].ip4 = dst[0];
2310
2311 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002312 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2313 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002314
2315 /* Add encapsulation string for software interface (e.g. ethernet header). */
2316 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2317 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2318
2319 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002320 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2321 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002322 to_next[0] = bi;
2323 f->n_vectors = 1;
2324 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2325 }
2326
2327 return /* no error */ 0;
2328}
2329
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330typedef enum
2331{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002333 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002334} ip4_rewrite_next_t;
2335
2336always_inline uword
2337ip4_rewrite_inline (vlib_main_t * vm,
2338 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002339 vlib_frame_t * frame,
2340 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002341{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002342 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2343 u32 *from = vlib_frame_vector_args (frame);
2344 u32 n_left_from, n_left_to_next, *to_next, next_index;
2345 vlib_node_runtime_t *error_node =
2346 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002347
2348 n_left_from = frame->n_vectors;
2349 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002350 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002351
Ed Warnickecb9cada2015-12-08 15:45:58 -07002352 while (n_left_from > 0)
2353 {
2354 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2355
2356 while (n_left_from >= 4 && n_left_to_next >= 2)
2357 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002358 ip_adjacency_t *adj0, *adj1;
2359 vlib_buffer_t *p0, *p1;
2360 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002361 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2362 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002363 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002364
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365 /* Prefetch next iteration. */
2366 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002367 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002368
2369 p2 = vlib_get_buffer (vm, from[2]);
2370 p3 = vlib_get_buffer (vm, from[3]);
2371
2372 vlib_prefetch_buffer_header (p2, STORE);
2373 vlib_prefetch_buffer_header (p3, STORE);
2374
2375 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2376 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2377 }
2378
2379 pi0 = to_next[0] = from[0];
2380 pi1 = to_next[1] = from[1];
2381
2382 from += 2;
2383 n_left_from -= 2;
2384 to_next += 2;
2385 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002386
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 p0 = vlib_get_buffer (vm, pi0);
2388 p1 = vlib_get_buffer (vm, pi1);
2389
Neale Rannsf06aea52016-11-29 06:51:37 -08002390 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2391 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392
Neale Ranns1bd01092017-03-15 15:41:17 -04002393 /*
2394 * pre-fetch the per-adjacency counters
2395 */
2396 if (do_counters)
2397 {
2398 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002399 thread_index, adj_index0);
Neale Ranns1bd01092017-03-15 15:41:17 -04002400 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002401 thread_index, adj_index1);
Neale Ranns1bd01092017-03-15 15:41:17 -04002402 }
2403
Ed Warnickecb9cada2015-12-08 15:45:58 -07002404 ip0 = vlib_buffer_get_current (p0);
2405 ip1 = vlib_buffer_get_current (p1);
2406
2407 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002408 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409
2410 /* Decrement TTL & update checksum.
2411 Works either endian, so no need for byte swap. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002412 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002413 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002414 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002415
2416 /* Input node should have reject packets with ttl 0. */
2417 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002418
2419 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002420 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002421
2422 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002423 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002424 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002425
Dave Barachd7cb1b52016-12-09 09:52:16 -05002426 /*
2427 * If the ttl drops below 1 when forwarding, generate
2428 * an ICMP response.
2429 */
2430 if (PREDICT_FALSE (ttl0 <= 0))
2431 {
2432 error0 = IP4_ERROR_TIME_EXPIRED;
2433 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2434 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2435 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2436 0);
2437 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2438 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002439
2440 /* Verify checksum. */
2441 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2442 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002443 else
2444 {
2445 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2446 }
2447 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002448 {
2449 i32 ttl1 = ip1->ttl;
2450
2451 /* Input node should have reject packets with ttl 0. */
2452 ASSERT (ip1->ttl > 0);
2453
2454 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2455 checksum1 += checksum1 >= 0xffff;
2456
2457 ip1->checksum = checksum1;
2458 ttl1 -= 1;
2459 ip1->ttl = ttl1;
2460
Dave Barachd7cb1b52016-12-09 09:52:16 -05002461 /*
2462 * If the ttl drops below 1 when forwarding, generate
2463 * an ICMP response.
2464 */
2465 if (PREDICT_FALSE (ttl1 <= 0))
2466 {
2467 error1 = IP4_ERROR_TIME_EXPIRED;
2468 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2469 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2470 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2471 0);
2472 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2473 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002474
2475 /* Verify checksum. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2477 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002478 else
2479 {
2480 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2481 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482
2483 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002484 adj0 = adj_get (adj_index0);
2485 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002486
Dave Barachd7cb1b52016-12-09 09:52:16 -05002487 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002488 rw_len0 = adj0[0].rewrite_header.data_bytes;
2489 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002490 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2491 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002492
Dave Barachd7cb1b52016-12-09 09:52:16 -05002493 /* Check MTU of outgoing interface. */
2494 error0 =
2495 (vlib_buffer_length_in_chain (vm, p0) >
2496 adj0[0].
2497 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2498 error0);
2499 error1 =
2500 (vlib_buffer_length_in_chain (vm, p1) >
2501 adj1[0].
2502 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2503 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002504
Dave Barachd7cb1b52016-12-09 09:52:16 -05002505 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2506 * to see the IP headerr */
2507 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2508 {
Damjan Marion892e0762016-12-09 18:52:05 +01002509 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002510 p0->current_data -= rw_len0;
2511 p0->current_length += rw_len0;
2512 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2513 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002514
Neale Rannsb069a692017-03-15 12:34:25 -04002515 if (PREDICT_FALSE
2516 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2517 vnet_feature_arc_start (lm->output_feature_arc_index,
2518 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519 }
2520 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2521 {
Damjan Marion892e0762016-12-09 18:52:05 +01002522 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002523 p1->current_data -= rw_len1;
2524 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002525
Dave Barachd7cb1b52016-12-09 09:52:16 -05002526 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2527 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002528
Neale Rannsb069a692017-03-15 12:34:25 -04002529 if (PREDICT_FALSE
2530 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2531 vnet_feature_arc_start (lm->output_feature_arc_index,
2532 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002533 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002534
2535 /* Guess we are only writing on simple Ethernet header. */
2536 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002537 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002538
Neale Ranns044183f2017-01-24 01:34:25 -08002539 /*
2540 * Bump the per-adjacency counters
2541 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002542 if (do_counters)
2543 {
2544 vlib_increment_combined_counter
2545 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002546 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002547 adj_index0, 1,
2548 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002549
Neale Ranns9c6a6132017-02-21 05:33:14 -08002550 vlib_increment_combined_counter
2551 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002552 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002553 adj_index1, 1,
2554 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2555 }
Neale Ranns044183f2017-01-24 01:34:25 -08002556
Neale Ranns5e575b12016-10-03 09:40:25 +01002557 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002558 {
2559 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2560 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2561 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002562 if (is_mcast)
2563 {
2564 /*
2565 * copy bytes from the IP address into the MAC rewrite
2566 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002567 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2568 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002569 }
Dave Barach75fc8542016-10-11 16:16:02 -04002570
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2572 to_next, n_left_to_next,
2573 pi0, pi1, next0, next1);
2574 }
2575
2576 while (n_left_from > 0 && n_left_to_next > 0)
2577 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002578 ip_adjacency_t *adj0;
2579 vlib_buffer_t *p0;
2580 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002581 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002582 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002583
Ed Warnickecb9cada2015-12-08 15:45:58 -07002584 pi0 = to_next[0] = from[0];
2585
2586 p0 = vlib_get_buffer (vm, pi0);
2587
Neale Rannsf06aea52016-11-29 06:51:37 -08002588 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002589
Neale Ranns107e7d42017-04-11 09:55:19 -07002590 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002591
Ed Warnickecb9cada2015-12-08 15:45:58 -07002592 ip0 = vlib_buffer_get_current (p0);
2593
2594 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002595 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002596
2597 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002598 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002599 {
2600 i32 ttl0 = ip0->ttl;
2601
2602 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2603
2604 checksum0 += checksum0 >= 0xffff;
2605
2606 ip0->checksum = checksum0;
2607
2608 ASSERT (ip0->ttl > 0);
2609
2610 ttl0 -= 1;
2611
2612 ip0->ttl = ttl0;
2613
2614 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2615
Dave Barachd7cb1b52016-12-09 09:52:16 -05002616 if (PREDICT_FALSE (ttl0 <= 0))
2617 {
2618 /*
2619 * If the ttl drops below 1 when forwarding, generate
2620 * an ICMP response.
2621 */
2622 error0 = IP4_ERROR_TIME_EXPIRED;
2623 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2624 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2625 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2626 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2627 0);
2628 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002630 else
2631 {
2632 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2633 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634
Neale Ranns1bd01092017-03-15 15:41:17 -04002635 if (do_counters)
2636 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002637 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002638
Ed Warnickecb9cada2015-12-08 15:45:58 -07002639 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002640 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002641 if (is_mcast)
2642 {
2643 /*
2644 * copy bytes from the IP address into the MAC rewrite
2645 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002646 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002647 }
Dave Barach75fc8542016-10-11 16:16:02 -04002648
Dave Barachd7cb1b52016-12-09 09:52:16 -05002649 /* Update packet buffer attributes/set output interface. */
2650 rw_len0 = adj0[0].rewrite_header.data_bytes;
2651 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002652
Neale Ranns1bd01092017-03-15 15:41:17 -04002653 if (do_counters)
2654 vlib_increment_combined_counter
2655 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002656 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002657 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002658
Dave Barachd7cb1b52016-12-09 09:52:16 -05002659 /* Check MTU of outgoing interface. */
2660 error0 = (vlib_buffer_length_in_chain (vm, p0)
2661 > adj0[0].rewrite_header.max_l3_packet_bytes
2662 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002663
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002665
Dave Barachd7cb1b52016-12-09 09:52:16 -05002666 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2667 * to see the IP headerr */
2668 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2669 {
2670 p0->current_data -= rw_len0;
2671 p0->current_length += rw_len0;
2672 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002673
Dave Barachd7cb1b52016-12-09 09:52:16 -05002674 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2675 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002676
Neale Ranns5e575b12016-10-03 09:40:25 +01002677 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002678 {
2679 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002680 }
2681
Neale Rannsb069a692017-03-15 12:34:25 -04002682 if (PREDICT_FALSE
2683 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2684 vnet_feature_arc_start (lm->output_feature_arc_index,
2685 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002686
Dave Barachd7cb1b52016-12-09 09:52:16 -05002687 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002688
Ed Warnickecb9cada2015-12-08 15:45:58 -07002689 from += 1;
2690 n_left_from -= 1;
2691 to_next += 1;
2692 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002693
Ed Warnickecb9cada2015-12-08 15:45:58 -07002694 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2695 to_next, n_left_to_next,
2696 pi0, next0);
2697 }
Dave Barach75fc8542016-10-11 16:16:02 -04002698
Ed Warnickecb9cada2015-12-08 15:45:58 -07002699 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2700 }
2701
2702 /* Need to do trace after rewrites to pick up new packet data. */
2703 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002704 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002705
2706 return frame->n_vectors;
2707}
2708
Dave Barach132d51d2016-07-07 10:10:17 -04002709
Neale Rannsf06aea52016-11-29 06:51:37 -08002710/** @brief IPv4 rewrite node.
2711 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002712
2713 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2714 header checksum, fetch the ip adjacency, check the outbound mtu,
2715 apply the adjacency rewrite, and send pkts to the adjacency
2716 rewrite header's rewrite_next_index.
2717
2718 @param vm vlib_main_t corresponding to the current thread
2719 @param node vlib_node_runtime_t
2720 @param frame vlib_frame_t whose contents should be dispatched
2721
2722 @par Graph mechanics: buffer metadata, next index usage
2723
2724 @em Uses:
2725 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2726 - the rewrite adjacency index
2727 - <code>adj->lookup_next_index</code>
2728 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002729 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002730 - <code>adj->rewrite_header</code>
2731 - Rewrite string length, rewrite string, next_index
2732
2733 @em Sets:
2734 - <code>b->current_data, b->current_length</code>
2735 - Updated net of applying the rewrite string
2736
2737 <em>Next Indices:</em>
2738 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002739 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002740*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002742ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002743 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002744{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002745 if (adj_are_counters_enabled ())
2746 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2747 else
2748 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002749}
2750
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002751static uword
2752ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002753 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002754{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002755 if (adj_are_counters_enabled ())
2756 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2757 else
2758 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002759}
2760
Neale Ranns32e1c012016-11-22 17:07:28 +00002761static uword
2762ip4_rewrite_mcast (vlib_main_t * vm,
2763 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002764{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002765 if (adj_are_counters_enabled ())
2766 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2767 else
2768 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002769}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002770
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002771static uword
2772ip4_mcast_midchain (vlib_main_t * vm,
2773 vlib_node_runtime_t * node, vlib_frame_t * frame)
2774{
2775 if (adj_are_counters_enabled ())
2776 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2777 else
2778 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2779}
2780
Neale Ranns32e1c012016-11-22 17:07:28 +00002781/* *INDENT-OFF* */
2782VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2783 .function = ip4_rewrite,
2784 .name = "ip4-rewrite",
2785 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002786
Neale Ranns32e1c012016-11-22 17:07:28 +00002787 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002788
Neale Ranns32e1c012016-11-22 17:07:28 +00002789 .n_next_nodes = 2,
2790 .next_nodes = {
2791 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2792 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2793 },
2794};
2795VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2796
2797VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2798 .function = ip4_rewrite_mcast,
2799 .name = "ip4-rewrite-mcast",
2800 .vector_size = sizeof (u32),
2801
2802 .format_trace = format_ip4_rewrite_trace,
2803 .sibling_of = "ip4-rewrite",
2804};
2805VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2806
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002807VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2808 .function = ip4_mcast_midchain,
2809 .name = "ip4-mcast-midchain",
2810 .vector_size = sizeof (u32),
2811
2812 .format_trace = format_ip4_rewrite_trace,
2813 .sibling_of = "ip4-rewrite",
2814};
2815VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2816
Neale Ranns32e1c012016-11-22 17:07:28 +00002817VLIB_REGISTER_NODE (ip4_midchain_node) = {
2818 .function = ip4_midchain,
2819 .name = "ip4-midchain",
2820 .vector_size = sizeof (u32),
2821 .format_trace = format_ip4_forward_next_trace,
2822 .sibling_of = "ip4-rewrite",
2823};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002824VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002825/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002826
Ed Warnickecb9cada2015-12-08 15:45:58 -07002827static clib_error_t *
2828add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002829 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002830{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002831 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002832 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002833 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002834 u32 sw_if_index, table_id;
2835
2836 sw_if_index = ~0;
2837
Dave Barachd7cb1b52016-12-09 09:52:16 -05002838 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002839 {
2840 error = clib_error_return (0, "unknown interface `%U'",
2841 format_unformat_error, input);
2842 goto done;
2843 }
2844
2845 if (unformat (input, "%d", &table_id))
2846 ;
2847 else
2848 {
2849 error = clib_error_return (0, "expected table id `%U'",
2850 format_unformat_error, input);
2851 goto done;
2852 }
2853
Neale Ranns4008ac92017-02-13 23:20:04 -08002854 /*
2855 * If the interface already has in IP address, then a change int
2856 * VRF is not allowed. The IP address applied must first be removed.
2857 * We do not do that automatically here, since VPP has no knowledge
2858 * of whether thoses subnets are valid in the destination VRF.
2859 */
2860 /* *INDENT-OFF* */
2861 foreach_ip_interface_address (&ip4_main.lookup_main,
2862 ia, sw_if_index,
2863 1 /* honor unnumbered */,
2864 ({
2865 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866
Neale Ranns4008ac92017-02-13 23:20:04 -08002867 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2868 error = clib_error_return (0, "interface %U has address %U",
2869 format_vnet_sw_if_index_name, vnm,
2870 sw_if_index,
2871 format_ip4_address, a);
2872 goto done;
2873 }));
2874 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002875
Neale Ranns4008ac92017-02-13 23:20:04 -08002876{
2877 ip4_main_t *im = &ip4_main;
2878 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002879
Neale Ranns4008ac92017-02-13 23:20:04 -08002880 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2881
2882 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2883 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2884
2885 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2886 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2887 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2888}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889
Dave Barachd7cb1b52016-12-09 09:52:16 -05002890done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002891return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002892}
2893
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002894/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002895 * Place the indicated interface into the supplied IPv4 FIB table (also known
2896 * as a VRF). If the FIB table does not exist, this command creates it. To
2897 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2898 * FIB table will only be displayed if a route has been added to the table, or
2899 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002900 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002901 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002902 * @note IP addresses added after setting the interface IP table are added to
2903 * the indicated FIB table. If an IP address is added prior to changing the
2904 * table then this is an error. The control plane must remove these addresses
2905 * first and then change the table. VPP will not automatically move the
2906 * addresses from the old to the new table as it does not know the validity
2907 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002908 *
2909 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002910 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2911 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002912 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002913/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002914VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2915{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002916 .path = "set interface ip table",
2917 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002918 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919};
Billy McFall0683c9c2016-10-13 08:27:31 -04002920/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002921
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922int
2923ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2924{
2925 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002926 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002927 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002928
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002929 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002930
Neale Ranns04a75e32017-03-23 06:46:01 -07002931 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002932 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2933 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002934
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002935 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002936
Dave Barachd7cb1b52016-12-09 09:52:16 -05002937 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002938}
Dave Barach75fc8542016-10-11 16:16:02 -04002939
Ed Warnickecb9cada2015-12-08 15:45:58 -07002940static clib_error_t *
2941test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002942 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002943{
Billy McFall309fe062016-10-14 07:37:33 -04002944 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002945 u32 table_id = 0;
2946 f64 count = 1;
2947 u32 n;
2948 int i;
2949 ip4_address_t ip4_base_address;
2950 u64 errors = 0;
2951
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2953 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002955 {
2956 /* Make sure the entry exists. */
2957 fib = ip4_fib_get (table_id);
2958 if ((fib) && (fib->index != table_id))
2959 return clib_error_return (0, "<fib-index> %d does not exist",
2960 table_id);
2961 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002962 else if (unformat (input, "count %f", &count))
2963 ;
2964
2965 else if (unformat (input, "%U",
2966 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002967 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002968 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002969 return clib_error_return (0, "unknown input `%U'",
2970 format_unformat_error, input);
2971 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972
2973 n = count;
2974
2975 for (i = 0; i < n; i++)
2976 {
2977 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002978 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002979
Dave Barach75fc8542016-10-11 16:16:02 -04002980 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002981 clib_host_to_net_u32 (1 +
2982 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002983 }
2984
Dave Barach75fc8542016-10-11 16:16:02 -04002985 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002986 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2987 else
2988 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2989
2990 return 0;
2991}
2992
Billy McFall0683c9c2016-10-13 08:27:31 -04002993/*?
2994 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2995 * given FIB table to determine if there is a conflict with the
2996 * adjacency table. The fib-id can be determined by using the
2997 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2998 * of 0 is used.
2999 *
3000 * @todo This command uses fib-id, other commands use table-id (not
3001 * just a name, they are different indexes). Would like to change this
3002 * to table-id for consistency.
3003 *
3004 * @cliexpar
3005 * Example of how to run the test lookup command:
3006 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3007 * No errors in 2 lookups
3008 * @cliexend
3009?*/
3010/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003011VLIB_CLI_COMMAND (lookup_test_command, static) =
3012{
3013 .path = "test lookup",
3014 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3015 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016};
Billy McFall0683c9c2016-10-13 08:27:31 -04003017/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003018
Dave Barachd7cb1b52016-12-09 09:52:16 -05003019int
3020vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021{
Neale Ranns107e7d42017-04-11 09:55:19 -07003022 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003023
Neale Ranns107e7d42017-04-11 09:55:19 -07003024 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
3025
3026 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027 return VNET_API_ERROR_NO_SUCH_FIB;
3028
Neale Ranns227038a2017-04-21 01:07:59 -07003029 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3030 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003031
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032 return 0;
3033}
Dave Barach75fc8542016-10-11 16:16:02 -04003034
Ed Warnickecb9cada2015-12-08 15:45:58 -07003035static clib_error_t *
3036set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003037 unformat_input_t * input,
3038 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003039{
3040 int matched = 0;
3041 u32 table_id = 0;
3042 u32 flow_hash_config = 0;
3043 int rv;
3044
Dave Barachd7cb1b52016-12-09 09:52:16 -05003045 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3046 {
3047 if (unformat (input, "table %d", &table_id))
3048 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003049#define _(a,v) \
3050 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003051 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003053 else
3054 break;
3055 }
Dave Barach75fc8542016-10-11 16:16:02 -04003056
Ed Warnickecb9cada2015-12-08 15:45:58 -07003057 if (matched == 0)
3058 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003059 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003060
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3062 switch (rv)
3063 {
3064 case 0:
3065 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003066
Ed Warnickecb9cada2015-12-08 15:45:58 -07003067 case VNET_API_ERROR_NO_SUCH_FIB:
3068 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003069
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070 default:
3071 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3072 break;
3073 }
Dave Barach75fc8542016-10-11 16:16:02 -04003074
Ed Warnickecb9cada2015-12-08 15:45:58 -07003075 return 0;
3076}
Dave Barach75fc8542016-10-11 16:16:02 -04003077
Billy McFall0683c9c2016-10-13 08:27:31 -04003078/*?
3079 * Configure the set of IPv4 fields used by the flow hash.
3080 *
3081 * @cliexpar
3082 * Example of how to set the flow hash on a given table:
3083 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3084 * Example of display the configured flow hash:
3085 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003086 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3087 * 0.0.0.0/0
3088 * unicast-ip4-chain
3089 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3090 * [0] [@0]: dpo-drop ip6
3091 * 0.0.0.0/32
3092 * unicast-ip4-chain
3093 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3094 * [0] [@0]: dpo-drop ip6
3095 * 224.0.0.0/8
3096 * unicast-ip4-chain
3097 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3098 * [0] [@0]: dpo-drop ip6
3099 * 6.0.1.2/32
3100 * unicast-ip4-chain
3101 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3102 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3103 * 7.0.0.1/32
3104 * unicast-ip4-chain
3105 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3106 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3107 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3108 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3109 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3110 * 240.0.0.0/8
3111 * unicast-ip4-chain
3112 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3113 * [0] [@0]: dpo-drop ip6
3114 * 255.255.255.255/32
3115 * unicast-ip4-chain
3116 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3117 * [0] [@0]: dpo-drop ip6
3118 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3119 * 0.0.0.0/0
3120 * unicast-ip4-chain
3121 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3122 * [0] [@0]: dpo-drop ip6
3123 * 0.0.0.0/32
3124 * unicast-ip4-chain
3125 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3126 * [0] [@0]: dpo-drop ip6
3127 * 172.16.1.0/24
3128 * unicast-ip4-chain
3129 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3130 * [0] [@4]: ipv4-glean: af_packet0
3131 * 172.16.1.1/32
3132 * unicast-ip4-chain
3133 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3134 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3135 * 172.16.1.2/32
3136 * unicast-ip4-chain
3137 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3138 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3139 * 172.16.2.0/24
3140 * unicast-ip4-chain
3141 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3142 * [0] [@4]: ipv4-glean: af_packet1
3143 * 172.16.2.1/32
3144 * unicast-ip4-chain
3145 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3146 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3147 * 224.0.0.0/8
3148 * unicast-ip4-chain
3149 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3150 * [0] [@0]: dpo-drop ip6
3151 * 240.0.0.0/8
3152 * unicast-ip4-chain
3153 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3154 * [0] [@0]: dpo-drop ip6
3155 * 255.255.255.255/32
3156 * unicast-ip4-chain
3157 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3158 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003159 * @cliexend
3160?*/
3161/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003162VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3163{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003164 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003165 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003166 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167 .function = set_ip_flow_hash_command_fn,
3168};
Billy McFall0683c9c2016-10-13 08:27:31 -04003169/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003170
Dave Barachd7cb1b52016-12-09 09:52:16 -05003171int
3172vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3173 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003174{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003175 vnet_main_t *vnm = vnet_get_main ();
3176 vnet_interface_main_t *im = &vnm->interface_main;
3177 ip4_main_t *ipm = &ip4_main;
3178 ip_lookup_main_t *lm = &ipm->lookup_main;
3179 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003180 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003181
3182 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3183 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3184
3185 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3186 return VNET_API_ERROR_NO_SUCH_ENTRY;
3187
3188 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003189 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003190
Neale Rannsdf089a82016-10-02 16:39:06 +01003191 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3192
3193 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003194 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003195 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003196 .fp_len = 32,
3197 .fp_proto = FIB_PROTOCOL_IP4,
3198 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003199 };
3200 u32 fib_index;
3201
Dave Barachd7cb1b52016-12-09 09:52:16 -05003202 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3203 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003204
3205
Dave Barachd7cb1b52016-12-09 09:52:16 -05003206 if (table_index != (u32) ~ 0)
3207 {
3208 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003209
Dave Barachd7cb1b52016-12-09 09:52:16 -05003210 dpo_set (&dpo,
3211 DPO_CLASSIFY,
3212 DPO_PROTO_IP4,
3213 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003214
Dave Barachd7cb1b52016-12-09 09:52:16 -05003215 fib_table_entry_special_dpo_add (fib_index,
3216 &pfx,
3217 FIB_SOURCE_CLASSIFY,
3218 FIB_ENTRY_FLAG_NONE, &dpo);
3219 dpo_reset (&dpo);
3220 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003221 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003222 {
3223 fib_table_entry_special_remove (fib_index,
3224 &pfx, FIB_SOURCE_CLASSIFY);
3225 }
3226 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003227
Ed Warnickecb9cada2015-12-08 15:45:58 -07003228 return 0;
3229}
3230
3231static clib_error_t *
3232set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003233 unformat_input_t * input,
3234 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003235{
3236 u32 table_index = ~0;
3237 int table_index_set = 0;
3238 u32 sw_if_index = ~0;
3239 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003240
Dave Barachd7cb1b52016-12-09 09:52:16 -05003241 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3242 {
3243 if (unformat (input, "table-index %d", &table_index))
3244 table_index_set = 1;
3245 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3246 vnet_get_main (), &sw_if_index))
3247 ;
3248 else
3249 break;
3250 }
Dave Barach75fc8542016-10-11 16:16:02 -04003251
Ed Warnickecb9cada2015-12-08 15:45:58 -07003252 if (table_index_set == 0)
3253 return clib_error_return (0, "classify table-index must be specified");
3254
3255 if (sw_if_index == ~0)
3256 return clib_error_return (0, "interface / subif must be specified");
3257
3258 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3259
3260 switch (rv)
3261 {
3262 case 0:
3263 break;
3264
3265 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3266 return clib_error_return (0, "No such interface");
3267
3268 case VNET_API_ERROR_NO_SUCH_ENTRY:
3269 return clib_error_return (0, "No such classifier table");
3270 }
3271 return 0;
3272}
3273
Billy McFall0683c9c2016-10-13 08:27:31 -04003274/*?
3275 * Assign a classification table to an interface. The classification
3276 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3277 * commands. Once the table is create, use this command to filter packets
3278 * on an interface.
3279 *
3280 * @cliexpar
3281 * Example of how to assign a classification table to an interface:
3282 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3283?*/
3284/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003285VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3286{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003287 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003288 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003289 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003290 .function = set_ip_classify_command_fn,
3291};
Billy McFall0683c9c2016-10-13 08:27:31 -04003292/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003293
3294/*
3295 * fd.io coding-style-patch-verification: ON
3296 *
3297 * Local Variables:
3298 * eval: (c-set-style "gnu")
3299 * End:
3300 */