blob: 374671827a9d01b57b594b204f0db23f0edac372 [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. */
2476 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2477 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2478 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002479 else
2480 {
2481 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2482 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002483
2484 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002485 adj0 = adj_get (adj_index0);
2486 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002487
Dave Barachd7cb1b52016-12-09 09:52:16 -05002488 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002489 rw_len0 = adj0[0].rewrite_header.data_bytes;
2490 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002491 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2492 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002493
Dave Barachd7cb1b52016-12-09 09:52:16 -05002494 /* Check MTU of outgoing interface. */
2495 error0 =
2496 (vlib_buffer_length_in_chain (vm, p0) >
2497 adj0[0].
2498 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2499 error0);
2500 error1 =
2501 (vlib_buffer_length_in_chain (vm, p1) >
2502 adj1[0].
2503 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2504 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002505
Dave Barachd7cb1b52016-12-09 09:52:16 -05002506 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2507 * to see the IP headerr */
2508 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2509 {
Damjan Marion892e0762016-12-09 18:52:05 +01002510 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002511 p0->current_data -= rw_len0;
2512 p0->current_length += rw_len0;
2513 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2514 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002515
Neale Rannsb069a692017-03-15 12:34:25 -04002516 if (PREDICT_FALSE
2517 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2518 vnet_feature_arc_start (lm->output_feature_arc_index,
2519 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002520 }
2521 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2522 {
Damjan Marion892e0762016-12-09 18:52:05 +01002523 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002524 p1->current_data -= rw_len1;
2525 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002526
Dave Barachd7cb1b52016-12-09 09:52:16 -05002527 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2528 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002529
Neale Rannsb069a692017-03-15 12:34:25 -04002530 if (PREDICT_FALSE
2531 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2532 vnet_feature_arc_start (lm->output_feature_arc_index,
2533 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002534 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002535
2536 /* Guess we are only writing on simple Ethernet header. */
2537 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002538 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002539
Neale Ranns044183f2017-01-24 01:34:25 -08002540 /*
2541 * Bump the per-adjacency counters
2542 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002543 if (do_counters)
2544 {
2545 vlib_increment_combined_counter
2546 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002547 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002548 adj_index0, 1,
2549 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002550
Neale Ranns9c6a6132017-02-21 05:33:14 -08002551 vlib_increment_combined_counter
2552 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002553 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002554 adj_index1, 1,
2555 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2556 }
Neale Ranns044183f2017-01-24 01:34:25 -08002557
Neale Ranns5e575b12016-10-03 09:40:25 +01002558 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002559 {
2560 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2561 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2562 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002563 if (is_mcast)
2564 {
2565 /*
2566 * copy bytes from the IP address into the MAC rewrite
2567 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002568 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2569 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002570 }
Dave Barach75fc8542016-10-11 16:16:02 -04002571
Ed Warnickecb9cada2015-12-08 15:45:58 -07002572 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2573 to_next, n_left_to_next,
2574 pi0, pi1, next0, next1);
2575 }
2576
2577 while (n_left_from > 0 && n_left_to_next > 0)
2578 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002579 ip_adjacency_t *adj0;
2580 vlib_buffer_t *p0;
2581 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002582 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002583 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002584
Ed Warnickecb9cada2015-12-08 15:45:58 -07002585 pi0 = to_next[0] = from[0];
2586
2587 p0 = vlib_get_buffer (vm, pi0);
2588
Neale Rannsf06aea52016-11-29 06:51:37 -08002589 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002590
Neale Ranns107e7d42017-04-11 09:55:19 -07002591 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002592
Ed Warnickecb9cada2015-12-08 15:45:58 -07002593 ip0 = vlib_buffer_get_current (p0);
2594
2595 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002596 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002597
2598 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002599 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002600 {
2601 i32 ttl0 = ip0->ttl;
2602
2603 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2604
2605 checksum0 += checksum0 >= 0xffff;
2606
2607 ip0->checksum = checksum0;
2608
2609 ASSERT (ip0->ttl > 0);
2610
2611 ttl0 -= 1;
2612
2613 ip0->ttl = ttl0;
2614
2615 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2616
Dave Barachd7cb1b52016-12-09 09:52:16 -05002617 if (PREDICT_FALSE (ttl0 <= 0))
2618 {
2619 /*
2620 * If the ttl drops below 1 when forwarding, generate
2621 * an ICMP response.
2622 */
2623 error0 = IP4_ERROR_TIME_EXPIRED;
2624 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2625 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2626 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2627 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2628 0);
2629 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002630 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002631 else
2632 {
2633 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2634 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002635
Neale Ranns1bd01092017-03-15 15:41:17 -04002636 if (do_counters)
2637 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002638 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002639
Ed Warnickecb9cada2015-12-08 15:45:58 -07002640 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002641 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002642 if (is_mcast)
2643 {
2644 /*
2645 * copy bytes from the IP address into the MAC rewrite
2646 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002647 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002648 }
Dave Barach75fc8542016-10-11 16:16:02 -04002649
Dave Barachd7cb1b52016-12-09 09:52:16 -05002650 /* Update packet buffer attributes/set output interface. */
2651 rw_len0 = adj0[0].rewrite_header.data_bytes;
2652 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002653
Neale Ranns1bd01092017-03-15 15:41:17 -04002654 if (do_counters)
2655 vlib_increment_combined_counter
2656 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002657 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002658 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002659
Dave Barachd7cb1b52016-12-09 09:52:16 -05002660 /* Check MTU of outgoing interface. */
2661 error0 = (vlib_buffer_length_in_chain (vm, p0)
2662 > adj0[0].rewrite_header.max_l3_packet_bytes
2663 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002664
Ed Warnickecb9cada2015-12-08 15:45:58 -07002665 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002666
Dave Barachd7cb1b52016-12-09 09:52:16 -05002667 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2668 * to see the IP headerr */
2669 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2670 {
2671 p0->current_data -= rw_len0;
2672 p0->current_length += rw_len0;
2673 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002674
Dave Barachd7cb1b52016-12-09 09:52:16 -05002675 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2676 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002677
Neale Ranns5e575b12016-10-03 09:40:25 +01002678 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002679 {
2680 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002681 }
2682
Neale Rannsb069a692017-03-15 12:34:25 -04002683 if (PREDICT_FALSE
2684 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2685 vnet_feature_arc_start (lm->output_feature_arc_index,
2686 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002687
Dave Barachd7cb1b52016-12-09 09:52:16 -05002688 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002689
Ed Warnickecb9cada2015-12-08 15:45:58 -07002690 from += 1;
2691 n_left_from -= 1;
2692 to_next += 1;
2693 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002694
Ed Warnickecb9cada2015-12-08 15:45:58 -07002695 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2696 to_next, n_left_to_next,
2697 pi0, next0);
2698 }
Dave Barach75fc8542016-10-11 16:16:02 -04002699
Ed Warnickecb9cada2015-12-08 15:45:58 -07002700 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2701 }
2702
2703 /* Need to do trace after rewrites to pick up new packet data. */
2704 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002705 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002706
2707 return frame->n_vectors;
2708}
2709
Dave Barach132d51d2016-07-07 10:10:17 -04002710
Neale Rannsf06aea52016-11-29 06:51:37 -08002711/** @brief IPv4 rewrite node.
2712 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002713
2714 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2715 header checksum, fetch the ip adjacency, check the outbound mtu,
2716 apply the adjacency rewrite, and send pkts to the adjacency
2717 rewrite header's rewrite_next_index.
2718
2719 @param vm vlib_main_t corresponding to the current thread
2720 @param node vlib_node_runtime_t
2721 @param frame vlib_frame_t whose contents should be dispatched
2722
2723 @par Graph mechanics: buffer metadata, next index usage
2724
2725 @em Uses:
2726 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2727 - the rewrite adjacency index
2728 - <code>adj->lookup_next_index</code>
2729 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002730 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002731 - <code>adj->rewrite_header</code>
2732 - Rewrite string length, rewrite string, next_index
2733
2734 @em Sets:
2735 - <code>b->current_data, b->current_length</code>
2736 - Updated net of applying the rewrite string
2737
2738 <em>Next Indices:</em>
2739 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002740 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002741*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002743ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002744 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002745{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002746 if (adj_are_counters_enabled ())
2747 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2748 else
2749 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002750}
2751
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002752static uword
2753ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002754 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002755{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002756 if (adj_are_counters_enabled ())
2757 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2758 else
2759 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002760}
2761
Neale Ranns32e1c012016-11-22 17:07:28 +00002762static uword
2763ip4_rewrite_mcast (vlib_main_t * vm,
2764 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002765{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002766 if (adj_are_counters_enabled ())
2767 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2768 else
2769 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002770}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002771
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002772static uword
2773ip4_mcast_midchain (vlib_main_t * vm,
2774 vlib_node_runtime_t * node, vlib_frame_t * frame)
2775{
2776 if (adj_are_counters_enabled ())
2777 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2778 else
2779 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2780}
2781
Neale Ranns32e1c012016-11-22 17:07:28 +00002782/* *INDENT-OFF* */
2783VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2784 .function = ip4_rewrite,
2785 .name = "ip4-rewrite",
2786 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002787
Neale Ranns32e1c012016-11-22 17:07:28 +00002788 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002789
Neale Ranns32e1c012016-11-22 17:07:28 +00002790 .n_next_nodes = 2,
2791 .next_nodes = {
2792 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2793 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2794 },
2795};
2796VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2797
2798VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2799 .function = ip4_rewrite_mcast,
2800 .name = "ip4-rewrite-mcast",
2801 .vector_size = sizeof (u32),
2802
2803 .format_trace = format_ip4_rewrite_trace,
2804 .sibling_of = "ip4-rewrite",
2805};
2806VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2807
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002808VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2809 .function = ip4_mcast_midchain,
2810 .name = "ip4-mcast-midchain",
2811 .vector_size = sizeof (u32),
2812
2813 .format_trace = format_ip4_rewrite_trace,
2814 .sibling_of = "ip4-rewrite",
2815};
2816VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2817
Neale Ranns32e1c012016-11-22 17:07:28 +00002818VLIB_REGISTER_NODE (ip4_midchain_node) = {
2819 .function = ip4_midchain,
2820 .name = "ip4-midchain",
2821 .vector_size = sizeof (u32),
2822 .format_trace = format_ip4_forward_next_trace,
2823 .sibling_of = "ip4-rewrite",
2824};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002825VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002826/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002827
Ed Warnickecb9cada2015-12-08 15:45:58 -07002828static clib_error_t *
2829add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002830 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002832 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002833 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002834 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002835 u32 sw_if_index, table_id;
2836
2837 sw_if_index = ~0;
2838
Dave Barachd7cb1b52016-12-09 09:52:16 -05002839 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002840 {
2841 error = clib_error_return (0, "unknown interface `%U'",
2842 format_unformat_error, input);
2843 goto done;
2844 }
2845
2846 if (unformat (input, "%d", &table_id))
2847 ;
2848 else
2849 {
2850 error = clib_error_return (0, "expected table id `%U'",
2851 format_unformat_error, input);
2852 goto done;
2853 }
2854
Neale Ranns4008ac92017-02-13 23:20:04 -08002855 /*
2856 * If the interface already has in IP address, then a change int
2857 * VRF is not allowed. The IP address applied must first be removed.
2858 * We do not do that automatically here, since VPP has no knowledge
2859 * of whether thoses subnets are valid in the destination VRF.
2860 */
2861 /* *INDENT-OFF* */
2862 foreach_ip_interface_address (&ip4_main.lookup_main,
2863 ia, sw_if_index,
2864 1 /* honor unnumbered */,
2865 ({
2866 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002867
Neale Ranns4008ac92017-02-13 23:20:04 -08002868 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2869 error = clib_error_return (0, "interface %U has address %U",
2870 format_vnet_sw_if_index_name, vnm,
2871 sw_if_index,
2872 format_ip4_address, a);
2873 goto done;
2874 }));
2875 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002876
Neale Ranns4008ac92017-02-13 23:20:04 -08002877{
2878 ip4_main_t *im = &ip4_main;
2879 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002880
Neale Ranns4008ac92017-02-13 23:20:04 -08002881 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2882
2883 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2884 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2885
2886 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2887 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2888 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2889}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002890
Dave Barachd7cb1b52016-12-09 09:52:16 -05002891done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002892return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002893}
2894
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002895/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002896 * Place the indicated interface into the supplied IPv4 FIB table (also known
2897 * as a VRF). If the FIB table does not exist, this command creates it. To
2898 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2899 * FIB table will only be displayed if a route has been added to the table, or
2900 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002901 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002902 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002903 * @note IP addresses added after setting the interface IP table are added to
2904 * the indicated FIB table. If an IP address is added prior to changing the
2905 * table then this is an error. The control plane must remove these addresses
2906 * first and then change the table. VPP will not automatically move the
2907 * addresses from the old to the new table as it does not know the validity
2908 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002909 *
2910 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002911 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2912 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002913 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002914/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002915VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2916{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002917 .path = "set interface ip table",
2918 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002919 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002920};
Billy McFall0683c9c2016-10-13 08:27:31 -04002921/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002922
Dave Barachd7cb1b52016-12-09 09:52:16 -05002923int
2924ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2925{
2926 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002927 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002928 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002929
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002930 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002931
Neale Ranns04a75e32017-03-23 06:46:01 -07002932 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002933 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2934 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002935
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002936 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002937
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002939}
Dave Barach75fc8542016-10-11 16:16:02 -04002940
Ed Warnickecb9cada2015-12-08 15:45:58 -07002941static clib_error_t *
2942test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002943 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002944{
Billy McFall309fe062016-10-14 07:37:33 -04002945 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946 u32 table_id = 0;
2947 f64 count = 1;
2948 u32 n;
2949 int i;
2950 ip4_address_t ip4_base_address;
2951 u64 errors = 0;
2952
Dave Barachd7cb1b52016-12-09 09:52:16 -05002953 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2954 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002955 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002956 {
2957 /* Make sure the entry exists. */
2958 fib = ip4_fib_get (table_id);
2959 if ((fib) && (fib->index != table_id))
2960 return clib_error_return (0, "<fib-index> %d does not exist",
2961 table_id);
2962 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002963 else if (unformat (input, "count %f", &count))
2964 ;
2965
2966 else if (unformat (input, "%U",
2967 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002968 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002969 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002970 return clib_error_return (0, "unknown input `%U'",
2971 format_unformat_error, input);
2972 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002973
2974 n = count;
2975
2976 for (i = 0; i < n; i++)
2977 {
2978 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002979 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002980
Dave Barach75fc8542016-10-11 16:16:02 -04002981 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002982 clib_host_to_net_u32 (1 +
2983 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002984 }
2985
Dave Barach75fc8542016-10-11 16:16:02 -04002986 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002987 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2988 else
2989 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2990
2991 return 0;
2992}
2993
Billy McFall0683c9c2016-10-13 08:27:31 -04002994/*?
2995 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2996 * given FIB table to determine if there is a conflict with the
2997 * adjacency table. The fib-id can be determined by using the
2998 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2999 * of 0 is used.
3000 *
3001 * @todo This command uses fib-id, other commands use table-id (not
3002 * just a name, they are different indexes). Would like to change this
3003 * to table-id for consistency.
3004 *
3005 * @cliexpar
3006 * Example of how to run the test lookup command:
3007 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3008 * No errors in 2 lookups
3009 * @cliexend
3010?*/
3011/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003012VLIB_CLI_COMMAND (lookup_test_command, static) =
3013{
3014 .path = "test lookup",
3015 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3016 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003017};
Billy McFall0683c9c2016-10-13 08:27:31 -04003018/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019
Dave Barachd7cb1b52016-12-09 09:52:16 -05003020int
3021vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022{
Neale Ranns107e7d42017-04-11 09:55:19 -07003023 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024
Neale Ranns107e7d42017-04-11 09:55:19 -07003025 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
3026
3027 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003028 return VNET_API_ERROR_NO_SUCH_FIB;
3029
Neale Ranns227038a2017-04-21 01:07:59 -07003030 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3031 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032
Ed Warnickecb9cada2015-12-08 15:45:58 -07003033 return 0;
3034}
Dave Barach75fc8542016-10-11 16:16:02 -04003035
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036static clib_error_t *
3037set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003038 unformat_input_t * input,
3039 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003040{
3041 int matched = 0;
3042 u32 table_id = 0;
3043 u32 flow_hash_config = 0;
3044 int rv;
3045
Dave Barachd7cb1b52016-12-09 09:52:16 -05003046 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3047 {
3048 if (unformat (input, "table %d", &table_id))
3049 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003050#define _(a,v) \
3051 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003052 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003053#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003054 else
3055 break;
3056 }
Dave Barach75fc8542016-10-11 16:16:02 -04003057
Ed Warnickecb9cada2015-12-08 15:45:58 -07003058 if (matched == 0)
3059 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003060 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003061
Ed Warnickecb9cada2015-12-08 15:45:58 -07003062 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3063 switch (rv)
3064 {
3065 case 0:
3066 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003067
Ed Warnickecb9cada2015-12-08 15:45:58 -07003068 case VNET_API_ERROR_NO_SUCH_FIB:
3069 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003070
Ed Warnickecb9cada2015-12-08 15:45:58 -07003071 default:
3072 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3073 break;
3074 }
Dave Barach75fc8542016-10-11 16:16:02 -04003075
Ed Warnickecb9cada2015-12-08 15:45:58 -07003076 return 0;
3077}
Dave Barach75fc8542016-10-11 16:16:02 -04003078
Billy McFall0683c9c2016-10-13 08:27:31 -04003079/*?
3080 * Configure the set of IPv4 fields used by the flow hash.
3081 *
3082 * @cliexpar
3083 * Example of how to set the flow hash on a given table:
3084 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3085 * Example of display the configured flow hash:
3086 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003087 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3088 * 0.0.0.0/0
3089 * unicast-ip4-chain
3090 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3091 * [0] [@0]: dpo-drop ip6
3092 * 0.0.0.0/32
3093 * unicast-ip4-chain
3094 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3095 * [0] [@0]: dpo-drop ip6
3096 * 224.0.0.0/8
3097 * unicast-ip4-chain
3098 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3099 * [0] [@0]: dpo-drop ip6
3100 * 6.0.1.2/32
3101 * unicast-ip4-chain
3102 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3103 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3104 * 7.0.0.1/32
3105 * unicast-ip4-chain
3106 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3107 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3108 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3109 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3110 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3111 * 240.0.0.0/8
3112 * unicast-ip4-chain
3113 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3114 * [0] [@0]: dpo-drop ip6
3115 * 255.255.255.255/32
3116 * unicast-ip4-chain
3117 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3118 * [0] [@0]: dpo-drop ip6
3119 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3120 * 0.0.0.0/0
3121 * unicast-ip4-chain
3122 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3123 * [0] [@0]: dpo-drop ip6
3124 * 0.0.0.0/32
3125 * unicast-ip4-chain
3126 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3127 * [0] [@0]: dpo-drop ip6
3128 * 172.16.1.0/24
3129 * unicast-ip4-chain
3130 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3131 * [0] [@4]: ipv4-glean: af_packet0
3132 * 172.16.1.1/32
3133 * unicast-ip4-chain
3134 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3135 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3136 * 172.16.1.2/32
3137 * unicast-ip4-chain
3138 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3139 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3140 * 172.16.2.0/24
3141 * unicast-ip4-chain
3142 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3143 * [0] [@4]: ipv4-glean: af_packet1
3144 * 172.16.2.1/32
3145 * unicast-ip4-chain
3146 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3147 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3148 * 224.0.0.0/8
3149 * unicast-ip4-chain
3150 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3151 * [0] [@0]: dpo-drop ip6
3152 * 240.0.0.0/8
3153 * unicast-ip4-chain
3154 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3155 * [0] [@0]: dpo-drop ip6
3156 * 255.255.255.255/32
3157 * unicast-ip4-chain
3158 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3159 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003160 * @cliexend
3161?*/
3162/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003163VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3164{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003165 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003166 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003167 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003168 .function = set_ip_flow_hash_command_fn,
3169};
Billy McFall0683c9c2016-10-13 08:27:31 -04003170/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003171
Dave Barachd7cb1b52016-12-09 09:52:16 -05003172int
3173vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3174 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003176 vnet_main_t *vnm = vnet_get_main ();
3177 vnet_interface_main_t *im = &vnm->interface_main;
3178 ip4_main_t *ipm = &ip4_main;
3179 ip_lookup_main_t *lm = &ipm->lookup_main;
3180 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003181 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003182
3183 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3184 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3185
3186 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3187 return VNET_API_ERROR_NO_SUCH_ENTRY;
3188
3189 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003190 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003191
Neale Rannsdf089a82016-10-02 16:39:06 +01003192 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3193
3194 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003195 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003196 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003197 .fp_len = 32,
3198 .fp_proto = FIB_PROTOCOL_IP4,
3199 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003200 };
3201 u32 fib_index;
3202
Dave Barachd7cb1b52016-12-09 09:52:16 -05003203 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3204 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003205
3206
Dave Barachd7cb1b52016-12-09 09:52:16 -05003207 if (table_index != (u32) ~ 0)
3208 {
3209 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003210
Dave Barachd7cb1b52016-12-09 09:52:16 -05003211 dpo_set (&dpo,
3212 DPO_CLASSIFY,
3213 DPO_PROTO_IP4,
3214 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003215
Dave Barachd7cb1b52016-12-09 09:52:16 -05003216 fib_table_entry_special_dpo_add (fib_index,
3217 &pfx,
3218 FIB_SOURCE_CLASSIFY,
3219 FIB_ENTRY_FLAG_NONE, &dpo);
3220 dpo_reset (&dpo);
3221 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003222 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003223 {
3224 fib_table_entry_special_remove (fib_index,
3225 &pfx, FIB_SOURCE_CLASSIFY);
3226 }
3227 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003228
Ed Warnickecb9cada2015-12-08 15:45:58 -07003229 return 0;
3230}
3231
3232static clib_error_t *
3233set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003234 unformat_input_t * input,
3235 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003236{
3237 u32 table_index = ~0;
3238 int table_index_set = 0;
3239 u32 sw_if_index = ~0;
3240 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003241
Dave Barachd7cb1b52016-12-09 09:52:16 -05003242 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3243 {
3244 if (unformat (input, "table-index %d", &table_index))
3245 table_index_set = 1;
3246 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3247 vnet_get_main (), &sw_if_index))
3248 ;
3249 else
3250 break;
3251 }
Dave Barach75fc8542016-10-11 16:16:02 -04003252
Ed Warnickecb9cada2015-12-08 15:45:58 -07003253 if (table_index_set == 0)
3254 return clib_error_return (0, "classify table-index must be specified");
3255
3256 if (sw_if_index == ~0)
3257 return clib_error_return (0, "interface / subif must be specified");
3258
3259 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3260
3261 switch (rv)
3262 {
3263 case 0:
3264 break;
3265
3266 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3267 return clib_error_return (0, "No such interface");
3268
3269 case VNET_API_ERROR_NO_SUCH_ENTRY:
3270 return clib_error_return (0, "No such classifier table");
3271 }
3272 return 0;
3273}
3274
Billy McFall0683c9c2016-10-13 08:27:31 -04003275/*?
3276 * Assign a classification table to an interface. The classification
3277 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3278 * commands. Once the table is create, use this command to filter packets
3279 * on an interface.
3280 *
3281 * @cliexpar
3282 * Example of how to assign a classification table to an interface:
3283 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3284?*/
3285/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003286VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3287{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003288 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003289 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003290 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003291 .function = set_ip_classify_command_fn,
3292};
Billy McFall0683c9c2016-10-13 08:27:31 -04003293/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003294
3295/*
3296 * fd.io coding-style-patch-verification: ON
3297 *
3298 * Local Variables:
3299 * eval: (c-set-style "gnu")
3300 * End:
3301 */