blob: 0a34497da7a6d9b51c158ecf923be5310c7267d2 [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 ip46_address_t nh = {
2261 .ip4 = *dst,
2262 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263
Neale Ranns7a272742017-05-30 02:08:14 -07002264 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2265 VNET_LINK_IP4, &nh, sw_if_index);
2266 adj = adj_get (ai);
2267
2268 h = vlib_packet_template_get_packet (vm,
2269 &im->ip4_arp_request_packet_template,
2270 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002271
2272 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002273 if (PREDICT_FALSE (!hi->hw_address))
2274 {
2275 return clib_error_return (0, "%U: interface %U do not support ip probe",
2276 format_ip4_address, dst,
2277 format_vnet_sw_if_index_name, vnm,
2278 sw_if_index);
2279 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280
Dave Barachd7cb1b52016-12-09 09:52:16 -05002281 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2282 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002283
2284 h->ip4_over_ethernet[0].ip4 = src[0];
2285 h->ip4_over_ethernet[1].ip4 = dst[0];
2286
2287 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002288 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2289 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002290
2291 /* Add encapsulation string for software interface (e.g. ethernet header). */
2292 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2293 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2294
2295 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002296 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2297 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298 to_next[0] = bi;
2299 f->n_vectors = 1;
2300 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2301 }
2302
Neale Ranns7a272742017-05-30 02:08:14 -07002303 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 return /* no error */ 0;
2305}
2306
Dave Barachd7cb1b52016-12-09 09:52:16 -05002307typedef enum
2308{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002309 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002310 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002311} ip4_rewrite_next_t;
2312
2313always_inline uword
2314ip4_rewrite_inline (vlib_main_t * vm,
2315 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002316 vlib_frame_t * frame,
2317 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002318{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002319 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2320 u32 *from = vlib_frame_vector_args (frame);
2321 u32 n_left_from, n_left_to_next, *to_next, next_index;
2322 vlib_node_runtime_t *error_node =
2323 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324
2325 n_left_from = frame->n_vectors;
2326 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002327 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002328
Ed Warnickecb9cada2015-12-08 15:45:58 -07002329 while (n_left_from > 0)
2330 {
2331 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2332
2333 while (n_left_from >= 4 && n_left_to_next >= 2)
2334 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002335 ip_adjacency_t *adj0, *adj1;
2336 vlib_buffer_t *p0, *p1;
2337 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002338 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2339 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002340 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002341
Ed Warnickecb9cada2015-12-08 15:45:58 -07002342 /* Prefetch next iteration. */
2343 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002344 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002345
2346 p2 = vlib_get_buffer (vm, from[2]);
2347 p3 = vlib_get_buffer (vm, from[3]);
2348
2349 vlib_prefetch_buffer_header (p2, STORE);
2350 vlib_prefetch_buffer_header (p3, STORE);
2351
2352 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2353 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2354 }
2355
2356 pi0 = to_next[0] = from[0];
2357 pi1 = to_next[1] = from[1];
2358
2359 from += 2;
2360 n_left_from -= 2;
2361 to_next += 2;
2362 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002363
Ed Warnickecb9cada2015-12-08 15:45:58 -07002364 p0 = vlib_get_buffer (vm, pi0);
2365 p1 = vlib_get_buffer (vm, pi1);
2366
Neale Rannsf06aea52016-11-29 06:51:37 -08002367 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2368 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002369
Neale Ranns1bd01092017-03-15 15:41:17 -04002370 /*
2371 * pre-fetch the per-adjacency counters
2372 */
2373 if (do_counters)
2374 {
2375 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002376 thread_index, adj_index0);
Neale Ranns1bd01092017-03-15 15:41:17 -04002377 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002378 thread_index, adj_index1);
Neale Ranns1bd01092017-03-15 15:41:17 -04002379 }
2380
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381 ip0 = vlib_buffer_get_current (p0);
2382 ip1 = vlib_buffer_get_current (p1);
2383
2384 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002385 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386
2387 /* Decrement TTL & update checksum.
2388 Works either endian, so no need for byte swap. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002389 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002391 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392
2393 /* Input node should have reject packets with ttl 0. */
2394 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395
2396 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398
2399 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002400 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002402
Dave Barachd7cb1b52016-12-09 09:52:16 -05002403 /*
2404 * If the ttl drops below 1 when forwarding, generate
2405 * an ICMP response.
2406 */
2407 if (PREDICT_FALSE (ttl0 <= 0))
2408 {
2409 error0 = IP4_ERROR_TIME_EXPIRED;
2410 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2411 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2412 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2413 0);
2414 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2415 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002416
2417 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002418 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002419 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Neale Rannsf06aea52016-11-29 06:51:37 -08002420 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002421 else
2422 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002423 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002424 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002425 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002426 {
2427 i32 ttl1 = ip1->ttl;
2428
2429 /* Input node should have reject packets with ttl 0. */
2430 ASSERT (ip1->ttl > 0);
2431
2432 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2433 checksum1 += checksum1 >= 0xffff;
2434
2435 ip1->checksum = checksum1;
2436 ttl1 -= 1;
2437 ip1->ttl = ttl1;
2438
Dave Barachd7cb1b52016-12-09 09:52:16 -05002439 /*
2440 * If the ttl drops below 1 when forwarding, generate
2441 * an ICMP response.
2442 */
2443 if (PREDICT_FALSE (ttl1 <= 0))
2444 {
2445 error1 = IP4_ERROR_TIME_EXPIRED;
2446 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2447 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2448 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2449 0);
2450 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2451 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002452
2453 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002454 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002455 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002457 else
2458 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002459 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002460 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002461
2462 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002463 adj0 = adj_get (adj_index0);
2464 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002465
Dave Barachd7cb1b52016-12-09 09:52:16 -05002466 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002467 rw_len0 = adj0[0].rewrite_header.data_bytes;
2468 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002469 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2470 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002471
Dave Barachd7cb1b52016-12-09 09:52:16 -05002472 /* Check MTU of outgoing interface. */
2473 error0 =
2474 (vlib_buffer_length_in_chain (vm, p0) >
2475 adj0[0].
2476 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2477 error0);
2478 error1 =
2479 (vlib_buffer_length_in_chain (vm, p1) >
2480 adj1[0].
2481 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2482 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002483
Dave Barachd7cb1b52016-12-09 09:52:16 -05002484 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2485 * to see the IP headerr */
2486 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2487 {
Damjan Marion892e0762016-12-09 18:52:05 +01002488 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002489 p0->current_data -= rw_len0;
2490 p0->current_length += rw_len0;
2491 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2492 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002493
Neale Rannsb069a692017-03-15 12:34:25 -04002494 if (PREDICT_FALSE
2495 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2496 vnet_feature_arc_start (lm->output_feature_arc_index,
2497 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002498 }
2499 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2500 {
Damjan Marion892e0762016-12-09 18:52:05 +01002501 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002502 p1->current_data -= rw_len1;
2503 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002504
Dave Barachd7cb1b52016-12-09 09:52:16 -05002505 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2506 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002507
Neale Rannsb069a692017-03-15 12:34:25 -04002508 if (PREDICT_FALSE
2509 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2510 vnet_feature_arc_start (lm->output_feature_arc_index,
2511 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002512 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002513
2514 /* Guess we are only writing on simple Ethernet header. */
2515 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002516 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002517
Neale Ranns044183f2017-01-24 01:34:25 -08002518 /*
2519 * Bump the per-adjacency counters
2520 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002521 if (do_counters)
2522 {
2523 vlib_increment_combined_counter
2524 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002525 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002526 adj_index0, 1,
2527 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002528
Neale Ranns9c6a6132017-02-21 05:33:14 -08002529 vlib_increment_combined_counter
2530 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002531 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002532 adj_index1, 1,
2533 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2534 }
Neale Ranns044183f2017-01-24 01:34:25 -08002535
Neale Ranns5e575b12016-10-03 09:40:25 +01002536 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002537 {
2538 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2539 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2540 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002541 if (is_mcast)
2542 {
2543 /*
2544 * copy bytes from the IP address into the MAC rewrite
2545 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002546 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2547 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002548 }
Dave Barach75fc8542016-10-11 16:16:02 -04002549
Ed Warnickecb9cada2015-12-08 15:45:58 -07002550 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2551 to_next, n_left_to_next,
2552 pi0, pi1, next0, next1);
2553 }
2554
2555 while (n_left_from > 0 && n_left_to_next > 0)
2556 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002557 ip_adjacency_t *adj0;
2558 vlib_buffer_t *p0;
2559 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002560 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002561 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002562
Ed Warnickecb9cada2015-12-08 15:45:58 -07002563 pi0 = to_next[0] = from[0];
2564
2565 p0 = vlib_get_buffer (vm, pi0);
2566
Neale Rannsf06aea52016-11-29 06:51:37 -08002567 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002568
Neale Ranns107e7d42017-04-11 09:55:19 -07002569 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002570
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571 ip0 = vlib_buffer_get_current (p0);
2572
2573 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002574 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575
2576 /* Decrement TTL & update checksum. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002577 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002578 {
2579 i32 ttl0 = ip0->ttl;
2580
2581 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2582
2583 checksum0 += checksum0 >= 0xffff;
2584
2585 ip0->checksum = checksum0;
2586
2587 ASSERT (ip0->ttl > 0);
2588
2589 ttl0 -= 1;
2590
2591 ip0->ttl = ttl0;
2592
Dave Barach2c0a4f42017-06-29 09:30:15 -04002593 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002594 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002595
Dave Barachd7cb1b52016-12-09 09:52:16 -05002596 if (PREDICT_FALSE (ttl0 <= 0))
2597 {
2598 /*
2599 * If the ttl drops below 1 when forwarding, generate
2600 * an ICMP response.
2601 */
2602 error0 = IP4_ERROR_TIME_EXPIRED;
2603 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2604 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2605 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2606 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2607 0);
2608 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002609 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002610 else
2611 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002612 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002613 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002614
Neale Ranns1bd01092017-03-15 15:41:17 -04002615 if (do_counters)
2616 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002617 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002618
Ed Warnickecb9cada2015-12-08 15:45:58 -07002619 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002620 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002621 if (is_mcast)
2622 {
2623 /*
2624 * copy bytes from the IP address into the MAC rewrite
2625 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002626 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002627 }
Dave Barach75fc8542016-10-11 16:16:02 -04002628
Dave Barachd7cb1b52016-12-09 09:52:16 -05002629 /* Update packet buffer attributes/set output interface. */
2630 rw_len0 = adj0[0].rewrite_header.data_bytes;
2631 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002632
Neale Ranns1bd01092017-03-15 15:41:17 -04002633 if (do_counters)
2634 vlib_increment_combined_counter
2635 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002636 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002637 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002638
Dave Barachd7cb1b52016-12-09 09:52:16 -05002639 /* Check MTU of outgoing interface. */
2640 error0 = (vlib_buffer_length_in_chain (vm, p0)
2641 > adj0[0].rewrite_header.max_l3_packet_bytes
2642 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002643
Ed Warnickecb9cada2015-12-08 15:45:58 -07002644 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002645
Dave Barachd7cb1b52016-12-09 09:52:16 -05002646 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2647 * to see the IP headerr */
2648 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2649 {
2650 p0->current_data -= rw_len0;
2651 p0->current_length += rw_len0;
2652 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002653
Dave Barachd7cb1b52016-12-09 09:52:16 -05002654 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2655 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002656
Neale Ranns5e575b12016-10-03 09:40:25 +01002657 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002658 {
2659 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002660 }
2661
Neale Rannsb069a692017-03-15 12:34:25 -04002662 if (PREDICT_FALSE
2663 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2664 vnet_feature_arc_start (lm->output_feature_arc_index,
2665 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002666
Dave Barachd7cb1b52016-12-09 09:52:16 -05002667 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002668
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669 from += 1;
2670 n_left_from -= 1;
2671 to_next += 1;
2672 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002673
Ed Warnickecb9cada2015-12-08 15:45:58 -07002674 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2675 to_next, n_left_to_next,
2676 pi0, next0);
2677 }
Dave Barach75fc8542016-10-11 16:16:02 -04002678
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2680 }
2681
2682 /* Need to do trace after rewrites to pick up new packet data. */
2683 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002684 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002685
2686 return frame->n_vectors;
2687}
2688
Dave Barach132d51d2016-07-07 10:10:17 -04002689
Neale Rannsf06aea52016-11-29 06:51:37 -08002690/** @brief IPv4 rewrite node.
2691 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002692
2693 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2694 header checksum, fetch the ip adjacency, check the outbound mtu,
2695 apply the adjacency rewrite, and send pkts to the adjacency
2696 rewrite header's rewrite_next_index.
2697
2698 @param vm vlib_main_t corresponding to the current thread
2699 @param node vlib_node_runtime_t
2700 @param frame vlib_frame_t whose contents should be dispatched
2701
2702 @par Graph mechanics: buffer metadata, next index usage
2703
2704 @em Uses:
2705 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2706 - the rewrite adjacency index
2707 - <code>adj->lookup_next_index</code>
2708 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002709 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002710 - <code>adj->rewrite_header</code>
2711 - Rewrite string length, rewrite string, next_index
2712
2713 @em Sets:
2714 - <code>b->current_data, b->current_length</code>
2715 - Updated net of applying the rewrite string
2716
2717 <em>Next Indices:</em>
2718 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002719 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002720*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002721static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002722ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002723 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002724{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002725 if (adj_are_counters_enabled ())
2726 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2727 else
2728 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729}
2730
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002731static uword
2732ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002733 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002734{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002735 if (adj_are_counters_enabled ())
2736 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2737 else
2738 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002739}
2740
Neale Ranns32e1c012016-11-22 17:07:28 +00002741static uword
2742ip4_rewrite_mcast (vlib_main_t * vm,
2743 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002744{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002745 if (adj_are_counters_enabled ())
2746 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2747 else
2748 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002749}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002750
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002751static uword
2752ip4_mcast_midchain (vlib_main_t * vm,
2753 vlib_node_runtime_t * node, vlib_frame_t * frame)
2754{
2755 if (adj_are_counters_enabled ())
2756 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2757 else
2758 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2759}
2760
Neale Ranns32e1c012016-11-22 17:07:28 +00002761/* *INDENT-OFF* */
2762VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2763 .function = ip4_rewrite,
2764 .name = "ip4-rewrite",
2765 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002766
Neale Ranns32e1c012016-11-22 17:07:28 +00002767 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002768
Neale Ranns32e1c012016-11-22 17:07:28 +00002769 .n_next_nodes = 2,
2770 .next_nodes = {
2771 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2772 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2773 },
2774};
2775VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2776
2777VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2778 .function = ip4_rewrite_mcast,
2779 .name = "ip4-rewrite-mcast",
2780 .vector_size = sizeof (u32),
2781
2782 .format_trace = format_ip4_rewrite_trace,
2783 .sibling_of = "ip4-rewrite",
2784};
2785VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2786
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002787VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2788 .function = ip4_mcast_midchain,
2789 .name = "ip4-mcast-midchain",
2790 .vector_size = sizeof (u32),
2791
2792 .format_trace = format_ip4_rewrite_trace,
2793 .sibling_of = "ip4-rewrite",
2794};
2795VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2796
Neale Ranns32e1c012016-11-22 17:07:28 +00002797VLIB_REGISTER_NODE (ip4_midchain_node) = {
2798 .function = ip4_midchain,
2799 .name = "ip4-midchain",
2800 .vector_size = sizeof (u32),
2801 .format_trace = format_ip4_forward_next_trace,
2802 .sibling_of = "ip4-rewrite",
2803};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002804VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002805/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002806
Dave Barachd7cb1b52016-12-09 09:52:16 -05002807int
2808ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2809{
2810 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002811 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002812 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002813
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002814 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002815
Neale Ranns04a75e32017-03-23 06:46:01 -07002816 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002817 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2818 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002819
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002820 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002821
Dave Barachd7cb1b52016-12-09 09:52:16 -05002822 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002823}
Dave Barach75fc8542016-10-11 16:16:02 -04002824
Ed Warnickecb9cada2015-12-08 15:45:58 -07002825static clib_error_t *
2826test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002827 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002828{
Billy McFall309fe062016-10-14 07:37:33 -04002829 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002830 u32 table_id = 0;
2831 f64 count = 1;
2832 u32 n;
2833 int i;
2834 ip4_address_t ip4_base_address;
2835 u64 errors = 0;
2836
Dave Barachd7cb1b52016-12-09 09:52:16 -05002837 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2838 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002839 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002840 {
2841 /* Make sure the entry exists. */
2842 fib = ip4_fib_get (table_id);
2843 if ((fib) && (fib->index != table_id))
2844 return clib_error_return (0, "<fib-index> %d does not exist",
2845 table_id);
2846 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002847 else if (unformat (input, "count %f", &count))
2848 ;
2849
2850 else if (unformat (input, "%U",
2851 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002852 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002853 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002854 return clib_error_return (0, "unknown input `%U'",
2855 format_unformat_error, input);
2856 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002857
2858 n = count;
2859
2860 for (i = 0; i < n; i++)
2861 {
2862 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002863 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002864
Dave Barach75fc8542016-10-11 16:16:02 -04002865 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002866 clib_host_to_net_u32 (1 +
2867 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002868 }
2869
Dave Barach75fc8542016-10-11 16:16:02 -04002870 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002871 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2872 else
2873 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2874
2875 return 0;
2876}
2877
Billy McFall0683c9c2016-10-13 08:27:31 -04002878/*?
2879 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2880 * given FIB table to determine if there is a conflict with the
2881 * adjacency table. The fib-id can be determined by using the
2882 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2883 * of 0 is used.
2884 *
2885 * @todo This command uses fib-id, other commands use table-id (not
2886 * just a name, they are different indexes). Would like to change this
2887 * to table-id for consistency.
2888 *
2889 * @cliexpar
2890 * Example of how to run the test lookup command:
2891 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2892 * No errors in 2 lookups
2893 * @cliexend
2894?*/
2895/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002896VLIB_CLI_COMMAND (lookup_test_command, static) =
2897{
2898 .path = "test lookup",
2899 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2900 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002901};
Billy McFall0683c9c2016-10-13 08:27:31 -04002902/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002903
Dave Barachd7cb1b52016-12-09 09:52:16 -05002904int
2905vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002906{
Neale Ranns107e7d42017-04-11 09:55:19 -07002907 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002908
Neale Ranns107e7d42017-04-11 09:55:19 -07002909 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2910
2911 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002912 return VNET_API_ERROR_NO_SUCH_FIB;
2913
Neale Ranns227038a2017-04-21 01:07:59 -07002914 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2915 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002916
Ed Warnickecb9cada2015-12-08 15:45:58 -07002917 return 0;
2918}
Dave Barach75fc8542016-10-11 16:16:02 -04002919
Ed Warnickecb9cada2015-12-08 15:45:58 -07002920static clib_error_t *
2921set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922 unformat_input_t * input,
2923 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002924{
2925 int matched = 0;
2926 u32 table_id = 0;
2927 u32 flow_hash_config = 0;
2928 int rv;
2929
Dave Barachd7cb1b52016-12-09 09:52:16 -05002930 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2931 {
2932 if (unformat (input, "table %d", &table_id))
2933 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002934#define _(a,v) \
2935 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002936 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002937#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 else
2939 break;
2940 }
Dave Barach75fc8542016-10-11 16:16:02 -04002941
Ed Warnickecb9cada2015-12-08 15:45:58 -07002942 if (matched == 0)
2943 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002944 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002945
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2947 switch (rv)
2948 {
2949 case 0:
2950 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002951
Ed Warnickecb9cada2015-12-08 15:45:58 -07002952 case VNET_API_ERROR_NO_SUCH_FIB:
2953 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002954
Ed Warnickecb9cada2015-12-08 15:45:58 -07002955 default:
2956 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2957 break;
2958 }
Dave Barach75fc8542016-10-11 16:16:02 -04002959
Ed Warnickecb9cada2015-12-08 15:45:58 -07002960 return 0;
2961}
Dave Barach75fc8542016-10-11 16:16:02 -04002962
Billy McFall0683c9c2016-10-13 08:27:31 -04002963/*?
2964 * Configure the set of IPv4 fields used by the flow hash.
2965 *
2966 * @cliexpar
2967 * Example of how to set the flow hash on a given table:
2968 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2969 * Example of display the configured flow hash:
2970 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002971 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2972 * 0.0.0.0/0
2973 * unicast-ip4-chain
2974 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2975 * [0] [@0]: dpo-drop ip6
2976 * 0.0.0.0/32
2977 * unicast-ip4-chain
2978 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2979 * [0] [@0]: dpo-drop ip6
2980 * 224.0.0.0/8
2981 * unicast-ip4-chain
2982 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2983 * [0] [@0]: dpo-drop ip6
2984 * 6.0.1.2/32
2985 * unicast-ip4-chain
2986 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2987 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2988 * 7.0.0.1/32
2989 * unicast-ip4-chain
2990 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2991 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2992 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2993 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2994 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2995 * 240.0.0.0/8
2996 * unicast-ip4-chain
2997 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2998 * [0] [@0]: dpo-drop ip6
2999 * 255.255.255.255/32
3000 * unicast-ip4-chain
3001 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3002 * [0] [@0]: dpo-drop ip6
3003 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3004 * 0.0.0.0/0
3005 * unicast-ip4-chain
3006 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3007 * [0] [@0]: dpo-drop ip6
3008 * 0.0.0.0/32
3009 * unicast-ip4-chain
3010 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3011 * [0] [@0]: dpo-drop ip6
3012 * 172.16.1.0/24
3013 * unicast-ip4-chain
3014 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3015 * [0] [@4]: ipv4-glean: af_packet0
3016 * 172.16.1.1/32
3017 * unicast-ip4-chain
3018 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3019 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3020 * 172.16.1.2/32
3021 * unicast-ip4-chain
3022 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3023 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3024 * 172.16.2.0/24
3025 * unicast-ip4-chain
3026 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3027 * [0] [@4]: ipv4-glean: af_packet1
3028 * 172.16.2.1/32
3029 * unicast-ip4-chain
3030 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3031 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3032 * 224.0.0.0/8
3033 * unicast-ip4-chain
3034 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3035 * [0] [@0]: dpo-drop ip6
3036 * 240.0.0.0/8
3037 * unicast-ip4-chain
3038 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3039 * [0] [@0]: dpo-drop ip6
3040 * 255.255.255.255/32
3041 * unicast-ip4-chain
3042 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3043 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003044 * @cliexend
3045?*/
3046/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003047VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3048{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003049 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003050 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003051 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052 .function = set_ip_flow_hash_command_fn,
3053};
Billy McFall0683c9c2016-10-13 08:27:31 -04003054/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003055
Dave Barachd7cb1b52016-12-09 09:52:16 -05003056int
3057vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3058 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003059{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003060 vnet_main_t *vnm = vnet_get_main ();
3061 vnet_interface_main_t *im = &vnm->interface_main;
3062 ip4_main_t *ipm = &ip4_main;
3063 ip_lookup_main_t *lm = &ipm->lookup_main;
3064 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003065 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003066
3067 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3068 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3069
3070 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3071 return VNET_API_ERROR_NO_SUCH_ENTRY;
3072
3073 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003074 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003075
Neale Rannsdf089a82016-10-02 16:39:06 +01003076 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3077
3078 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003079 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003080 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003081 .fp_len = 32,
3082 .fp_proto = FIB_PROTOCOL_IP4,
3083 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003084 };
3085 u32 fib_index;
3086
Dave Barachd7cb1b52016-12-09 09:52:16 -05003087 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3088 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003089
3090
Dave Barachd7cb1b52016-12-09 09:52:16 -05003091 if (table_index != (u32) ~ 0)
3092 {
3093 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003094
Dave Barachd7cb1b52016-12-09 09:52:16 -05003095 dpo_set (&dpo,
3096 DPO_CLASSIFY,
3097 DPO_PROTO_IP4,
3098 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003099
Dave Barachd7cb1b52016-12-09 09:52:16 -05003100 fib_table_entry_special_dpo_add (fib_index,
3101 &pfx,
3102 FIB_SOURCE_CLASSIFY,
3103 FIB_ENTRY_FLAG_NONE, &dpo);
3104 dpo_reset (&dpo);
3105 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003106 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003107 {
3108 fib_table_entry_special_remove (fib_index,
3109 &pfx, FIB_SOURCE_CLASSIFY);
3110 }
3111 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003112
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113 return 0;
3114}
3115
3116static clib_error_t *
3117set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003118 unformat_input_t * input,
3119 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120{
3121 u32 table_index = ~0;
3122 int table_index_set = 0;
3123 u32 sw_if_index = ~0;
3124 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003125
Dave Barachd7cb1b52016-12-09 09:52:16 -05003126 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3127 {
3128 if (unformat (input, "table-index %d", &table_index))
3129 table_index_set = 1;
3130 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3131 vnet_get_main (), &sw_if_index))
3132 ;
3133 else
3134 break;
3135 }
Dave Barach75fc8542016-10-11 16:16:02 -04003136
Ed Warnickecb9cada2015-12-08 15:45:58 -07003137 if (table_index_set == 0)
3138 return clib_error_return (0, "classify table-index must be specified");
3139
3140 if (sw_if_index == ~0)
3141 return clib_error_return (0, "interface / subif must be specified");
3142
3143 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3144
3145 switch (rv)
3146 {
3147 case 0:
3148 break;
3149
3150 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3151 return clib_error_return (0, "No such interface");
3152
3153 case VNET_API_ERROR_NO_SUCH_ENTRY:
3154 return clib_error_return (0, "No such classifier table");
3155 }
3156 return 0;
3157}
3158
Billy McFall0683c9c2016-10-13 08:27:31 -04003159/*?
3160 * Assign a classification table to an interface. The classification
3161 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3162 * commands. Once the table is create, use this command to filter packets
3163 * on an interface.
3164 *
3165 * @cliexpar
3166 * Example of how to assign a classification table to an interface:
3167 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3168?*/
3169/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003170VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3171{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003173 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003174 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175 .function = set_ip_classify_command_fn,
3176};
Billy McFall0683c9c2016-10-13 08:27:31 -04003177/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003178
3179/*
3180 * fd.io coding-style-patch-verification: ON
3181 *
3182 * Local Variables:
3183 * eval: (c-set-style "gnu")
3184 * End:
3185 */