blob: 58cfd1816d8b3f0bd29aeeeb9c8430a161c91cc2 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip/ip4_forward.c: IP v4 forwarding
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/vnet.h>
41#include <vnet/ip/ip.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010042#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
43#include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/ppp/ppp.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010045#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
Dave Barachd7cb1b52016-12-09 09:52:16 -050046#include <vnet/api_errno.h> /* for API error numbers */
47#include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
48#include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
49#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/fib/ip4_fib.h>
51#include <vnet/dpo/load_balance.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070052#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010053#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000054#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070055
Billy McFall0683c9c2016-10-13 08:27:31 -040056/**
57 * @file
58 * @brief IPv4 Forwarding.
59 *
60 * This file contains the source code for IPv4 forwarding.
61 */
62
Pierre Pfister0febaf12016-06-08 12:23:21 +010063void
64ip4_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050065 vlib_node_runtime_t * node,
66 vlib_frame_t * frame,
67 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010068
Ed Warnickecb9cada2015-12-08 15:45:58 -070069always_inline uword
70ip4_lookup_inline (vlib_main_t * vm,
71 vlib_node_runtime_t * node,
72 vlib_frame_t * frame,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010073 int lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -070074{
Dave Barachd7cb1b52016-12-09 09:52:16 -050075 ip4_main_t *im = &ip4_main;
76 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
77 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070078 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020079 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070080
81 from = vlib_frame_vector_args (frame);
82 n_left_from = frame->n_vectors;
83 next = node->cached_next_index;
84
85 while (n_left_from > 0)
86 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050087 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070088
Dave Barach670909e2016-10-18 15:25:35 -040089 while (n_left_from >= 8 && n_left_to_next >= 4)
Dave Barachd7cb1b52016-12-09 09:52:16 -050090 {
91 vlib_buffer_t *p0, *p1, *p2, *p3;
92 ip4_header_t *ip0, *ip1, *ip2, *ip3;
Dave Barachd7cb1b52016-12-09 09:52:16 -050093 ip_lookup_next_t next0, next1, next2, next3;
94 const load_balance_t *lb0, *lb1, *lb2, *lb3;
95 ip4_fib_mtrie_t *mtrie0, *mtrie1, *mtrie2, *mtrie3;
96 ip4_fib_mtrie_leaf_t leaf0, leaf1, leaf2, leaf3;
97 ip4_address_t *dst_addr0, *dst_addr1, *dst_addr2, *dst_addr3;
Neale Ranns340690e2017-03-22 13:27:53 -070098 u32 pi0, fib_index0, lb_index0;
99 u32 pi1, fib_index1, lb_index1;
100 u32 pi2, fib_index2, lb_index2;
101 u32 pi3, fib_index3, lb_index3;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500102 flow_hash_config_t flow_hash_config0, flow_hash_config1;
103 flow_hash_config_t flow_hash_config2, flow_hash_config3;
104 u32 hash_c0, hash_c1, hash_c2, hash_c3;
Dave Barach670909e2016-10-18 15:25:35 -0400105 const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106
Dave Barachd7cb1b52016-12-09 09:52:16 -0500107 /* Prefetch next iteration. */
108 {
109 vlib_buffer_t *p4, *p5, *p6, *p7;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110
Dave Barachd7cb1b52016-12-09 09:52:16 -0500111 p4 = vlib_get_buffer (vm, from[4]);
112 p5 = vlib_get_buffer (vm, from[5]);
113 p6 = vlib_get_buffer (vm, from[6]);
114 p7 = vlib_get_buffer (vm, from[7]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
Dave Barachd7cb1b52016-12-09 09:52:16 -0500116 vlib_prefetch_buffer_header (p4, LOAD);
117 vlib_prefetch_buffer_header (p5, LOAD);
118 vlib_prefetch_buffer_header (p6, LOAD);
119 vlib_prefetch_buffer_header (p7, LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Dave Barachd7cb1b52016-12-09 09:52:16 -0500121 CLIB_PREFETCH (p4->data, sizeof (ip0[0]), LOAD);
122 CLIB_PREFETCH (p5->data, sizeof (ip0[0]), LOAD);
123 CLIB_PREFETCH (p6->data, sizeof (ip0[0]), LOAD);
124 CLIB_PREFETCH (p7->data, sizeof (ip0[0]), LOAD);
125 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Dave Barachd7cb1b52016-12-09 09:52:16 -0500127 pi0 = to_next[0] = from[0];
128 pi1 = to_next[1] = from[1];
129 pi2 = to_next[2] = from[2];
130 pi3 = to_next[3] = from[3];
Dave Barach670909e2016-10-18 15:25:35 -0400131
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 from += 4;
133 to_next += 4;
134 n_left_to_next -= 4;
135 n_left_from -= 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
Dave Barachd7cb1b52016-12-09 09:52:16 -0500137 p0 = vlib_get_buffer (vm, pi0);
138 p1 = vlib_get_buffer (vm, pi1);
139 p2 = vlib_get_buffer (vm, pi2);
140 p3 = vlib_get_buffer (vm, pi3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
Dave Barachd7cb1b52016-12-09 09:52:16 -0500142 ip0 = vlib_buffer_get_current (p0);
143 ip1 = vlib_buffer_get_current (p1);
144 ip2 = vlib_buffer_get_current (p2);
145 ip3 = vlib_buffer_get_current (p3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Dave Barachd7cb1b52016-12-09 09:52:16 -0500147 dst_addr0 = &ip0->dst_address;
148 dst_addr1 = &ip1->dst_address;
149 dst_addr2 = &ip2->dst_address;
150 dst_addr3 = &ip3->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200151
Dave Barachd7cb1b52016-12-09 09:52:16 -0500152 fib_index0 =
153 vec_elt (im->fib_index_by_sw_if_index,
154 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
155 fib_index1 =
156 vec_elt (im->fib_index_by_sw_if_index,
157 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
158 fib_index2 =
159 vec_elt (im->fib_index_by_sw_if_index,
160 vnet_buffer (p2)->sw_if_index[VLIB_RX]);
161 fib_index3 =
162 vec_elt (im->fib_index_by_sw_if_index,
163 vnet_buffer (p3)->sw_if_index[VLIB_RX]);
164 fib_index0 =
165 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
166 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
167 fib_index1 =
168 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
169 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
170 fib_index2 =
171 (vnet_buffer (p2)->sw_if_index[VLIB_TX] ==
172 (u32) ~ 0) ? fib_index2 : vnet_buffer (p2)->sw_if_index[VLIB_TX];
173 fib_index3 =
174 (vnet_buffer (p3)->sw_if_index[VLIB_TX] ==
175 (u32) ~ 0) ? fib_index3 : vnet_buffer (p3)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
177
Dave Barachd7cb1b52016-12-09 09:52:16 -0500178 if (!lookup_for_responses_to_locally_received_packets)
179 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100180 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
181 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Dave Barach670909e2016-10-18 15:25:35 -0400182 mtrie2 = &ip4_fib_get (fib_index2)->mtrie;
183 mtrie3 = &ip4_fib_get (fib_index3)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184
Neale Ranns04a75e32017-03-23 06:46:01 -0700185 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, dst_addr0);
186 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, dst_addr1);
187 leaf2 = ip4_fib_mtrie_lookup_step_one (mtrie2, dst_addr2);
188 leaf3 = ip4_fib_mtrie_lookup_step_one (mtrie3, dst_addr3);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barachd7cb1b52016-12-09 09:52:16 -0500191 if (!lookup_for_responses_to_locally_received_packets)
192 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500193 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
194 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
195 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 2);
196 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 2);
197 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198
Dave Barachd7cb1b52016-12-09 09:52:16 -0500199 if (!lookup_for_responses_to_locally_received_packets)
200 {
201 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
202 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
203 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 3);
204 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 3);
205 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206
Dave Barachd7cb1b52016-12-09 09:52:16 -0500207 if (lookup_for_responses_to_locally_received_packets)
208 {
209 lb_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
210 lb_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
211 lb_index2 = vnet_buffer (p2)->ip.adj_index[VLIB_RX];
212 lb_index3 = vnet_buffer (p3)->ip.adj_index[VLIB_RX];
213 }
214 else
215 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500216 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
217 lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
218 lb_index2 = ip4_fib_mtrie_leaf_get_adj_index (leaf2);
219 lb_index3 = ip4_fib_mtrie_leaf_get_adj_index (leaf3);
220 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
Neale Ranns04a75e32017-03-23 06:46:01 -0700222 ASSERT (lb_index0 && lb_index1 && lb_index2 && lb_index3);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100223 lb0 = load_balance_get (lb_index0);
224 lb1 = load_balance_get (lb_index1);
Dave Barach670909e2016-10-18 15:25:35 -0400225 lb2 = load_balance_get (lb_index2);
226 lb3 = load_balance_get (lb_index3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
Neale Rannsf12a83f2017-04-18 09:09:40 -0700228 ASSERT (lb0->lb_n_buckets > 0);
229 ASSERT (is_pow2 (lb0->lb_n_buckets));
230 ASSERT (lb1->lb_n_buckets > 0);
231 ASSERT (is_pow2 (lb1->lb_n_buckets));
232 ASSERT (lb2->lb_n_buckets > 0);
233 ASSERT (is_pow2 (lb2->lb_n_buckets));
234 ASSERT (lb3->lb_n_buckets > 0);
235 ASSERT (is_pow2 (lb3->lb_n_buckets));
236
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 /* Use flow hash to compute multipath adjacency. */
238 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
239 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
240 hash_c2 = vnet_buffer (p2)->ip.flow_hash = 0;
241 hash_c3 = vnet_buffer (p3)->ip.flow_hash = 0;
242 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
243 {
244 flow_hash_config0 = lb0->lb_hash_config;
245 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
246 ip4_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700247 dpo0 =
248 load_balance_get_fwd_bucket (lb0,
249 (hash_c0 &
250 (lb0->lb_n_buckets_minus_1)));
251 }
252 else
253 {
254 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500255 }
256 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
257 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100258 flow_hash_config1 = lb1->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500259 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
260 ip4_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700261 dpo1 =
262 load_balance_get_fwd_bucket (lb1,
263 (hash_c1 &
264 (lb1->lb_n_buckets_minus_1)));
265 }
266 else
267 {
268 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500269 }
270 if (PREDICT_FALSE (lb2->lb_n_buckets > 1))
271 {
272 flow_hash_config2 = lb2->lb_hash_config;
273 hash_c2 = vnet_buffer (p2)->ip.flow_hash =
274 ip4_compute_flow_hash (ip2, flow_hash_config2);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700275 dpo2 =
276 load_balance_get_fwd_bucket (lb2,
277 (hash_c2 &
278 (lb2->lb_n_buckets_minus_1)));
279 }
280 else
281 {
282 dpo2 = load_balance_get_bucket_i (lb2, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500283 }
284 if (PREDICT_FALSE (lb3->lb_n_buckets > 1))
285 {
Dave Barach670909e2016-10-18 15:25:35 -0400286 flow_hash_config3 = lb3->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500287 hash_c3 = vnet_buffer (p3)->ip.flow_hash =
288 ip4_compute_flow_hash (ip3, flow_hash_config3);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700289 dpo3 =
290 load_balance_get_fwd_bucket (lb3,
291 (hash_c3 &
292 (lb3->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700294 else
295 {
296 dpo3 = load_balance_get_bucket_i (lb3, 0);
297 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100299 next0 = dpo0->dpoi_next_node;
300 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
301 next1 = dpo1->dpoi_next_node;
302 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Dave Barach670909e2016-10-18 15:25:35 -0400303 next2 = dpo2->dpoi_next_node;
304 vnet_buffer (p2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
305 next3 = dpo3->dpoi_next_node;
306 vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200307
Dave Barachd7cb1b52016-12-09 09:52:16 -0500308 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200309 (cm, thread_index, lb_index0, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700310 vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500311 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200312 (cm, thread_index, lb_index1, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700313 vlib_buffer_length_in_chain (vm, p1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500314 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200315 (cm, thread_index, lb_index2, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700316 vlib_buffer_length_in_chain (vm, p2));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200318 (cm, thread_index, lb_index3, 1,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700319 vlib_buffer_length_in_chain (vm, p3));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320
Dave Barach670909e2016-10-18 15:25:35 -0400321 vlib_validate_buffer_enqueue_x4 (vm, node, next,
322 to_next, n_left_to_next,
323 pi0, pi1, pi2, pi3,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500324 next0, next1, next2, next3);
325 }
Dave Barach75fc8542016-10-11 16:16:02 -0400326
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327 while (n_left_from > 0 && n_left_to_next > 0)
328 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329 vlib_buffer_t *p0;
330 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700331 ip_lookup_next_t next0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100332 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500333 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 ip4_fib_mtrie_leaf_t leaf0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500335 ip4_address_t *dst_addr0;
Neale Ranns340690e2017-03-22 13:27:53 -0700336 u32 pi0, fib_index0, lbi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500337 flow_hash_config_t flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100338 const dpo_id_t *dpo0;
339 u32 hash_c0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
341 pi0 = from[0];
342 to_next[0] = pi0;
343
344 p0 = vlib_get_buffer (vm, pi0);
345
346 ip0 = vlib_buffer_get_current (p0);
347
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100348 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200349
Dave Barachd7cb1b52016-12-09 09:52:16 -0500350 fib_index0 =
351 vec_elt (im->fib_index_by_sw_if_index,
352 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
353 fib_index0 =
354 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
355 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356
Dave Barachd7cb1b52016-12-09 09:52:16 -0500357 if (!lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500359 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360
Neale Ranns04a75e32017-03-23 06:46:01 -0700361 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362 }
363
Dave Barachd7cb1b52016-12-09 09:52:16 -0500364 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200365 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
Dave Barachd7cb1b52016-12-09 09:52:16 -0500367 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200368 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369
370 if (lookup_for_responses_to_locally_received_packets)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100371 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372 else
373 {
374 /* Handle default route. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 }
377
Neale Ranns04a75e32017-03-23 06:46:01 -0700378 ASSERT (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100379 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380
Neale Rannsf12a83f2017-04-18 09:09:40 -0700381 ASSERT (lb0->lb_n_buckets > 0);
382 ASSERT (is_pow2 (lb0->lb_n_buckets));
383
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 /* Use flow hash to compute multipath adjacency. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500385 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
386 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
387 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100388 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389
Dave Barachd7cb1b52016-12-09 09:52:16 -0500390 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
391 ip4_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700392 dpo0 =
393 load_balance_get_fwd_bucket (lb0,
394 (hash_c0 &
395 (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500396 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700397 else
398 {
399 dpo0 = load_balance_get_bucket_i (lb0, 0);
400 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100402 next0 = dpo0->dpoi_next_node;
403 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200404
Neale Rannsf12a83f2017-04-18 09:09:40 -0700405 vlib_increment_combined_counter (cm, thread_index, lbi0, 1,
406 vlib_buffer_length_in_chain (vm,
407 p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408
409 from += 1;
410 to_next += 1;
411 n_left_to_next -= 1;
412 n_left_from -= 1;
413
414 if (PREDICT_FALSE (next0 != next))
415 {
416 n_left_to_next += 1;
417 vlib_put_next_frame (vm, node, next, n_left_to_next);
418 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500419 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 to_next[0] = pi0;
421 to_next += 1;
422 n_left_to_next -= 1;
423 }
424 }
425
426 vlib_put_next_frame (vm, node, next, n_left_to_next);
427 }
428
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100429 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500430 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100431
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432 return frame->n_vectors;
433}
434
Chris Luke8e5b0412016-07-26 13:06:10 -0400435/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -0400436 @node ip4-lookup
437
438 This is the main IPv4 lookup dispatch node.
439
440 @param vm vlib_main_t corresponding to the current thread
441 @param node vlib_node_runtime_t
442 @param frame vlib_frame_t whose contents should be dispatched
443
444 @par Graph mechanics: buffer metadata, next index usage
445
446 @em Uses:
447 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
448 - Indicates the @c sw_if_index value of the interface that the
449 packet was received on.
450 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
451 - When the value is @c ~0 then the node performs a longest prefix
452 match (LPM) for the packet destination address in the FIB attached
453 to the receive interface.
454 - Otherwise perform LPM for the packet destination address in the
455 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
456 value (0, 1, ...) and not a VRF id.
457
458 @em Sets:
459 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
460 - The lookup result adjacency index.
461
462 <em>Next Index:</em>
463 - Dispatches the packet to the node index found in
464 ip_adjacency_t @c adj->lookup_next_index
465 (where @c adj is the lookup result adjacency).
466*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467static uword
468ip4_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500469 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470{
Damjan Marionaca64c92016-04-13 09:48:56 +0200471 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 /* lookup_for_responses_to_locally_received_packets */
473 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474
475}
476
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100478
Dave Barachd7cb1b52016-12-09 09:52:16 -0500479VLIB_REGISTER_NODE (ip4_lookup_node) =
480{
481.function = ip4_lookup,.name = "ip4-lookup",.vector_size =
482 sizeof (u32),.format_trace = format_ip4_lookup_trace,.n_next_nodes =
483 IP_LOOKUP_N_NEXT,.next_nodes = IP4_LOOKUP_NEXT_NODES,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484
Dave Barachd7cb1b52016-12-09 09:52:16 -0500485VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100486
487always_inline uword
488ip4_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500489 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500491 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
492 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100493 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200494 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100496 from = vlib_frame_vector_args (frame);
497 n_left_from = frame->n_vectors;
498 next = node->cached_next_index;
499
500 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500501 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100502
503 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700504 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100506
Dave Barach75fc8542016-10-11 16:16:02 -0400507
Neale Ranns2be95c12016-11-19 13:50:04 +0000508 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500509 {
510 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000511 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500512 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000513 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
514 const ip4_header_t *ip0, *ip1;
515 const dpo_id_t *dpo0, *dpo1;
516
Dave Barachd7cb1b52016-12-09 09:52:16 -0500517 /* Prefetch next iteration. */
518 {
519 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000520
521 p2 = vlib_get_buffer (vm, from[2]);
522 p3 = vlib_get_buffer (vm, from[3]);
523
524 vlib_prefetch_buffer_header (p2, STORE);
525 vlib_prefetch_buffer_header (p3, STORE);
526
527 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
528 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000530
531 pi0 = to_next[0] = from[0];
532 pi1 = to_next[1] = from[1];
533
534 from += 2;
535 n_left_from -= 2;
536 to_next += 2;
537 n_left_to_next -= 2;
538
539 p0 = vlib_get_buffer (vm, pi0);
540 p1 = vlib_get_buffer (vm, pi1);
541
542 ip0 = vlib_buffer_get_current (p0);
543 ip1 = vlib_buffer_get_current (p1);
544 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
545 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
546
Dave Barachd7cb1b52016-12-09 09:52:16 -0500547 lb0 = load_balance_get (lbi0);
548 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000549
Dave Barachd7cb1b52016-12-09 09:52:16 -0500550 /*
551 * this node is for via FIBs we can re-use the hash value from the
552 * to node if present.
553 * We don't want to use the same hash value at each level in the recursion
554 * graph as that would lead to polarisation
555 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000556 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000557
Dave Barachd7cb1b52016-12-09 09:52:16 -0500558 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
559 {
560 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
561 {
562 hc0 = vnet_buffer (p0)->ip.flow_hash =
563 vnet_buffer (p0)->ip.flow_hash >> 1;
564 }
565 else
566 {
567 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000568 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500569 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700570 dpo0 = load_balance_get_fwd_bucket
571 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
572 }
573 else
574 {
575 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500576 }
577 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
578 {
579 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
580 {
581 hc1 = vnet_buffer (p1)->ip.flow_hash =
582 vnet_buffer (p1)->ip.flow_hash >> 1;
583 }
584 else
585 {
586 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000587 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700589 dpo1 = load_balance_get_fwd_bucket
590 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500591 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700592 else
593 {
594 dpo1 = load_balance_get_bucket_i (lb1, 0);
595 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000596
597 next0 = dpo0->dpoi_next_node;
598 next1 = dpo1->dpoi_next_node;
599
600 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
601 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
602
603 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200604 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000605 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200606 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000607
608 vlib_validate_buffer_enqueue_x2 (vm, node, next,
609 to_next, n_left_to_next,
610 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500611 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000612
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100613 while (n_left_from > 0 && n_left_to_next > 0)
614 {
615 ip_lookup_next_t next0;
616 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500617 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100618 u32 pi0, lbi0, hc0;
619 const ip4_header_t *ip0;
620 const dpo_id_t *dpo0;
621
622 pi0 = from[0];
623 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000624 from += 1;
625 to_next += 1;
626 n_left_to_next -= 1;
627 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628
629 p0 = vlib_get_buffer (vm, pi0);
630
631 ip0 = vlib_buffer_get_current (p0);
632 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
633
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100635
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000636 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500637 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
638 {
639 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
640 {
641 hc0 = vnet_buffer (p0)->ip.flow_hash =
642 vnet_buffer (p0)->ip.flow_hash >> 1;
643 }
644 else
645 {
646 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000647 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500648 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700649 dpo0 = load_balance_get_fwd_bucket
650 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500651 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700652 else
653 {
654 dpo0 = load_balance_get_bucket_i (lb0, 0);
655 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656
657 next0 = dpo0->dpoi_next_node;
658 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
659
Dave Barach75fc8542016-10-11 16:16:02 -0400660 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200661 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100662
Neale Ranns2be95c12016-11-19 13:50:04 +0000663 vlib_validate_buffer_enqueue_x1 (vm, node, next,
664 to_next, n_left_to_next,
665 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100666 }
667
668 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669 }
670
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100671 return frame->n_vectors;
672}
673
Dave Barachd7cb1b52016-12-09 09:52:16 -0500674VLIB_REGISTER_NODE (ip4_load_balance_node) =
675{
676.function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
677 sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
678 format_ip4_lookup_trace,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100679
Dave Barachd7cb1b52016-12-09 09:52:16 -0500680VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100681
682/* get first interface address */
683ip4_address_t *
684ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500685 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100686{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687 ip_lookup_main_t *lm = &im->lookup_main;
688 ip_interface_address_t *ia = 0;
689 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690
Neale Ranns32e1c012016-11-22 17:07:28 +0000691 /* *INDENT-OFF* */
692 foreach_ip_interface_address
693 (lm, ia, sw_if_index,
694 1 /* honor unnumbered */ ,
695 ({
696 ip4_address_t * a =
697 ip_interface_address_get_address (lm, ia);
698 result = a;
699 break;
700 }));
701 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100702 if (result_ia)
703 *result_ia = result ? ia : 0;
704 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705}
706
707static void
708ip4_add_interface_routes (u32 sw_if_index,
709 ip4_main_t * im, u32 fib_index,
710 ip_interface_address_t * a)
711{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500712 ip_lookup_main_t *lm = &im->lookup_main;
713 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100714 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500715 .fp_len = a->address_length,
716 .fp_proto = FIB_PROTOCOL_IP4,
717 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100718 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
Neale Ranns9a69a602017-03-26 10:56:33 -0700720 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500721 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700722 /* a /30 or shorter - add a glean for the network address */
Neale Ranns7a272742017-05-30 02:08:14 -0700723 fib_table_entry_update_one_path (fib_index, &pfx,
724 FIB_SOURCE_INTERFACE,
725 (FIB_ENTRY_FLAG_CONNECTED |
726 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700727 DPO_PROTO_IP4,
Neale Ranns7a272742017-05-30 02:08:14 -0700728 /* No next-hop address */
729 NULL,
730 sw_if_index,
731 // invalid FIB index
732 ~0,
733 1,
734 // no out-label stack
735 NULL,
736 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100737
Neale Ranns9a69a602017-03-26 10:56:33 -0700738 /* Add the two broadcast addresses as drop */
739 fib_prefix_t net_pfx = {
740 .fp_len = 32,
741 .fp_proto = FIB_PROTOCOL_IP4,
742 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
743 };
744 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
745 fib_table_entry_special_add(fib_index,
746 &net_pfx,
747 FIB_SOURCE_INTERFACE,
748 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700749 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700750 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
751 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
752 fib_table_entry_special_add(fib_index,
753 &net_pfx,
754 FIB_SOURCE_INTERFACE,
755 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700756 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700757 }
758 else if (pfx.fp_len == 31)
759 {
760 u32 mask = clib_host_to_net_u32(1);
761 fib_prefix_t net_pfx = pfx;
762
763 net_pfx.fp_len = 32;
764 net_pfx.fp_addr.ip4.as_u32 ^= mask;
765
766 /* a /31 - add the other end as an attached host */
767 fib_table_entry_update_one_path (fib_index, &net_pfx,
768 FIB_SOURCE_INTERFACE,
769 (FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700770 DPO_PROTO_IP4,
Neale Ranns9a69a602017-03-26 10:56:33 -0700771 &net_pfx.fp_addr,
772 sw_if_index,
773 // invalid FIB index
774 ~0,
775 1,
776 NULL,
777 FIB_ROUTE_PATH_FLAG_NONE);
778 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100779 pfx.fp_len = 32;
780
781 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100783 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 lm->classify_table_index_by_sw_if_index[sw_if_index];
785 if (classify_table_index != (u32) ~ 0)
786 {
787 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100788
Dave Barachd7cb1b52016-12-09 09:52:16 -0500789 dpo_set (&dpo,
790 DPO_CLASSIFY,
791 DPO_PROTO_IP4,
792 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100793
Dave Barachd7cb1b52016-12-09 09:52:16 -0500794 fib_table_entry_special_dpo_add (fib_index,
795 &pfx,
796 FIB_SOURCE_CLASSIFY,
797 FIB_ENTRY_FLAG_NONE, &dpo);
798 dpo_reset (&dpo);
799 }
800 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100801
Neale Ranns32e1c012016-11-22 17:07:28 +0000802 fib_table_entry_update_one_path (fib_index, &pfx,
803 FIB_SOURCE_INTERFACE,
804 (FIB_ENTRY_FLAG_CONNECTED |
805 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700806 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000807 &pfx.fp_addr,
808 sw_if_index,
809 // invalid FIB index
810 ~0,
811 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813}
814
815static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100816ip4_del_interface_routes (ip4_main_t * im,
817 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500818 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700819{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500820 fib_prefix_t pfx = {
821 .fp_len = address_length,
822 .fp_proto = FIB_PROTOCOL_IP4,
823 .fp_addr.ip4 = *address,
824 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825
Neale Ranns9a69a602017-03-26 10:56:33 -0700826 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100827 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700828 fib_prefix_t net_pfx = {
829 .fp_len = 32,
830 .fp_proto = FIB_PROTOCOL_IP4,
831 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
832 };
833 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
834 fib_table_entry_special_remove(fib_index,
835 &net_pfx,
836 FIB_SOURCE_INTERFACE);
837 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
838 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
839 fib_table_entry_special_remove(fib_index,
840 &net_pfx,
841 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500842 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100843 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700844 else if (pfx.fp_len == 31)
845 {
846 u32 mask = clib_host_to_net_u32(1);
847 fib_prefix_t net_pfx = pfx;
848
849 net_pfx.fp_len = 32;
850 net_pfx.fp_addr.ip4.as_u32 ^= mask;
851
852 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
853 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854
Dave Barachd7cb1b52016-12-09 09:52:16 -0500855 pfx.fp_len = 32;
856 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857}
858
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100859void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500860ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100861{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100864 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
865
866 /*
867 * enable/disable only on the 1<->0 transition
868 */
869 if (is_enable)
870 {
871 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500872 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100873 }
874 else
875 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500876 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100877 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500878 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100879 }
Damjan Marion4d489932016-12-09 03:21:27 -0800880 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
881 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100882
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100883
Neale Ranns180279b2017-03-16 15:49:09 -0400884 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop",
885 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100886}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700887
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888static clib_error_t *
889ip4_add_del_interface_address_internal (vlib_main_t * vm,
890 u32 sw_if_index,
891 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500892 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500894 vnet_main_t *vnm = vnet_get_main ();
895 ip4_main_t *im = &ip4_main;
896 ip_lookup_main_t *lm = &im->lookup_main;
897 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500899 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900
Pavel Kotucek57808982017-08-02 08:20:19 +0200901 /* local0 interface doesn't support IP addressing */
902 if (sw_if_index == 0)
903 {
904 return
905 clib_error_create ("local0 interface doesn't support IP addressing");
906 }
907
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
909 ip4_addr_fib_init (&ip4_af, address,
910 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
911 vec_add1 (addr_fib, ip4_af);
912
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100913 /* FIXME-LATER
914 * there is no support for adj-fib handling in the presence of overlapping
915 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
916 * most routers do.
917 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000918 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500919 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100921 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922 with an existing address. */
923 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000924 foreach_ip_interface_address
925 (&im->lookup_main, ia, sw_if_index,
926 0 /* honor unnumbered */ ,
927 ({
928 ip4_address_t * x =
929 ip_interface_address_get_address
930 (&im->lookup_main, ia);
931 if (ip4_destination_matches_route
932 (im, address, x, ia->address_length) ||
933 ip4_destination_matches_route (im,
934 x,
935 address,
936 address_length))
937 return
938 clib_error_create
939 ("failed to add %U which conflicts with %U for interface %U",
940 format_ip4_address_and_length, address,
941 address_length,
942 format_ip4_address_and_length, x,
943 ia->address_length,
944 format_vnet_sw_if_index_name, vnm,
945 sw_if_index);
946 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000948 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949
Ed Warnickecb9cada2015-12-08 15:45:58 -0700950 elts_before = pool_elts (lm->if_address_pool);
951
952 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500953 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954 if (error)
955 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400956
Dave Barachd7cb1b52016-12-09 09:52:16 -0500957 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958
959 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100961 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500962 ip4_add_interface_routes (sw_if_index,
963 im, ip4_af.fib_index,
964 pool_elt_at_index
965 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966
967 /* If pool did not grow/shrink: add duplicate address. */
968 if (elts_before != pool_elts (lm->if_address_pool))
969 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500970 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 vec_foreach (cb, im->add_del_interface_address_callbacks)
972 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500973 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974 }
975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977 vec_free (addr_fib);
978 return error;
979}
980
981clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000982ip4_add_del_interface_address (vlib_main_t * vm,
983 u32 sw_if_index,
984 ip4_address_t * address,
985 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986{
987 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500988 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989}
990
Dave Barachd6534602016-06-14 18:38:02 -0400991/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500992/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100993VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
994{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100996 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
997 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
998};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100999
Dave Barachd7cb1b52016-12-09 09:52:16 -05001000VNET_FEATURE_INIT (ip4_flow_classify, static) =
1001{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001002 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -07001003 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001004 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -07001005};
1006
Dave Barachd7cb1b52016-12-09 09:52:16 -05001007VNET_FEATURE_INIT (ip4_inacl, static) =
1008{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001009 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -04001010 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001011 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -04001012};
1013
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014VNET_FEATURE_INIT (ip4_source_check_1, static) =
1015{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001016 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001017 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001018 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -04001019};
1020
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021VNET_FEATURE_INIT (ip4_source_check_2, static) =
1022{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001023 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001024 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001025 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -04001026};
1027
Dave Barachd7cb1b52016-12-09 09:52:16 -05001028VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
1029{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -04001031 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001032 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -04001033};
1034
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035VNET_FEATURE_INIT (ip4_policer_classify, static) =
1036{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001037 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001038 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001039 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001040};
1041
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042VNET_FEATURE_INIT (ip4_ipsec, static) =
1043{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001044 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001045 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001046 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -04001047};
1048
Dave Barachd7cb1b52016-12-09 09:52:16 -05001049VNET_FEATURE_INIT (ip4_vpath, static) =
1050{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001051 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001052 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -05001053 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1054};
1055
Dave Barachd7cb1b52016-12-09 09:52:16 -05001056VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1057{
John Lo37682e12016-11-30 12:51:39 -05001058 .arc_name = "ip4-unicast",
1059 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001060 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001061};
1062
Dave Barachd7cb1b52016-12-09 09:52:16 -05001063VNET_FEATURE_INIT (ip4_drop, static) =
1064{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001065 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001066 .node_name = "ip4-drop",
Neale Ranns180279b2017-03-16 15:49:09 -04001067 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001068};
1069
Neale Ranns180279b2017-03-16 15:49:09 -04001070VNET_FEATURE_INIT (ip4_lookup, static) =
1071{
1072 .arc_name = "ip4-unicast",
1073 .node_name = "ip4-lookup",
1074 .runs_before = 0, /* not before any other features */
1075};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001076
Dave Barachd6534602016-06-14 18:38:02 -04001077/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001078VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1079{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001080 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001081 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
1082 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1083};
1084
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1086{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001087 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001088 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001089 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001090};
1091
Dave Barachd7cb1b52016-12-09 09:52:16 -05001092VNET_FEATURE_INIT (ip4_mc_drop, static) =
1093{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001094 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001095 .node_name = "ip4-drop",
Neale Ranns180279b2017-03-16 15:49:09 -04001096 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1097};
1098
1099VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1100{
1101 .arc_name = "ip4-multicast",
1102 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001103 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001104};
Dave Barach5331c722016-08-17 11:54:30 -04001105
1106/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001107VNET_FEATURE_ARC_INIT (ip4_output, static) =
1108{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001110 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion8b3191e2016-11-09 19:54:20 +01001111 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1112};
Dave Barach5331c722016-08-17 11:54:30 -04001113
Dave Barachd7cb1b52016-12-09 09:52:16 -05001114VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1115{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001116 .arc_name = "ip4-output",
1117 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001118 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1119};
1120
Dave Barachd7cb1b52016-12-09 09:52:16 -05001121VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1122{
Matus Fabian08a6f012016-11-15 06:08:51 -08001123 .arc_name = "ip4-output",
1124 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001125 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001126};
1127
1128/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001129VNET_FEATURE_INIT (ip4_interface_output, static) =
1130{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001131 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001132 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001134};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001135/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001136
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001138ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001140 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001142 /* Fill in lookup tables with default table (0). */
1143 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001144 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001145
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001146 if (!is_add)
1147 {
1148 ip4_main_t *im4 = &ip4_main;
1149 ip_lookup_main_t *lm4 = &im4->lookup_main;
1150 ip_interface_address_t *ia = 0;
1151 ip4_address_t *address;
1152 vlib_main_t *vm = vlib_get_main ();
1153
1154 /* *INDENT-OFF* */
1155 foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* honor unnumbered */,
1156 ({
1157 address = ip_interface_address_get_address (lm4, ia);
1158 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1159 }));
1160 /* *INDENT-ON* */
1161 }
1162
Damjan Marion8b3191e2016-11-09 19:54:20 +01001163 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1164 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165
Damjan Marion8b3191e2016-11-09 19:54:20 +01001166 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1167 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169 return /* no error */ 0;
1170}
1171
1172VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1173
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174/* Global IP4 main. */
1175ip4_main_t ip4_main;
1176
1177clib_error_t *
1178ip4_lookup_init (vlib_main_t * vm)
1179{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001180 ip4_main_t *im = &ip4_main;
1181 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 uword i;
1183
Damjan Marion8b3191e2016-11-09 19:54:20 +01001184 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1185 return error;
1186
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1188 {
1189 u32 m;
1190
1191 if (i < 32)
1192 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001193 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194 m = ~0;
1195 im->fib_masks[i] = clib_host_to_net_u32 (m);
1196 }
1197
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1199
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001200 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001201 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1202 FIB_SOURCE_DEFAULT_ROUTE);
1203 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1204 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001205
Ed Warnickecb9cada2015-12-08 15:45:58 -07001206 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001207 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208 pn = pg_get_node (ip4_lookup_node.index);
1209 pn->unformat_edit = unformat_pg_ip4_header;
1210 }
1211
1212 {
1213 ethernet_arp_header_t h;
1214
1215 memset (&h, 0, sizeof (h));
1216
1217 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001218 memset (h.ip4_over_ethernet[1].ethernet, 0,
1219 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001220
1221#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1222#define _8(f,v) h.f = v;
1223 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1224 _16 (l3_type, ETHERNET_TYPE_IP4);
1225 _8 (n_l2_address_bytes, 6);
1226 _8 (n_l3_address_bytes, 4);
1227 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1228#undef _16
1229#undef _8
1230
Dave Barachd7cb1b52016-12-09 09:52:16 -05001231 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001232 /* data */ &h,
1233 sizeof (h),
1234 /* alloc chunk size */ 8,
1235 "ip4 arp");
1236 }
1237
Dave Barach203c6322016-06-26 10:29:03 -04001238 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239}
1240
1241VLIB_INIT_FUNCTION (ip4_lookup_init);
1242
Dave Barachd7cb1b52016-12-09 09:52:16 -05001243typedef struct
1244{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001246 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 u32 flow_hash;
1248 u32 fib_index;
1249
1250 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001251 u8 packet_data[64 - 1 * sizeof (u32)];
1252}
1253ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254
Dave Barachd7cb1b52016-12-09 09:52:16 -05001255u8 *
1256format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001257{
1258 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1259 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001260 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001261 uword indent = format_get_indent (s);
1262 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001263 format_white_space, indent,
1264 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001265 return s;
1266}
1267
Dave Barachd7cb1b52016-12-09 09:52:16 -05001268static u8 *
1269format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001270{
1271 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1272 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001273 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001274 uword indent = format_get_indent (s);
1275
John Loac8146c2016-09-27 17:44:02 -04001276 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001277 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001278 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001279 format_white_space, indent,
1280 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001281 return s;
1282}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283
Dave Barachd7cb1b52016-12-09 09:52:16 -05001284static u8 *
1285format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001286{
1287 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1288 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001290 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291
Vengada Govindanf1544482016-09-28 02:45:57 -07001292 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001293 t->fib_index, t->dpo_index, format_ip_adjacency,
1294 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001295 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001296 format_white_space, indent,
1297 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001298 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001299 return s;
1300}
1301
1302/* Common trace function for all ip4-forward next nodes. */
1303void
1304ip4_forward_next_trace (vlib_main_t * vm,
1305 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001306 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001308 u32 *from, n_left;
1309 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001310
1311 n_left = frame->n_vectors;
1312 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001313
Ed Warnickecb9cada2015-12-08 15:45:58 -07001314 while (n_left >= 4)
1315 {
1316 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001317 vlib_buffer_t *b0, *b1;
1318 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001319
1320 /* Prefetch next iteration. */
1321 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1322 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1323
1324 bi0 = from[0];
1325 bi1 = from[1];
1326
1327 b0 = vlib_get_buffer (vm, bi0);
1328 b1 = vlib_get_buffer (vm, bi1);
1329
1330 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1331 {
1332 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001333 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001334 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001335 t0->fib_index =
1336 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1337 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1338 vec_elt (im->fib_index_by_sw_if_index,
1339 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001340
Damjan Marionf1213b82016-03-13 02:22:06 +01001341 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001342 vlib_buffer_get_current (b0),
1343 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001344 }
1345 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1346 {
1347 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001348 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001350 t1->fib_index =
1351 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1352 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1353 vec_elt (im->fib_index_by_sw_if_index,
1354 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1355 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1356 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357 }
1358 from += 2;
1359 n_left -= 2;
1360 }
1361
1362 while (n_left >= 1)
1363 {
1364 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001365 vlib_buffer_t *b0;
1366 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367
1368 bi0 = from[0];
1369
1370 b0 = vlib_get_buffer (vm, bi0);
1371
1372 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1373 {
1374 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001375 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001377 t0->fib_index =
1378 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1379 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1380 vec_elt (im->fib_index_by_sw_if_index,
1381 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1382 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1383 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001384 }
1385 from += 1;
1386 n_left -= 1;
1387 }
1388}
1389
1390static uword
1391ip4_drop_or_punt (vlib_main_t * vm,
1392 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001393 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001395 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001396 uword n_packets = frame->n_vectors;
1397
Dave Barachd7cb1b52016-12-09 09:52:16 -05001398 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399 /* stride */ 1,
1400 n_packets,
1401 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001402 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403
1404 if (node->flags & VLIB_NODE_FLAG_TRACE)
1405 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1406
1407 return n_packets;
1408}
1409
1410static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001411ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1412{
1413 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1414}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001415
1416static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001417ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1418{
1419 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1420}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001421
Neale Ranns32e1c012016-11-22 17:07:28 +00001422/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001423VLIB_REGISTER_NODE (ip4_drop_node, static) =
1424{
flyingeagle239e355522017-05-03 11:29:53 +08001425 .function = ip4_drop,
1426 .name = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00001427 .vector_size = sizeof (u32),
1428 .format_trace = format_ip4_forward_next_trace,
1429 .n_next_nodes = 1,
1430 .next_nodes = {
1431 [0] = "error-drop",
1432 },
1433};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434
Dave Barachd7cb1b52016-12-09 09:52:16 -05001435VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436
Dave Barachd7cb1b52016-12-09 09:52:16 -05001437VLIB_REGISTER_NODE (ip4_punt_node, static) =
1438{
Neale Ranns32e1c012016-11-22 17:07:28 +00001439 .function = ip4_punt,
1440 .name = "ip4-punt",
1441 .vector_size = sizeof (u32),
1442 .format_trace = format_ip4_forward_next_trace,
1443 .n_next_nodes = 1,
1444 .next_nodes = {
1445 [0] = "error-punt",
1446 },
1447};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001448
Dave Barachd7cb1b52016-12-09 09:52:16 -05001449VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Neale Ranns32e1c012016-11-22 17:07:28 +00001450/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02001451
Ed Warnickecb9cada2015-12-08 15:45:58 -07001452/* Compute TCP/UDP/ICMP4 checksum in software. */
1453u16
1454ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1455 ip4_header_t * ip0)
1456{
1457 ip_csum_t sum0;
1458 u32 ip_header_length, payload_length_host_byte_order;
Florin Corasb2215d62017-08-01 16:56:58 -07001459 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001460 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001461 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001462
Ed Warnickecb9cada2015-12-08 15:45:58 -07001463 /* Initialize checksum with ip header. */
1464 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001465 payload_length_host_byte_order =
1466 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1467 sum0 =
1468 clib_host_to_net_u32 (payload_length_host_byte_order +
1469 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001470
1471 if (BITS (uword) == 32)
1472 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001473 sum0 =
1474 ip_csum_with_carry (sum0,
1475 clib_mem_unaligned (&ip0->src_address, u32));
1476 sum0 =
1477 ip_csum_with_carry (sum0,
1478 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001479 }
1480 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001481 sum0 =
1482 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001483
1484 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1485 data_this_buffer = (void *) ip0 + ip_header_length;
Florin Corasb2215d62017-08-01 16:56:58 -07001486 n_ip_bytes_this_buffer = p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1487 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1488 {
1489 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
1490 n_ip_bytes_this_buffer - ip_header_length : 0;
1491 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492 while (1)
1493 {
1494 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1495 n_bytes_left -= n_this_buffer;
1496 if (n_bytes_left == 0)
1497 break;
1498
1499 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1500 p0 = vlib_get_buffer (vm, p0->next_buffer);
1501 data_this_buffer = vlib_buffer_get_current (p0);
1502 n_this_buffer = p0->current_length;
1503 }
1504
Dave Barachd7cb1b52016-12-09 09:52:16 -05001505 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506
1507 return sum16;
1508}
1509
John Lo37682e12016-11-30 12:51:39 -05001510u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001511ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1512{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001513 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1514 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001515 u16 sum16;
1516
1517 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1518 || ip0->protocol == IP_PROTOCOL_UDP);
1519
1520 udp0 = (void *) (ip0 + 1);
1521 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1522 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001523 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1524 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525 return p0->flags;
1526 }
1527
1528 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1529
Damjan Marion213b5aa2017-07-13 21:19:27 +02001530 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1531 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001532
1533 return p0->flags;
1534}
1535
Dave Barach68b0fb02017-02-28 15:15:56 -05001536/* *INDENT-OFF* */
1537VNET_FEATURE_ARC_INIT (ip4_local) =
1538{
1539 .arc_name = "ip4-local",
1540 .start_nodes = VNET_FEATURES ("ip4-local"),
1541};
1542/* *INDENT-ON* */
1543
Florin Coras20a14b92017-08-15 22:47:22 -07001544static inline void
1545ip4_local_validate_l4 (vlib_main_t * vm, vlib_buffer_t * p, ip4_header_t * ip,
1546 u8 is_udp, u8 * error, u8 * good_tcp_udp)
1547{
1548 u32 flags0;
1549 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1550 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1551 if (is_udp)
1552 {
1553 udp_header_t *udp;
1554 u32 ip_len, udp_len;
1555 i32 len_diff;
1556 udp = ip4_next_header (ip);
1557 /* Verify UDP length. */
1558 ip_len = clib_net_to_host_u16 (ip->length);
1559 udp_len = clib_net_to_host_u16 (udp->length);
1560
1561 len_diff = ip_len - udp_len;
1562 *good_tcp_udp &= len_diff >= 0;
1563 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1564 }
1565}
1566
1567#define ip4_local_do_l4_check(is_tcp_udp, flags) \
1568 (is_tcp_udp && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED))
1569
Dave Barach68b0fb02017-02-28 15:15:56 -05001570static inline uword
1571ip4_local_inline (vlib_main_t * vm,
1572 vlib_node_runtime_t * node,
1573 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001574{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001575 ip4_main_t *im = &ip4_main;
1576 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001577 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001578 u32 *from, *to_next, n_left_from, n_left_to_next;
1579 vlib_node_runtime_t *error_node =
1580 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001581 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001582
1583 from = vlib_frame_vector_args (frame);
1584 n_left_from = frame->n_vectors;
1585 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001586
Ed Warnickecb9cada2015-12-08 15:45:58 -07001587 if (node->flags & VLIB_NODE_FLAG_TRACE)
1588 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1589
1590 while (n_left_from > 0)
1591 {
1592 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1593
1594 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001595 {
1596 vlib_buffer_t *p0, *p1;
1597 ip4_header_t *ip0, *ip1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001598 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1599 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1600 const dpo_id_t *dpo0, *dpo1;
1601 const load_balance_t *lb0, *lb1;
Florin Coras20a14b92017-08-15 22:47:22 -07001602 u32 pi0, next0, fib_index0, lbi0;
1603 u32 pi1, next1, fib_index1, lbi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001604 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1605 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001606 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001607
Dave Barachd7cb1b52016-12-09 09:52:16 -05001608 pi0 = to_next[0] = from[0];
1609 pi1 = to_next[1] = from[1];
1610 from += 2;
1611 n_left_from -= 2;
1612 to_next += 2;
1613 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001614
Dave Barach68b0fb02017-02-28 15:15:56 -05001615 next0 = next1 = IP_LOCAL_NEXT_DROP;
Florin Coras20a14b92017-08-15 22:47:22 -07001616 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
Dave Barach68b0fb02017-02-28 15:15:56 -05001617
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618 p0 = vlib_get_buffer (vm, pi0);
1619 p1 = vlib_get_buffer (vm, pi1);
1620
1621 ip0 = vlib_buffer_get_current (p0);
1622 ip1 = vlib_buffer_get_current (p1);
1623
Damjan Marion072401e2017-07-13 18:53:27 +02001624 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1625 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001626
Dave Barach68b0fb02017-02-28 15:15:56 -05001627 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1628 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1629
Florin Coras20a14b92017-08-15 22:47:22 -07001630 /* Treat IP frag packets as "experimental" protocol for now
1631 until support of IP frag reassembly is implemented */
1632 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1633 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
1634
1635 if (head_of_feature_arc == 0)
1636 goto skip_checks;
1637
1638 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1639 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1640 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1641 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1642
1643 good_tcp_udp0 =
1644 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1645 good_tcp_udp1 =
1646 (p1->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1647
1648 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)
1649 || ip4_local_do_l4_check (is_tcp_udp1,
1650 p1->flags)))
1651 {
1652 if (is_tcp_udp0)
1653 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1654 &good_tcp_udp0);
1655 if (is_tcp_udp1)
1656 ip4_local_validate_l4 (vm, p1, ip1, is_udp1, &error1,
1657 &good_tcp_udp1);
1658 }
1659
1660 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1661 error0 = (is_tcp_udp0 && !good_tcp_udp0
1662 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1663 error1 = (is_tcp_udp1 && !good_tcp_udp1
1664 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Dave Barach68b0fb02017-02-28 15:15:56 -05001665
1666 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001667 fib_index0 =
1668 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1669 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001670
Dave Barach68b0fb02017-02-28 15:15:56 -05001671 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001672 fib_index1 =
1673 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1674 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001675
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001676 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1677 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001678
Neale Ranns04a75e32017-03-23 06:46:01 -07001679 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1680 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
Florin Coras20a14b92017-08-15 22:47:22 -07001681 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1682 2);
1683 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1684 2);
1685 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1686 3);
1687 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1688 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001689
Dave Barachd7cb1b52016-12-09 09:52:16 -05001690 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1691 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1692 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001693
Dave Barachd7cb1b52016-12-09 09:52:16 -05001694 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1695 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1696 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001697
Dave Barachd7cb1b52016-12-09 09:52:16 -05001698 lb0 = load_balance_get (lbi0);
1699 lb1 = load_balance_get (lbi1);
1700 dpo0 = load_balance_get_bucket_i (lb0, 0);
1701 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001702
Dave Barach75fc8542016-10-11 16:16:02 -04001703 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001704 * Must have a route to source otherwise we drop the packet.
1705 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001706 *
1707 * The checks are:
1708 * - the source is a recieve => it's from us => bogus, do this
1709 * first since it sets a different error code.
1710 * - uRPF check for any route to source - accept if passes.
1711 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001712 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001713 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001714 dpo0->dpoi_type == DPO_RECEIVE) ?
1715 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1716 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1717 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001718 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001719 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001720 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001721 dpo1->dpoi_type == DPO_RECEIVE) ?
1722 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1723 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1724 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001725 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001726 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001727
Florin Corasa0b34a72017-03-07 01:20:52 -08001728 skip_checks:
1729
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730 next0 = lm->local_next_by_ip_protocol[proto0];
1731 next1 = lm->local_next_by_ip_protocol[proto1];
1732
Dave Barachd7cb1b52016-12-09 09:52:16 -05001733 next0 =
1734 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1735 next1 =
1736 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001737
1738 p0->error = error0 ? error_node->errors[error0] : 0;
1739 p1->error = error1 ? error_node->errors[error1] : 0;
1740
Dave Barach68b0fb02017-02-28 15:15:56 -05001741 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001743 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1744 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1745 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1746 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001747 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001748
1749 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1750 n_left_to_next, pi0, pi1,
1751 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001752 }
1753
1754 while (n_left_from > 0 && n_left_to_next > 0)
1755 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001756 vlib_buffer_t *p0;
1757 ip4_header_t *ip0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001758 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 ip4_fib_mtrie_leaf_t leaf0;
Florin Coras20a14b92017-08-15 22:47:22 -07001760 u32 pi0, next0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001762 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001763 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001764 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001765
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766 pi0 = to_next[0] = from[0];
1767 from += 1;
1768 n_left_from -= 1;
1769 to_next += 1;
1770 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001771
Dave Barach68b0fb02017-02-28 15:15:56 -05001772 next0 = IP_LOCAL_NEXT_DROP;
Florin Coras20a14b92017-08-15 22:47:22 -07001773 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
Dave Barach68b0fb02017-02-28 15:15:56 -05001774
Ed Warnickecb9cada2015-12-08 15:45:58 -07001775 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001776 ip0 = vlib_buffer_get_current (p0);
Damjan Marion072401e2017-07-13 18:53:27 +02001777 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Dave Barach68b0fb02017-02-28 15:15:56 -05001778 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1779
John Lo3419d0b2016-06-02 09:28:37 -04001780 /* Treat IP frag packets as "experimental" protocol for now
1781 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001782 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001783
1784 if (head_of_feature_arc == 0)
Florin Coras20a14b92017-08-15 22:47:22 -07001785 goto skip_check;
Dave Barach68b0fb02017-02-28 15:15:56 -05001786
Ed Warnickecb9cada2015-12-08 15:45:58 -07001787 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1788 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
Florin Coras20a14b92017-08-15 22:47:22 -07001789 good_tcp_udp0 =
1790 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001791
Florin Coras20a14b92017-08-15 22:47:22 -07001792 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001793 {
Florin Coras20a14b92017-08-15 22:47:22 -07001794 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1795 &good_tcp_udp0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796 }
1797
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 error0 = (is_tcp_udp0 && !good_tcp_udp0
1800 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801
Florin Coras20a14b92017-08-15 22:47:22 -07001802 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1803 fib_index0 =
1804 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1805 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1806 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1807 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1808 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1809 2);
1810 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1811 3);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001812 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001813 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras20a14b92017-08-15 22:47:22 -07001814 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001815
Dave Barachd7cb1b52016-12-09 09:52:16 -05001816 lb0 = load_balance_get (lbi0);
1817 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818
Neale Ranns3ee44042016-10-03 13:05:48 +01001819 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001820 dpo0->dpoi_type == DPO_RECEIVE) ?
1821 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1822 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1823 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001824 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001825 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001826
Dave Barach68b0fb02017-02-28 15:15:56 -05001827 skip_check:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001828 next0 = lm->local_next_by_ip_protocol[proto0];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001829 next0 =
1830 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001831
Dave Barachd7cb1b52016-12-09 09:52:16 -05001832 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833
Dave Barach68b0fb02017-02-28 15:15:56 -05001834 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001835 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001836 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1837 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001838 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001839
1840 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1841 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1844 }
1845
1846 return frame->n_vectors;
1847}
1848
Dave Barach68b0fb02017-02-28 15:15:56 -05001849static uword
1850ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1851{
1852 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1853}
1854
1855/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001856VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857{
Dave Barach68b0fb02017-02-28 15:15:56 -05001858 .function = ip4_local,
1859 .name = "ip4-local",
1860 .vector_size = sizeof (u32),
1861 .format_trace = format_ip4_forward_next_trace,
1862 .n_next_nodes = IP_LOCAL_N_NEXT,
1863 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001864 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001865 [IP_LOCAL_NEXT_DROP] = "error-drop",
1866 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1867 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001868 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1869 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001870};
1871/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001872
1873VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1874
Dave Barach68b0fb02017-02-28 15:15:56 -05001875static uword
1876ip4_local_end_of_arc (vlib_main_t * vm,
1877 vlib_node_runtime_t * node, vlib_frame_t * frame)
1878{
1879 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1880}
1881
1882/* *INDENT-OFF* */
1883VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1884 .function = ip4_local_end_of_arc,
1885 .name = "ip4-local-end-of-arc",
1886 .vector_size = sizeof (u32),
1887
1888 .format_trace = format_ip4_forward_next_trace,
1889 .sibling_of = "ip4-local",
1890};
1891
1892VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1893
1894VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1895 .arc_name = "ip4-local",
1896 .node_name = "ip4-local-end-of-arc",
1897 .runs_before = 0, /* not before any other features */
1898};
1899/* *INDENT-ON* */
1900
Dave Barachd7cb1b52016-12-09 09:52:16 -05001901void
1902ip4_register_protocol (u32 protocol, u32 node_index)
1903{
1904 vlib_main_t *vm = vlib_get_main ();
1905 ip4_main_t *im = &ip4_main;
1906 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907
1908 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001909 lm->local_next_by_ip_protocol[protocol] =
1910 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001911}
1912
1913static clib_error_t *
1914show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001915 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001916{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917 ip4_main_t *im = &ip4_main;
1918 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001919 int i;
1920
1921 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001923 {
1924 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001925 {
1926 u32 node_index = vlib_get_node (vm,
1927 ip4_local_node.index)->
1928 next_nodes[lm->local_next_by_ip_protocol[i]];
1929 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1930 node_index);
1931 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001932 }
1933 return 0;
1934}
1935
1936
1937
Billy McFall0683c9c2016-10-13 08:27:31 -04001938/*?
1939 * Display the set of protocols handled by the local IPv4 stack.
1940 *
1941 * @cliexpar
1942 * Example of how to display local protocol table:
1943 * @cliexstart{show ip local}
1944 * Protocols handled by ip4_local
1945 * 1
1946 * 17
1947 * 47
1948 * @cliexend
1949?*/
1950/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001951VLIB_CLI_COMMAND (show_ip_local, static) =
1952{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001953 .path = "show ip local",
1954 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001955 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956};
Billy McFall0683c9c2016-10-13 08:27:31 -04001957/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001959always_inline uword
1960ip4_arp_inline (vlib_main_t * vm,
1961 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001962 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001964 vnet_main_t *vnm = vnet_get_main ();
1965 ip4_main_t *im = &ip4_main;
1966 ip_lookup_main_t *lm = &im->lookup_main;
1967 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 uword n_left_from, n_left_to_next_drop, next_index;
1969 static f64 time_last_seed_change = -1e100;
1970 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001971 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001972 f64 time_now;
1973
1974 if (node->flags & VLIB_NODE_FLAG_TRACE)
1975 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1976
1977 time_now = vlib_time_now (vm);
1978 if (time_now - time_last_seed_change > 1e-3)
1979 {
1980 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1982 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1984 hash_seeds[i] = r[i];
1985
1986 /* Mark all hash keys as been no-seen before. */
1987 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1988 hash_bitmap[i] = 0;
1989
1990 time_last_seed_change = time_now;
1991 }
1992
1993 from = vlib_frame_vector_args (frame);
1994 n_left_from = frame->n_vectors;
1995 next_index = node->cached_next_index;
1996 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001997 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998
1999 while (n_left_from > 0)
2000 {
2001 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2002 to_next_drop, n_left_to_next_drop);
2003
2004 while (n_left_from > 0 && n_left_to_next_drop > 0)
2005 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002006 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002007 ip_adjacency_t *adj0;
2008 vlib_buffer_t *p0;
2009 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002010 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011
2012 pi0 = from[0];
2013
2014 p0 = vlib_get_buffer (vm, pi0);
2015
2016 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002017 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 ip0 = vlib_buffer_get_current (p0);
2019
Ed Warnickecb9cada2015-12-08 15:45:58 -07002020 a0 = hash_seeds[0];
2021 b0 = hash_seeds[1];
2022 c0 = hash_seeds[2];
2023
2024 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2025 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2026
Dave Barachd7cb1b52016-12-09 09:52:16 -05002027 if (is_glean)
2028 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002029 /*
2030 * this is the Glean case, so we are ARPing for the
2031 * packet's destination
2032 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002033 a0 ^= ip0->dst_address.data_u32;
2034 }
2035 else
2036 {
2037 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2038 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002039 b0 ^= sw_if_index0;
2040
Florin Coras2d3dbc42017-09-08 16:22:38 -04002041 hash_v3_mix32 (a0, b0, c0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002042 hash_v3_finalize32 (a0, b0, c0);
2043
2044 c0 &= BITS (hash_bitmap) - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002045 m0 = (uword) 1 << (c0 % BITS (uword));
Florin Coras2d3dbc42017-09-08 16:22:38 -04002046 c0 = c0 / BITS (uword);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047
2048 bm0 = hash_bitmap[c0];
2049 drop0 = (bm0 & m0) != 0;
2050
2051 /* Mark it as seen. */
2052 hash_bitmap[c0] = bm0 | m0;
2053
2054 from += 1;
2055 n_left_from -= 1;
2056 to_next_drop[0] = pi0;
2057 to_next_drop += 1;
2058 n_left_to_next_drop -= 1;
2059
Dave Barachd7cb1b52016-12-09 09:52:16 -05002060 p0->error =
2061 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2062 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002063
Neale Rannsb80c5362016-10-08 13:03:40 +01002064 /*
2065 * the adj has been updated to a rewrite but the node the DPO that got
2066 * us here hasn't - yet. no big deal. we'll drop while we wait.
2067 */
2068 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2069 continue;
2070
Ed Warnickecb9cada2015-12-08 15:45:58 -07002071 if (drop0)
2072 continue;
2073
Dave Barachd7cb1b52016-12-09 09:52:16 -05002074 /*
2075 * Can happen if the control-plane is programming tables
2076 * with traffic flowing; at least that's today's lame excuse.
2077 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002078 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2079 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002080 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002081 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002082 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002083 else
2084 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002085 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002086 u32 bi0 = 0;
2087 vlib_buffer_t *b0;
2088 ethernet_arp_header_t *h0;
2089 vnet_hw_interface_t *hw_if0;
2090
2091 h0 =
2092 vlib_packet_template_get_packet (vm,
2093 &im->ip4_arp_request_packet_template,
2094 &bi0);
2095
2096 /* Add rewrite/encap string for ARP packet. */
2097 vnet_rewrite_one_header (adj0[0], h0,
2098 sizeof (ethernet_header_t));
2099
2100 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2101
2102 /* Src ethernet address in ARP header. */
2103 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2104 hw_if0->hw_address,
2105 sizeof (h0->ip4_over_ethernet[0].ethernet));
2106
2107 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002108 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002109 /* The interface's source address is stashed in the Glean Adj */
2110 h0->ip4_over_ethernet[0].ip4 =
2111 adj0->sub_type.glean.receive_addr.ip4;
2112
2113 /* Copy in destination address we are requesting. This is the
2114 * glean case, so it's the packet's destination.*/
2115 h0->ip4_over_ethernet[1].ip4.data_u32 =
2116 ip0->dst_address.data_u32;
2117 }
2118 else
2119 {
2120 /* Src IP address in ARP header. */
2121 if (ip4_src_address_for_packet (lm, sw_if_index0,
2122 &h0->
2123 ip4_over_ethernet[0].ip4))
2124 {
2125 /* No source address available */
2126 p0->error =
2127 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2128 vlib_buffer_free (vm, &bi0, 1);
2129 continue;
2130 }
2131
2132 /* Copy in destination address we are requesting from the
2133 incomplete adj */
2134 h0->ip4_over_ethernet[1].ip4.data_u32 =
2135 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002136 }
2137
Dave Barachd7cb1b52016-12-09 09:52:16 -05002138 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2139 b0 = vlib_get_buffer (vm, bi0);
Florin Coras2f9b0c02017-09-11 20:54:15 -04002140 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002141 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2142
2143 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2144
2145 vlib_set_next_frame_buffer (vm, node,
2146 adj0->rewrite_header.next_index,
2147 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002148 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149 }
2150
2151 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2152 }
2153
2154 return frame->n_vectors;
2155}
2156
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002157static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002158ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002159{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002160 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002161}
2162
2163static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002164ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002165{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002166 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002167}
2168
Dave Barachd7cb1b52016-12-09 09:52:16 -05002169static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2171 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2172 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2173 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2174 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002175 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002176};
2177
Dave Barachd7cb1b52016-12-09 09:52:16 -05002178VLIB_REGISTER_NODE (ip4_arp_node) =
2179{
2180 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2181 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2182 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2183 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2184 {
2185 [IP4_ARP_NEXT_DROP] = "error-drop",}
2186,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002187
Dave Barachd7cb1b52016-12-09 09:52:16 -05002188VLIB_REGISTER_NODE (ip4_glean_node) =
2189{
2190 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2191 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2192 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2193 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2194 {
2195 [IP4_ARP_NEXT_DROP] = "error-drop",}
2196,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002197
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198#define foreach_notrace_ip4_arp_error \
2199_(DROP) \
2200_(REQUEST_SENT) \
2201_(REPLICATE_DROP) \
2202_(REPLICATE_FAIL)
2203
Dave Barachd7cb1b52016-12-09 09:52:16 -05002204clib_error_t *
2205arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002206{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002207 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002208
2209 /* don't trace ARP request packets */
2210#define _(a) \
2211 vnet_pcap_drop_trace_filter_add_del \
2212 (rt->errors[IP4_ARP_ERROR_##a], \
2213 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002214 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002215#undef _
2216 return 0;
2217}
2218
Dave Barachd7cb1b52016-12-09 09:52:16 -05002219VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002220
2221
2222/* Send an ARP request to see if given destination is reachable on given interface. */
2223clib_error_t *
2224ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2225{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002226 vnet_main_t *vnm = vnet_get_main ();
2227 ip4_main_t *im = &ip4_main;
2228 ethernet_arp_header_t *h;
2229 ip4_address_t *src;
2230 ip_interface_address_t *ia;
2231 ip_adjacency_t *adj;
2232 vnet_hw_interface_t *hi;
2233 vnet_sw_interface_t *si;
2234 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002235 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236 u32 bi = 0;
2237
2238 si = vnet_get_sw_interface (vnm, sw_if_index);
2239
2240 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2241 {
2242 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002243 format_ip4_address, dst,
2244 format_vnet_sw_if_index_name, vnm,
2245 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002246 }
2247
Dave Barachd7cb1b52016-12-09 09:52:16 -05002248 src =
2249 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2250 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002251 {
2252 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002253 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002254 (0,
2255 "no matching interface address for destination %U (interface %U)",
2256 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2257 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002258 }
2259
Neale Ranns7a272742017-05-30 02:08:14 -07002260 h = vlib_packet_template_get_packet (vm,
2261 &im->ip4_arp_request_packet_template,
2262 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263
2264 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002265 if (PREDICT_FALSE (!hi->hw_address))
2266 {
2267 return clib_error_return (0, "%U: interface %U do not support ip probe",
2268 format_ip4_address, dst,
2269 format_vnet_sw_if_index_name, vnm,
2270 sw_if_index);
2271 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272
Dave Barachd7cb1b52016-12-09 09:52:16 -05002273 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2274 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275
2276 h->ip4_over_ethernet[0].ip4 = src[0];
2277 h->ip4_over_ethernet[1].ip4 = dst[0];
2278
2279 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002280 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2281 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282
Dave Barach59b25652017-09-10 15:04:27 -04002283 ip46_address_t nh = {
2284 .ip4 = *dst,
2285 };
2286
2287 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2288 VNET_LINK_IP4, &nh, sw_if_index);
2289 adj = adj_get (ai);
2290
2291 /* Peer has been previously resolved, retrieve glean adj instead */
2292 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2293 {
2294 adj_unlock (ai);
2295 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4, sw_if_index, &nh);
2296 adj = adj_get (ai);
2297 }
2298
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 /* Add encapsulation string for software interface (e.g. ethernet header). */
2300 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2301 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2302
2303 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002304 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2305 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 to_next[0] = bi;
2307 f->n_vectors = 1;
2308 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2309 }
2310
Neale Ranns7a272742017-05-30 02:08:14 -07002311 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002312 return /* no error */ 0;
2313}
2314
Dave Barachd7cb1b52016-12-09 09:52:16 -05002315typedef enum
2316{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002318 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002319} ip4_rewrite_next_t;
2320
2321always_inline uword
2322ip4_rewrite_inline (vlib_main_t * vm,
2323 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002324 vlib_frame_t * frame,
2325 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002326{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002327 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2328 u32 *from = vlib_frame_vector_args (frame);
2329 u32 n_left_from, n_left_to_next, *to_next, next_index;
2330 vlib_node_runtime_t *error_node =
2331 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332
2333 n_left_from = frame->n_vectors;
2334 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002335 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002336
Ed Warnickecb9cada2015-12-08 15:45:58 -07002337 while (n_left_from > 0)
2338 {
2339 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2340
2341 while (n_left_from >= 4 && n_left_to_next >= 2)
2342 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002343 ip_adjacency_t *adj0, *adj1;
2344 vlib_buffer_t *p0, *p1;
2345 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2347 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002348 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002349
Ed Warnickecb9cada2015-12-08 15:45:58 -07002350 /* Prefetch next iteration. */
2351 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002352 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002353
2354 p2 = vlib_get_buffer (vm, from[2]);
2355 p3 = vlib_get_buffer (vm, from[3]);
2356
2357 vlib_prefetch_buffer_header (p2, STORE);
2358 vlib_prefetch_buffer_header (p3, STORE);
2359
2360 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2361 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2362 }
2363
2364 pi0 = to_next[0] = from[0];
2365 pi1 = to_next[1] = from[1];
2366
2367 from += 2;
2368 n_left_from -= 2;
2369 to_next += 2;
2370 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002371
Ed Warnickecb9cada2015-12-08 15:45:58 -07002372 p0 = vlib_get_buffer (vm, pi0);
2373 p1 = vlib_get_buffer (vm, pi1);
2374
Neale Rannsf06aea52016-11-29 06:51:37 -08002375 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2376 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377
Neale Ranns1bd01092017-03-15 15:41:17 -04002378 /*
2379 * pre-fetch the per-adjacency counters
2380 */
2381 if (do_counters)
2382 {
2383 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002384 thread_index, adj_index0);
Neale Ranns1bd01092017-03-15 15:41:17 -04002385 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002386 thread_index, adj_index1);
Neale Ranns1bd01092017-03-15 15:41:17 -04002387 }
2388
Ed Warnickecb9cada2015-12-08 15:45:58 -07002389 ip0 = vlib_buffer_get_current (p0);
2390 ip1 = vlib_buffer_get_current (p1);
2391
2392 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002393 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002394
2395 /* Decrement TTL & update checksum.
2396 Works either endian, so no need for byte swap. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002397 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002399 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002400
2401 /* Input node should have reject packets with ttl 0. */
2402 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403
2404 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406
2407 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002408 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002410
Dave Barachd7cb1b52016-12-09 09:52:16 -05002411 /*
2412 * If the ttl drops below 1 when forwarding, generate
2413 * an ICMP response.
2414 */
2415 if (PREDICT_FALSE (ttl0 <= 0))
2416 {
2417 error0 = IP4_ERROR_TIME_EXPIRED;
2418 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2419 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2420 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2421 0);
2422 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2423 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002424
2425 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002426 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002427 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Neale Rannsf06aea52016-11-29 06:51:37 -08002428 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002429 else
2430 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002431 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002432 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002433 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002434 {
2435 i32 ttl1 = ip1->ttl;
2436
2437 /* Input node should have reject packets with ttl 0. */
2438 ASSERT (ip1->ttl > 0);
2439
2440 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2441 checksum1 += checksum1 >= 0xffff;
2442
2443 ip1->checksum = checksum1;
2444 ttl1 -= 1;
2445 ip1->ttl = ttl1;
2446
Dave Barachd7cb1b52016-12-09 09:52:16 -05002447 /*
2448 * If the ttl drops below 1 when forwarding, generate
2449 * an ICMP response.
2450 */
2451 if (PREDICT_FALSE (ttl1 <= 0))
2452 {
2453 error1 = IP4_ERROR_TIME_EXPIRED;
2454 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2455 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2456 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2457 0);
2458 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2459 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002460
2461 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002462 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002463 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002464 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002465 else
2466 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002467 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002468 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469
2470 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002471 adj0 = adj_get (adj_index0);
2472 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002473
Dave Barachd7cb1b52016-12-09 09:52:16 -05002474 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 rw_len0 = adj0[0].rewrite_header.data_bytes;
2476 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002477 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2478 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002479
Dave Barachd7cb1b52016-12-09 09:52:16 -05002480 /* Check MTU of outgoing interface. */
2481 error0 =
2482 (vlib_buffer_length_in_chain (vm, p0) >
2483 adj0[0].
2484 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2485 error0);
2486 error1 =
2487 (vlib_buffer_length_in_chain (vm, p1) >
2488 adj1[0].
2489 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2490 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002491
Dave Barachd7cb1b52016-12-09 09:52:16 -05002492 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2493 * to see the IP headerr */
2494 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2495 {
Damjan Marion892e0762016-12-09 18:52:05 +01002496 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002497 p0->current_data -= rw_len0;
2498 p0->current_length += rw_len0;
2499 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2500 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002501
Neale Rannsb069a692017-03-15 12:34:25 -04002502 if (PREDICT_FALSE
2503 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2504 vnet_feature_arc_start (lm->output_feature_arc_index,
2505 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002506 }
2507 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2508 {
Damjan Marion892e0762016-12-09 18:52:05 +01002509 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002510 p1->current_data -= rw_len1;
2511 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002512
Dave Barachd7cb1b52016-12-09 09:52:16 -05002513 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2514 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002515
Neale Rannsb069a692017-03-15 12:34:25 -04002516 if (PREDICT_FALSE
2517 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2518 vnet_feature_arc_start (lm->output_feature_arc_index,
2519 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002520 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002521
2522 /* Guess we are only writing on simple Ethernet header. */
2523 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002524 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002525
Neale Ranns044183f2017-01-24 01:34:25 -08002526 /*
2527 * Bump the per-adjacency counters
2528 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002529 if (do_counters)
2530 {
2531 vlib_increment_combined_counter
2532 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002533 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002534 adj_index0, 1,
2535 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002536
Neale Ranns9c6a6132017-02-21 05:33:14 -08002537 vlib_increment_combined_counter
2538 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002539 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002540 adj_index1, 1,
2541 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2542 }
Neale Ranns044183f2017-01-24 01:34:25 -08002543
Neale Ranns5e575b12016-10-03 09:40:25 +01002544 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002545 {
2546 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2547 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2548 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002549 if (is_mcast)
2550 {
2551 /*
2552 * copy bytes from the IP address into the MAC rewrite
2553 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002554 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2555 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002556 }
Dave Barach75fc8542016-10-11 16:16:02 -04002557
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2559 to_next, n_left_to_next,
2560 pi0, pi1, next0, next1);
2561 }
2562
2563 while (n_left_from > 0 && n_left_to_next > 0)
2564 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002565 ip_adjacency_t *adj0;
2566 vlib_buffer_t *p0;
2567 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002568 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002569 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002570
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571 pi0 = to_next[0] = from[0];
2572
2573 p0 = vlib_get_buffer (vm, pi0);
2574
Neale Rannsf06aea52016-11-29 06:51:37 -08002575 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002576
Neale Ranns107e7d42017-04-11 09:55:19 -07002577 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002578
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579 ip0 = vlib_buffer_get_current (p0);
2580
2581 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002582 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002583
2584 /* Decrement TTL & update checksum. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002585 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586 {
2587 i32 ttl0 = ip0->ttl;
2588
2589 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2590
2591 checksum0 += checksum0 >= 0xffff;
2592
2593 ip0->checksum = checksum0;
2594
2595 ASSERT (ip0->ttl > 0);
2596
2597 ttl0 -= 1;
2598
2599 ip0->ttl = ttl0;
2600
Dave Barach2c0a4f42017-06-29 09:30:15 -04002601 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002602 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002603
Dave Barachd7cb1b52016-12-09 09:52:16 -05002604 if (PREDICT_FALSE (ttl0 <= 0))
2605 {
2606 /*
2607 * If the ttl drops below 1 when forwarding, generate
2608 * an ICMP response.
2609 */
2610 error0 = IP4_ERROR_TIME_EXPIRED;
2611 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2612 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2613 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2614 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2615 0);
2616 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002617 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002618 else
2619 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002620 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002621 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002622
Neale Ranns1bd01092017-03-15 15:41:17 -04002623 if (do_counters)
2624 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002625 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002626
Ed Warnickecb9cada2015-12-08 15:45:58 -07002627 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002628 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002629 if (is_mcast)
2630 {
2631 /*
2632 * copy bytes from the IP address into the MAC rewrite
2633 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002634 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002635 }
Dave Barach75fc8542016-10-11 16:16:02 -04002636
Dave Barachd7cb1b52016-12-09 09:52:16 -05002637 /* Update packet buffer attributes/set output interface. */
2638 rw_len0 = adj0[0].rewrite_header.data_bytes;
2639 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002640
Neale Ranns1bd01092017-03-15 15:41:17 -04002641 if (do_counters)
2642 vlib_increment_combined_counter
2643 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002644 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002645 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002646
Dave Barachd7cb1b52016-12-09 09:52:16 -05002647 /* Check MTU of outgoing interface. */
2648 error0 = (vlib_buffer_length_in_chain (vm, p0)
2649 > adj0[0].rewrite_header.max_l3_packet_bytes
2650 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002651
Ed Warnickecb9cada2015-12-08 15:45:58 -07002652 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002653
Dave Barachd7cb1b52016-12-09 09:52:16 -05002654 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2655 * to see the IP headerr */
2656 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2657 {
2658 p0->current_data -= rw_len0;
2659 p0->current_length += rw_len0;
2660 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002661
Dave Barachd7cb1b52016-12-09 09:52:16 -05002662 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2663 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002664
Neale Ranns5e575b12016-10-03 09:40:25 +01002665 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002666 {
2667 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002668 }
2669
Neale Rannsb069a692017-03-15 12:34:25 -04002670 if (PREDICT_FALSE
2671 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2672 vnet_feature_arc_start (lm->output_feature_arc_index,
2673 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002674
Dave Barachd7cb1b52016-12-09 09:52:16 -05002675 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002676
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677 from += 1;
2678 n_left_from -= 1;
2679 to_next += 1;
2680 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002681
Ed Warnickecb9cada2015-12-08 15:45:58 -07002682 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2683 to_next, n_left_to_next,
2684 pi0, next0);
2685 }
Dave Barach75fc8542016-10-11 16:16:02 -04002686
Ed Warnickecb9cada2015-12-08 15:45:58 -07002687 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2688 }
2689
2690 /* Need to do trace after rewrites to pick up new packet data. */
2691 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002692 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002693
2694 return frame->n_vectors;
2695}
2696
Dave Barach132d51d2016-07-07 10:10:17 -04002697
Neale Rannsf06aea52016-11-29 06:51:37 -08002698/** @brief IPv4 rewrite node.
2699 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002700
2701 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2702 header checksum, fetch the ip adjacency, check the outbound mtu,
2703 apply the adjacency rewrite, and send pkts to the adjacency
2704 rewrite header's rewrite_next_index.
2705
2706 @param vm vlib_main_t corresponding to the current thread
2707 @param node vlib_node_runtime_t
2708 @param frame vlib_frame_t whose contents should be dispatched
2709
2710 @par Graph mechanics: buffer metadata, next index usage
2711
2712 @em Uses:
2713 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2714 - the rewrite adjacency index
2715 - <code>adj->lookup_next_index</code>
2716 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002717 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002718 - <code>adj->rewrite_header</code>
2719 - Rewrite string length, rewrite string, next_index
2720
2721 @em Sets:
2722 - <code>b->current_data, b->current_length</code>
2723 - Updated net of applying the rewrite string
2724
2725 <em>Next Indices:</em>
2726 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002727 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002728*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002730ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002731 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002733 if (adj_are_counters_enabled ())
2734 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2735 else
2736 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737}
2738
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002739static uword
2740ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002741 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002742{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002743 if (adj_are_counters_enabled ())
2744 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2745 else
2746 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002747}
2748
Neale Ranns32e1c012016-11-22 17:07:28 +00002749static uword
2750ip4_rewrite_mcast (vlib_main_t * vm,
2751 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002752{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002753 if (adj_are_counters_enabled ())
2754 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2755 else
2756 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002757}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002758
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002759static uword
2760ip4_mcast_midchain (vlib_main_t * vm,
2761 vlib_node_runtime_t * node, vlib_frame_t * frame)
2762{
2763 if (adj_are_counters_enabled ())
2764 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2765 else
2766 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2767}
2768
Neale Ranns32e1c012016-11-22 17:07:28 +00002769/* *INDENT-OFF* */
2770VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2771 .function = ip4_rewrite,
2772 .name = "ip4-rewrite",
2773 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002774
Neale Ranns32e1c012016-11-22 17:07:28 +00002775 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002776
Neale Ranns32e1c012016-11-22 17:07:28 +00002777 .n_next_nodes = 2,
2778 .next_nodes = {
2779 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2780 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2781 },
2782};
2783VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2784
2785VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2786 .function = ip4_rewrite_mcast,
2787 .name = "ip4-rewrite-mcast",
2788 .vector_size = sizeof (u32),
2789
2790 .format_trace = format_ip4_rewrite_trace,
2791 .sibling_of = "ip4-rewrite",
2792};
2793VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2794
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002795VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2796 .function = ip4_mcast_midchain,
2797 .name = "ip4-mcast-midchain",
2798 .vector_size = sizeof (u32),
2799
2800 .format_trace = format_ip4_rewrite_trace,
2801 .sibling_of = "ip4-rewrite",
2802};
2803VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2804
Neale Ranns32e1c012016-11-22 17:07:28 +00002805VLIB_REGISTER_NODE (ip4_midchain_node) = {
2806 .function = ip4_midchain,
2807 .name = "ip4-midchain",
2808 .vector_size = sizeof (u32),
2809 .format_trace = format_ip4_forward_next_trace,
2810 .sibling_of = "ip4-rewrite",
2811};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002812VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002813/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002814
Dave Barachd7cb1b52016-12-09 09:52:16 -05002815int
2816ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2817{
2818 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002819 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002820 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002821
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002822 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002823
Neale Ranns04a75e32017-03-23 06:46:01 -07002824 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002825 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2826 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002827
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002828 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002829
Dave Barachd7cb1b52016-12-09 09:52:16 -05002830 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831}
Dave Barach75fc8542016-10-11 16:16:02 -04002832
Ed Warnickecb9cada2015-12-08 15:45:58 -07002833static clib_error_t *
2834test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002835 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002836{
Billy McFall309fe062016-10-14 07:37:33 -04002837 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838 u32 table_id = 0;
2839 f64 count = 1;
2840 u32 n;
2841 int i;
2842 ip4_address_t ip4_base_address;
2843 u64 errors = 0;
2844
Dave Barachd7cb1b52016-12-09 09:52:16 -05002845 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2846 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002847 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002848 {
2849 /* Make sure the entry exists. */
2850 fib = ip4_fib_get (table_id);
2851 if ((fib) && (fib->index != table_id))
2852 return clib_error_return (0, "<fib-index> %d does not exist",
2853 table_id);
2854 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002855 else if (unformat (input, "count %f", &count))
2856 ;
2857
2858 else if (unformat (input, "%U",
2859 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002861 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002862 return clib_error_return (0, "unknown input `%U'",
2863 format_unformat_error, input);
2864 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002865
2866 n = count;
2867
2868 for (i = 0; i < n; i++)
2869 {
2870 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002871 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002872
Dave Barach75fc8542016-10-11 16:16:02 -04002873 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874 clib_host_to_net_u32 (1 +
2875 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002876 }
2877
Dave Barach75fc8542016-10-11 16:16:02 -04002878 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2880 else
2881 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2882
2883 return 0;
2884}
2885
Billy McFall0683c9c2016-10-13 08:27:31 -04002886/*?
2887 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2888 * given FIB table to determine if there is a conflict with the
2889 * adjacency table. The fib-id can be determined by using the
2890 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2891 * of 0 is used.
2892 *
2893 * @todo This command uses fib-id, other commands use table-id (not
2894 * just a name, they are different indexes). Would like to change this
2895 * to table-id for consistency.
2896 *
2897 * @cliexpar
2898 * Example of how to run the test lookup command:
2899 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2900 * No errors in 2 lookups
2901 * @cliexend
2902?*/
2903/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002904VLIB_CLI_COMMAND (lookup_test_command, static) =
2905{
2906 .path = "test lookup",
2907 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2908 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002909};
Billy McFall0683c9c2016-10-13 08:27:31 -04002910/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002911
Dave Barachd7cb1b52016-12-09 09:52:16 -05002912int
2913vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002914{
Neale Ranns107e7d42017-04-11 09:55:19 -07002915 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002916
Neale Ranns107e7d42017-04-11 09:55:19 -07002917 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2918
2919 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002920 return VNET_API_ERROR_NO_SUCH_FIB;
2921
Neale Ranns227038a2017-04-21 01:07:59 -07002922 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2923 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002924
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925 return 0;
2926}
Dave Barach75fc8542016-10-11 16:16:02 -04002927
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928static clib_error_t *
2929set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002930 unformat_input_t * input,
2931 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002932{
2933 int matched = 0;
2934 u32 table_id = 0;
2935 u32 flow_hash_config = 0;
2936 int rv;
2937
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2939 {
2940 if (unformat (input, "table %d", &table_id))
2941 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002942#define _(a,v) \
2943 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002944 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002945#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002946 else
2947 break;
2948 }
Dave Barach75fc8542016-10-11 16:16:02 -04002949
Ed Warnickecb9cada2015-12-08 15:45:58 -07002950 if (matched == 0)
2951 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002953
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2955 switch (rv)
2956 {
2957 case 0:
2958 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002959
Ed Warnickecb9cada2015-12-08 15:45:58 -07002960 case VNET_API_ERROR_NO_SUCH_FIB:
2961 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002962
Ed Warnickecb9cada2015-12-08 15:45:58 -07002963 default:
2964 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2965 break;
2966 }
Dave Barach75fc8542016-10-11 16:16:02 -04002967
Ed Warnickecb9cada2015-12-08 15:45:58 -07002968 return 0;
2969}
Dave Barach75fc8542016-10-11 16:16:02 -04002970
Billy McFall0683c9c2016-10-13 08:27:31 -04002971/*?
2972 * Configure the set of IPv4 fields used by the flow hash.
2973 *
2974 * @cliexpar
2975 * Example of how to set the flow hash on a given table:
2976 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2977 * Example of display the configured flow hash:
2978 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002979 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2980 * 0.0.0.0/0
2981 * unicast-ip4-chain
2982 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2983 * [0] [@0]: dpo-drop ip6
2984 * 0.0.0.0/32
2985 * unicast-ip4-chain
2986 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2987 * [0] [@0]: dpo-drop ip6
2988 * 224.0.0.0/8
2989 * unicast-ip4-chain
2990 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2991 * [0] [@0]: dpo-drop ip6
2992 * 6.0.1.2/32
2993 * unicast-ip4-chain
2994 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2995 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2996 * 7.0.0.1/32
2997 * unicast-ip4-chain
2998 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2999 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3000 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3001 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3002 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3003 * 240.0.0.0/8
3004 * unicast-ip4-chain
3005 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3006 * [0] [@0]: dpo-drop ip6
3007 * 255.255.255.255/32
3008 * unicast-ip4-chain
3009 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3010 * [0] [@0]: dpo-drop ip6
3011 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3012 * 0.0.0.0/0
3013 * unicast-ip4-chain
3014 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3015 * [0] [@0]: dpo-drop ip6
3016 * 0.0.0.0/32
3017 * unicast-ip4-chain
3018 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3019 * [0] [@0]: dpo-drop ip6
3020 * 172.16.1.0/24
3021 * unicast-ip4-chain
3022 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3023 * [0] [@4]: ipv4-glean: af_packet0
3024 * 172.16.1.1/32
3025 * unicast-ip4-chain
3026 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3027 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3028 * 172.16.1.2/32
3029 * unicast-ip4-chain
3030 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3031 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3032 * 172.16.2.0/24
3033 * unicast-ip4-chain
3034 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3035 * [0] [@4]: ipv4-glean: af_packet1
3036 * 172.16.2.1/32
3037 * unicast-ip4-chain
3038 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3039 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3040 * 224.0.0.0/8
3041 * unicast-ip4-chain
3042 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3043 * [0] [@0]: dpo-drop ip6
3044 * 240.0.0.0/8
3045 * unicast-ip4-chain
3046 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3047 * [0] [@0]: dpo-drop ip6
3048 * 255.255.255.255/32
3049 * unicast-ip4-chain
3050 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3051 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003052 * @cliexend
3053?*/
3054/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003055VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3056{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003057 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003058 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003059 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003060 .function = set_ip_flow_hash_command_fn,
3061};
Billy McFall0683c9c2016-10-13 08:27:31 -04003062/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003063
Dave Barachd7cb1b52016-12-09 09:52:16 -05003064int
3065vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3066 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003067{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003068 vnet_main_t *vnm = vnet_get_main ();
3069 vnet_interface_main_t *im = &vnm->interface_main;
3070 ip4_main_t *ipm = &ip4_main;
3071 ip_lookup_main_t *lm = &ipm->lookup_main;
3072 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003073 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003074
3075 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3076 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3077
3078 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3079 return VNET_API_ERROR_NO_SUCH_ENTRY;
3080
3081 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003082 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003083
Neale Rannsdf089a82016-10-02 16:39:06 +01003084 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3085
3086 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003087 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003088 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003089 .fp_len = 32,
3090 .fp_proto = FIB_PROTOCOL_IP4,
3091 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003092 };
3093 u32 fib_index;
3094
Dave Barachd7cb1b52016-12-09 09:52:16 -05003095 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3096 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003097
3098
Dave Barachd7cb1b52016-12-09 09:52:16 -05003099 if (table_index != (u32) ~ 0)
3100 {
3101 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003102
Dave Barachd7cb1b52016-12-09 09:52:16 -05003103 dpo_set (&dpo,
3104 DPO_CLASSIFY,
3105 DPO_PROTO_IP4,
3106 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003107
Dave Barachd7cb1b52016-12-09 09:52:16 -05003108 fib_table_entry_special_dpo_add (fib_index,
3109 &pfx,
3110 FIB_SOURCE_CLASSIFY,
3111 FIB_ENTRY_FLAG_NONE, &dpo);
3112 dpo_reset (&dpo);
3113 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003114 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003115 {
3116 fib_table_entry_special_remove (fib_index,
3117 &pfx, FIB_SOURCE_CLASSIFY);
3118 }
3119 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003120
Ed Warnickecb9cada2015-12-08 15:45:58 -07003121 return 0;
3122}
3123
3124static clib_error_t *
3125set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003126 unformat_input_t * input,
3127 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003128{
3129 u32 table_index = ~0;
3130 int table_index_set = 0;
3131 u32 sw_if_index = ~0;
3132 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003133
Dave Barachd7cb1b52016-12-09 09:52:16 -05003134 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3135 {
3136 if (unformat (input, "table-index %d", &table_index))
3137 table_index_set = 1;
3138 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3139 vnet_get_main (), &sw_if_index))
3140 ;
3141 else
3142 break;
3143 }
Dave Barach75fc8542016-10-11 16:16:02 -04003144
Ed Warnickecb9cada2015-12-08 15:45:58 -07003145 if (table_index_set == 0)
3146 return clib_error_return (0, "classify table-index must be specified");
3147
3148 if (sw_if_index == ~0)
3149 return clib_error_return (0, "interface / subif must be specified");
3150
3151 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3152
3153 switch (rv)
3154 {
3155 case 0:
3156 break;
3157
3158 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3159 return clib_error_return (0, "No such interface");
3160
3161 case VNET_API_ERROR_NO_SUCH_ENTRY:
3162 return clib_error_return (0, "No such classifier table");
3163 }
3164 return 0;
3165}
3166
Billy McFall0683c9c2016-10-13 08:27:31 -04003167/*?
3168 * Assign a classification table to an interface. The classification
3169 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3170 * commands. Once the table is create, use this command to filter packets
3171 * on an interface.
3172 *
3173 * @cliexpar
3174 * Example of how to assign a classification table to an interface:
3175 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3176?*/
3177/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003178VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3179{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003180 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003181 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003182 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003183 .function = set_ip_classify_command_fn,
3184};
Billy McFall0683c9c2016-10-13 08:27:31 -04003185/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003186
3187/*
3188 * fd.io coding-style-patch-verification: ON
3189 *
3190 * Local Variables:
3191 * eval: (c-set-style "gnu")
3192 * End:
3193 */