blob: 5472428fcfdec5f5173fed955a422dd8e94359c3 [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>
52#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000053#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
Billy McFall0683c9c2016-10-13 08:27:31 -040055/**
56 * @file
57 * @brief IPv4 Forwarding.
58 *
59 * This file contains the source code for IPv4 forwarding.
60 */
61
Pierre Pfister0febaf12016-06-08 12:23:21 +010062void
63ip4_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050064 vlib_node_runtime_t * node,
65 vlib_frame_t * frame,
66 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010067
Ed Warnickecb9cada2015-12-08 15:45:58 -070068always_inline uword
69ip4_lookup_inline (vlib_main_t * vm,
70 vlib_node_runtime_t * node,
71 vlib_frame_t * frame,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010072 int lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -070073{
Dave Barachd7cb1b52016-12-09 09:52:16 -050074 ip4_main_t *im = &ip4_main;
75 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
76 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -050078 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 from = vlib_frame_vector_args (frame);
81 n_left_from = frame->n_vectors;
82 next = node->cached_next_index;
83
84 while (n_left_from > 0)
85 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050086 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070087
Dave Barach670909e2016-10-18 15:25:35 -040088 while (n_left_from >= 8 && n_left_to_next >= 4)
Dave Barachd7cb1b52016-12-09 09:52:16 -050089 {
90 vlib_buffer_t *p0, *p1, *p2, *p3;
91 ip4_header_t *ip0, *ip1, *ip2, *ip3;
92 __attribute__ ((unused)) tcp_header_t *tcp0, *tcp1, *tcp2, *tcp3;
93 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;
98 __attribute__ ((unused)) u32 pi0, fib_index0, lb_index0,
99 is_tcp_udp0;
100 __attribute__ ((unused)) u32 pi1, fib_index1, lb_index1,
101 is_tcp_udp1;
102 __attribute__ ((unused)) u32 pi2, fib_index2, lb_index2,
103 is_tcp_udp2;
104 __attribute__ ((unused)) u32 pi3, fib_index3, lb_index3,
105 is_tcp_udp3;
106 flow_hash_config_t flow_hash_config0, flow_hash_config1;
107 flow_hash_config_t flow_hash_config2, flow_hash_config3;
108 u32 hash_c0, hash_c1, hash_c2, hash_c3;
Dave Barach670909e2016-10-18 15:25:35 -0400109 const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110
Dave Barachd7cb1b52016-12-09 09:52:16 -0500111 /* Prefetch next iteration. */
112 {
113 vlib_buffer_t *p4, *p5, *p6, *p7;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114
Dave Barachd7cb1b52016-12-09 09:52:16 -0500115 p4 = vlib_get_buffer (vm, from[4]);
116 p5 = vlib_get_buffer (vm, from[5]);
117 p6 = vlib_get_buffer (vm, from[6]);
118 p7 = vlib_get_buffer (vm, from[7]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 vlib_prefetch_buffer_header (p4, LOAD);
121 vlib_prefetch_buffer_header (p5, LOAD);
122 vlib_prefetch_buffer_header (p6, LOAD);
123 vlib_prefetch_buffer_header (p7, LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124
Dave Barachd7cb1b52016-12-09 09:52:16 -0500125 CLIB_PREFETCH (p4->data, sizeof (ip0[0]), LOAD);
126 CLIB_PREFETCH (p5->data, sizeof (ip0[0]), LOAD);
127 CLIB_PREFETCH (p6->data, sizeof (ip0[0]), LOAD);
128 CLIB_PREFETCH (p7->data, sizeof (ip0[0]), LOAD);
129 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barachd7cb1b52016-12-09 09:52:16 -0500131 pi0 = to_next[0] = from[0];
132 pi1 = to_next[1] = from[1];
133 pi2 = to_next[2] = from[2];
134 pi3 = to_next[3] = from[3];
Dave Barach670909e2016-10-18 15:25:35 -0400135
Dave Barachd7cb1b52016-12-09 09:52:16 -0500136 from += 4;
137 to_next += 4;
138 n_left_to_next -= 4;
139 n_left_from -= 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141 p0 = vlib_get_buffer (vm, pi0);
142 p1 = vlib_get_buffer (vm, pi1);
143 p2 = vlib_get_buffer (vm, pi2);
144 p3 = vlib_get_buffer (vm, pi3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
Dave Barachd7cb1b52016-12-09 09:52:16 -0500146 ip0 = vlib_buffer_get_current (p0);
147 ip1 = vlib_buffer_get_current (p1);
148 ip2 = vlib_buffer_get_current (p2);
149 ip3 = vlib_buffer_get_current (p3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150
Dave Barachd7cb1b52016-12-09 09:52:16 -0500151 dst_addr0 = &ip0->dst_address;
152 dst_addr1 = &ip1->dst_address;
153 dst_addr2 = &ip2->dst_address;
154 dst_addr3 = &ip3->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200155
Dave Barachd7cb1b52016-12-09 09:52:16 -0500156 fib_index0 =
157 vec_elt (im->fib_index_by_sw_if_index,
158 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
159 fib_index1 =
160 vec_elt (im->fib_index_by_sw_if_index,
161 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
162 fib_index2 =
163 vec_elt (im->fib_index_by_sw_if_index,
164 vnet_buffer (p2)->sw_if_index[VLIB_RX]);
165 fib_index3 =
166 vec_elt (im->fib_index_by_sw_if_index,
167 vnet_buffer (p3)->sw_if_index[VLIB_RX]);
168 fib_index0 =
169 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
170 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
171 fib_index1 =
172 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
173 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
174 fib_index2 =
175 (vnet_buffer (p2)->sw_if_index[VLIB_TX] ==
176 (u32) ~ 0) ? fib_index2 : vnet_buffer (p2)->sw_if_index[VLIB_TX];
177 fib_index3 =
178 (vnet_buffer (p3)->sw_if_index[VLIB_TX] ==
179 (u32) ~ 0) ? fib_index3 : vnet_buffer (p3)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180
181
Dave Barachd7cb1b52016-12-09 09:52:16 -0500182 if (!lookup_for_responses_to_locally_received_packets)
183 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100184 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
185 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Dave Barach670909e2016-10-18 15:25:35 -0400186 mtrie2 = &ip4_fib_get (fib_index2)->mtrie;
187 mtrie3 = &ip4_fib_get (fib_index3)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 leaf0 = leaf1 = leaf2 = leaf3 = IP4_FIB_MTRIE_LEAF_ROOT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barachd7cb1b52016-12-09 09:52:16 -0500191 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
192 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 0);
193 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 0);
194 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 0);
195 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196
Dave Barachd7cb1b52016-12-09 09:52:16 -0500197 tcp0 = (void *) (ip0 + 1);
198 tcp1 = (void *) (ip1 + 1);
199 tcp2 = (void *) (ip2 + 1);
200 tcp3 = (void *) (ip3 + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201
Dave Barachd7cb1b52016-12-09 09:52:16 -0500202 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
203 || ip0->protocol == IP_PROTOCOL_UDP);
204 is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
205 || ip1->protocol == IP_PROTOCOL_UDP);
206 is_tcp_udp2 = (ip2->protocol == IP_PROTOCOL_TCP
207 || ip2->protocol == IP_PROTOCOL_UDP);
208 is_tcp_udp3 = (ip1->protocol == IP_PROTOCOL_TCP
209 || ip1->protocol == IP_PROTOCOL_UDP);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
Dave Barachd7cb1b52016-12-09 09:52:16 -0500211 if (!lookup_for_responses_to_locally_received_packets)
212 {
213 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
214 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 1);
215 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 1);
216 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 1);
217 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218
Dave Barachd7cb1b52016-12-09 09:52:16 -0500219 if (!lookup_for_responses_to_locally_received_packets)
220 {
221 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
222 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
223 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 2);
224 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 2);
225 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226
Dave Barachd7cb1b52016-12-09 09:52:16 -0500227 if (!lookup_for_responses_to_locally_received_packets)
228 {
229 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
230 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
231 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 3);
232 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 3);
233 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234
Dave Barachd7cb1b52016-12-09 09:52:16 -0500235 if (lookup_for_responses_to_locally_received_packets)
236 {
237 lb_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
238 lb_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
239 lb_index2 = vnet_buffer (p2)->ip.adj_index[VLIB_RX];
240 lb_index3 = vnet_buffer (p3)->ip.adj_index[VLIB_RX];
241 }
242 else
243 {
244 /* Handle default route. */
245 leaf0 =
246 (leaf0 ==
247 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
248 leaf1 =
249 (leaf1 ==
250 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
251 leaf2 =
252 (leaf2 ==
253 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie2->default_leaf : leaf2);
254 leaf3 =
255 (leaf3 ==
256 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie3->default_leaf : leaf3);
257 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
258 lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
259 lb_index2 = ip4_fib_mtrie_leaf_get_adj_index (leaf2);
260 lb_index3 = ip4_fib_mtrie_leaf_get_adj_index (leaf3);
261 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100263 lb0 = load_balance_get (lb_index0);
264 lb1 = load_balance_get (lb_index1);
Dave Barach670909e2016-10-18 15:25:35 -0400265 lb2 = load_balance_get (lb_index2);
266 lb3 = load_balance_get (lb_index3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Dave Barachd7cb1b52016-12-09 09:52:16 -0500268 /* Use flow hash to compute multipath adjacency. */
269 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
270 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
271 hash_c2 = vnet_buffer (p2)->ip.flow_hash = 0;
272 hash_c3 = vnet_buffer (p3)->ip.flow_hash = 0;
273 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
274 {
275 flow_hash_config0 = lb0->lb_hash_config;
276 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
277 ip4_compute_flow_hash (ip0, flow_hash_config0);
278 }
279 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
280 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281 flow_hash_config1 = lb1->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500282 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
283 ip4_compute_flow_hash (ip1, flow_hash_config1);
284 }
285 if (PREDICT_FALSE (lb2->lb_n_buckets > 1))
286 {
287 flow_hash_config2 = lb2->lb_hash_config;
288 hash_c2 = vnet_buffer (p2)->ip.flow_hash =
289 ip4_compute_flow_hash (ip2, flow_hash_config2);
290 }
291 if (PREDICT_FALSE (lb3->lb_n_buckets > 1))
292 {
Dave Barach670909e2016-10-18 15:25:35 -0400293 flow_hash_config3 = lb3->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500294 hash_c3 = vnet_buffer (p3)->ip.flow_hash =
295 ip4_compute_flow_hash (ip3, flow_hash_config3);
296 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298 ASSERT (lb0->lb_n_buckets > 0);
299 ASSERT (is_pow2 (lb0->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500300 ASSERT (lb1->lb_n_buckets > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100301 ASSERT (is_pow2 (lb1->lb_n_buckets));
Dave Barach670909e2016-10-18 15:25:35 -0400302 ASSERT (lb2->lb_n_buckets > 0);
303 ASSERT (is_pow2 (lb2->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304 ASSERT (lb3->lb_n_buckets > 0);
Dave Barach670909e2016-10-18 15:25:35 -0400305 ASSERT (is_pow2 (lb3->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
Dave Barachd7cb1b52016-12-09 09:52:16 -0500307 dpo0 = load_balance_get_bucket_i (lb0,
308 (hash_c0 &
309 (lb0->lb_n_buckets_minus_1)));
310 dpo1 = load_balance_get_bucket_i (lb1,
311 (hash_c1 &
312 (lb1->lb_n_buckets_minus_1)));
313 dpo2 = load_balance_get_bucket_i (lb2,
314 (hash_c2 &
315 (lb2->lb_n_buckets_minus_1)));
316 dpo3 = load_balance_get_bucket_i (lb3,
317 (hash_c3 &
318 (lb3->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100320 next0 = dpo0->dpoi_next_node;
321 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
322 next1 = dpo1->dpoi_next_node;
323 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Dave Barach670909e2016-10-18 15:25:35 -0400324 next2 = dpo2->dpoi_next_node;
325 vnet_buffer (p2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
326 next3 = dpo3->dpoi_next_node;
327 vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200328
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329 vlib_increment_combined_counter
330 (cm, cpu_index, lb_index0, 1,
331 vlib_buffer_length_in_chain (vm, p0)
332 + sizeof (ethernet_header_t));
333 vlib_increment_combined_counter
334 (cm, cpu_index, lb_index1, 1,
335 vlib_buffer_length_in_chain (vm, p1)
336 + sizeof (ethernet_header_t));
337 vlib_increment_combined_counter
338 (cm, cpu_index, lb_index2, 1,
339 vlib_buffer_length_in_chain (vm, p2)
340 + sizeof (ethernet_header_t));
341 vlib_increment_combined_counter
342 (cm, cpu_index, lb_index3, 1,
343 vlib_buffer_length_in_chain (vm, p3)
344 + sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345
Dave Barach670909e2016-10-18 15:25:35 -0400346 vlib_validate_buffer_enqueue_x4 (vm, node, next,
347 to_next, n_left_to_next,
348 pi0, pi1, pi2, pi3,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500349 next0, next1, next2, next3);
350 }
Dave Barach75fc8542016-10-11 16:16:02 -0400351
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 while (n_left_from > 0 && n_left_to_next > 0)
353 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500354 vlib_buffer_t *p0;
355 ip4_header_t *ip0;
356 __attribute__ ((unused)) tcp_header_t *tcp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 ip_lookup_next_t next0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100358 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500359 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 ip4_fib_mtrie_leaf_t leaf0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500361 ip4_address_t *dst_addr0;
362 __attribute__ ((unused)) u32 pi0, fib_index0, is_tcp_udp0, lbi0;
363 flow_hash_config_t flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100364 const dpo_id_t *dpo0;
365 u32 hash_c0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
367 pi0 = from[0];
368 to_next[0] = pi0;
369
370 p0 = vlib_get_buffer (vm, pi0);
371
372 ip0 = vlib_buffer_get_current (p0);
373
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100374 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200375
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 fib_index0 =
377 vec_elt (im->fib_index_by_sw_if_index,
378 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
379 fib_index0 =
380 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
381 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Dave Barachd7cb1b52016-12-09 09:52:16 -0500383 if (!lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500385 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386
387 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
388
Damjan Marionaca64c92016-04-13 09:48:56 +0200389 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 }
391
392 tcp0 = (void *) (ip0 + 1);
393
394 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
395 || ip0->protocol == IP_PROTOCOL_UDP);
396
Dave Barachd7cb1b52016-12-09 09:52:16 -0500397 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200398 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399
Dave Barachd7cb1b52016-12-09 09:52:16 -0500400 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200401 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402
Dave Barachd7cb1b52016-12-09 09:52:16 -0500403 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200404 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405
406 if (lookup_for_responses_to_locally_received_packets)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100407 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408 else
409 {
410 /* Handle default route. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500411 leaf0 =
412 (leaf0 ==
413 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100414 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415 }
416
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418
419 /* Use flow hash to compute multipath adjacency. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500420 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
421 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
422 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100423 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424
Dave Barachd7cb1b52016-12-09 09:52:16 -0500425 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
426 ip4_compute_flow_hash (ip0, flow_hash_config0);
427 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100429 ASSERT (lb0->lb_n_buckets > 0);
430 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431
Dave Barachd7cb1b52016-12-09 09:52:16 -0500432 dpo0 = load_balance_get_bucket_i (lb0,
433 (hash_c0 &
434 (lb0->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100436 next0 = dpo0->dpoi_next_node;
437 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200438
Dave Barach75fc8542016-10-11 16:16:02 -0400439 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500440 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700441
442 from += 1;
443 to_next += 1;
444 n_left_to_next -= 1;
445 n_left_from -= 1;
446
447 if (PREDICT_FALSE (next0 != next))
448 {
449 n_left_to_next += 1;
450 vlib_put_next_frame (vm, node, next, n_left_to_next);
451 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453 to_next[0] = pi0;
454 to_next += 1;
455 n_left_to_next -= 1;
456 }
457 }
458
459 vlib_put_next_frame (vm, node, next, n_left_to_next);
460 }
461
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100462 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500463 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100464
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465 return frame->n_vectors;
466}
467
Chris Luke8e5b0412016-07-26 13:06:10 -0400468/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -0400469 @node ip4-lookup
470
471 This is the main IPv4 lookup dispatch node.
472
473 @param vm vlib_main_t corresponding to the current thread
474 @param node vlib_node_runtime_t
475 @param frame vlib_frame_t whose contents should be dispatched
476
477 @par Graph mechanics: buffer metadata, next index usage
478
479 @em Uses:
480 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
481 - Indicates the @c sw_if_index value of the interface that the
482 packet was received on.
483 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
484 - When the value is @c ~0 then the node performs a longest prefix
485 match (LPM) for the packet destination address in the FIB attached
486 to the receive interface.
487 - Otherwise perform LPM for the packet destination address in the
488 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
489 value (0, 1, ...) and not a VRF id.
490
491 @em Sets:
492 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
493 - The lookup result adjacency index.
494
495 <em>Next Index:</em>
496 - Dispatches the packet to the node index found in
497 ip_adjacency_t @c adj->lookup_next_index
498 (where @c adj is the lookup result adjacency).
499*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500static uword
501ip4_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500502 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503{
Damjan Marionaca64c92016-04-13 09:48:56 +0200504 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505 /* lookup_for_responses_to_locally_received_packets */
506 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507
508}
509
Dave Barachd7cb1b52016-12-09 09:52:16 -0500510static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100511
Dave Barachd7cb1b52016-12-09 09:52:16 -0500512VLIB_REGISTER_NODE (ip4_lookup_node) =
513{
514.function = ip4_lookup,.name = "ip4-lookup",.vector_size =
515 sizeof (u32),.format_trace = format_ip4_lookup_trace,.n_next_nodes =
516 IP_LOOKUP_N_NEXT,.next_nodes = IP4_LOOKUP_NEXT_NODES,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100517
Dave Barachd7cb1b52016-12-09 09:52:16 -0500518VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100519
520always_inline uword
521ip4_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500522 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500524 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
525 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100526 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500527 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100529 from = vlib_frame_vector_args (frame);
530 n_left_from = frame->n_vectors;
531 next = node->cached_next_index;
532
533 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100535
536 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500538 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100539
Dave Barach75fc8542016-10-11 16:16:02 -0400540
Neale Ranns2be95c12016-11-19 13:50:04 +0000541 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500542 {
543 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000544 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500545 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000546 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
547 const ip4_header_t *ip0, *ip1;
548 const dpo_id_t *dpo0, *dpo1;
549
Dave Barachd7cb1b52016-12-09 09:52:16 -0500550 /* Prefetch next iteration. */
551 {
552 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000553
554 p2 = vlib_get_buffer (vm, from[2]);
555 p3 = vlib_get_buffer (vm, from[3]);
556
557 vlib_prefetch_buffer_header (p2, STORE);
558 vlib_prefetch_buffer_header (p3, STORE);
559
560 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
561 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500562 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000563
564 pi0 = to_next[0] = from[0];
565 pi1 = to_next[1] = from[1];
566
567 from += 2;
568 n_left_from -= 2;
569 to_next += 2;
570 n_left_to_next -= 2;
571
572 p0 = vlib_get_buffer (vm, pi0);
573 p1 = vlib_get_buffer (vm, pi1);
574
575 ip0 = vlib_buffer_get_current (p0);
576 ip1 = vlib_buffer_get_current (p1);
577 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
578 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
579
Dave Barachd7cb1b52016-12-09 09:52:16 -0500580 lb0 = load_balance_get (lbi0);
581 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000582
Dave Barachd7cb1b52016-12-09 09:52:16 -0500583 /*
584 * this node is for via FIBs we can re-use the hash value from the
585 * to node if present.
586 * We don't want to use the same hash value at each level in the recursion
587 * graph as that would lead to polarisation
588 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000589 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000590
Dave Barachd7cb1b52016-12-09 09:52:16 -0500591 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
592 {
593 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
594 {
595 hc0 = vnet_buffer (p0)->ip.flow_hash =
596 vnet_buffer (p0)->ip.flow_hash >> 1;
597 }
598 else
599 {
600 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000601 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500602 }
603 }
604 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
605 {
606 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
607 {
608 hc1 = vnet_buffer (p1)->ip.flow_hash =
609 vnet_buffer (p1)->ip.flow_hash >> 1;
610 }
611 else
612 {
613 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000614 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500615 }
616 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000617
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 dpo0 =
619 load_balance_get_bucket_i (lb0,
620 hc0 & (lb0->lb_n_buckets_minus_1));
621 dpo1 =
622 load_balance_get_bucket_i (lb1,
623 hc1 & (lb1->lb_n_buckets_minus_1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000624
625 next0 = dpo0->dpoi_next_node;
626 next1 = dpo1->dpoi_next_node;
627
628 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
629 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
630
631 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500632 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000633 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000635
636 vlib_validate_buffer_enqueue_x2 (vm, node, next,
637 to_next, n_left_to_next,
638 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000640
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 while (n_left_from > 0 && n_left_to_next > 0)
642 {
643 ip_lookup_next_t next0;
644 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500645 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100646 u32 pi0, lbi0, hc0;
647 const ip4_header_t *ip0;
648 const dpo_id_t *dpo0;
649
650 pi0 = from[0];
651 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000652 from += 1;
653 to_next += 1;
654 n_left_to_next -= 1;
655 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656
657 p0 = vlib_get_buffer (vm, pi0);
658
659 ip0 = vlib_buffer_get_current (p0);
660 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
661
Dave Barachd7cb1b52016-12-09 09:52:16 -0500662 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100663
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000664 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500665 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
666 {
667 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
668 {
669 hc0 = vnet_buffer (p0)->ip.flow_hash =
670 vnet_buffer (p0)->ip.flow_hash >> 1;
671 }
672 else
673 {
674 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000675 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500676 }
677 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000678
Dave Barachd7cb1b52016-12-09 09:52:16 -0500679 dpo0 =
680 load_balance_get_bucket_i (lb0,
681 hc0 & (lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100682
683 next0 = dpo0->dpoi_next_node;
684 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
685
Dave Barach75fc8542016-10-11 16:16:02 -0400686 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100688
Neale Ranns2be95c12016-11-19 13:50:04 +0000689 vlib_validate_buffer_enqueue_x1 (vm, node, next,
690 to_next, n_left_to_next,
691 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100692 }
693
694 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 }
696
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 return frame->n_vectors;
698}
699
Dave Barachd7cb1b52016-12-09 09:52:16 -0500700VLIB_REGISTER_NODE (ip4_load_balance_node) =
701{
702.function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
703 sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
704 format_ip4_lookup_trace,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100707
708/* get first interface address */
709ip4_address_t *
710ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500711 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100712{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500713 ip_lookup_main_t *lm = &im->lookup_main;
714 ip_interface_address_t *ia = 0;
715 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100716
Neale Ranns32e1c012016-11-22 17:07:28 +0000717 /* *INDENT-OFF* */
718 foreach_ip_interface_address
719 (lm, ia, sw_if_index,
720 1 /* honor unnumbered */ ,
721 ({
722 ip4_address_t * a =
723 ip_interface_address_get_address (lm, ia);
724 result = a;
725 break;
726 }));
727 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100728 if (result_ia)
729 *result_ia = result ? ia : 0;
730 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731}
732
733static void
734ip4_add_interface_routes (u32 sw_if_index,
735 ip4_main_t * im, u32 fib_index,
736 ip_interface_address_t * a)
737{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500738 ip_lookup_main_t *lm = &im->lookup_main;
739 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100740 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500741 .fp_len = a->address_length,
742 .fp_proto = FIB_PROTOCOL_IP4,
743 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100744 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
746 a->neighbor_probe_adj_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100748 if (pfx.fp_len < 32)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500749 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100750 fib_node_index_t fei;
751
Neale Ranns32e1c012016-11-22 17:07:28 +0000752 fei = fib_table_entry_update_one_path (fib_index, &pfx,
753 FIB_SOURCE_INTERFACE,
754 (FIB_ENTRY_FLAG_CONNECTED |
755 FIB_ENTRY_FLAG_ATTACHED),
756 FIB_PROTOCOL_IP4,
757 /* No next-hop address */
758 NULL,
759 sw_if_index,
760 // invalid FIB index
761 ~0,
762 1,
763 // no out-label stack
764 NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500765 FIB_ROUTE_PATH_FLAG_NONE);
766 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
767 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100768
769 pfx.fp_len = 32;
770
771 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500772 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100773 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500774 lm->classify_table_index_by_sw_if_index[sw_if_index];
775 if (classify_table_index != (u32) ~ 0)
776 {
777 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100778
Dave Barachd7cb1b52016-12-09 09:52:16 -0500779 dpo_set (&dpo,
780 DPO_CLASSIFY,
781 DPO_PROTO_IP4,
782 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100783
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 fib_table_entry_special_dpo_add (fib_index,
785 &pfx,
786 FIB_SOURCE_CLASSIFY,
787 FIB_ENTRY_FLAG_NONE, &dpo);
788 dpo_reset (&dpo);
789 }
790 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100791
Neale Ranns32e1c012016-11-22 17:07:28 +0000792 fib_table_entry_update_one_path (fib_index, &pfx,
793 FIB_SOURCE_INTERFACE,
794 (FIB_ENTRY_FLAG_CONNECTED |
795 FIB_ENTRY_FLAG_LOCAL),
796 FIB_PROTOCOL_IP4,
797 &pfx.fp_addr,
798 sw_if_index,
799 // invalid FIB index
800 ~0,
801 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500802 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803}
804
805static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100806ip4_del_interface_routes (ip4_main_t * im,
807 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500808 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500810 fib_prefix_t pfx = {
811 .fp_len = address_length,
812 .fp_proto = FIB_PROTOCOL_IP4,
813 .fp_addr.ip4 = *address,
814 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
Dave Barachd7cb1b52016-12-09 09:52:16 -0500816 if (pfx.fp_len < 32)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100817 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500818 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100819 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820
Dave Barachd7cb1b52016-12-09 09:52:16 -0500821 pfx.fp_len = 32;
822 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823}
824
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100825void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500826ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100827{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500828 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100830 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
831
832 /*
833 * enable/disable only on the 1<->0 transition
834 */
835 if (is_enable)
836 {
837 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500838 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100839 }
840 else
841 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500842 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100843 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500844 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100845 }
Damjan Marion4d489932016-12-09 03:21:27 -0800846 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
847 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100848
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100849
Neale Ranns32e1c012016-11-22 17:07:28 +0000850 vnet_feature_enable_disable ("ip4-multicast",
851 "ip4-mfib-forward-lookup",
852 sw_if_index, is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100853}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855static clib_error_t *
856ip4_add_del_interface_address_internal (vlib_main_t * vm,
857 u32 sw_if_index,
858 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500859 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700860{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500861 vnet_main_t *vnm = vnet_get_main ();
862 ip4_main_t *im = &ip4_main;
863 ip_lookup_main_t *lm = &im->lookup_main;
864 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500866 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867
868 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
869 ip4_addr_fib_init (&ip4_af, address,
870 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
871 vec_add1 (addr_fib, ip4_af);
872
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100873 /* FIXME-LATER
874 * there is no support for adj-fib handling in the presence of overlapping
875 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
876 * most routers do.
877 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000878 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500879 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100881 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500882 with an existing address. */
883 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000884 foreach_ip_interface_address
885 (&im->lookup_main, ia, sw_if_index,
886 0 /* honor unnumbered */ ,
887 ({
888 ip4_address_t * x =
889 ip_interface_address_get_address
890 (&im->lookup_main, ia);
891 if (ip4_destination_matches_route
892 (im, address, x, ia->address_length) ||
893 ip4_destination_matches_route (im,
894 x,
895 address,
896 address_length))
897 return
898 clib_error_create
899 ("failed to add %U which conflicts with %U for interface %U",
900 format_ip4_address_and_length, address,
901 address_length,
902 format_ip4_address_and_length, x,
903 ia->address_length,
904 format_vnet_sw_if_index_name, vnm,
905 sw_if_index);
906 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000908 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700909
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 elts_before = pool_elts (lm->if_address_pool);
911
912 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500913 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700914 if (error)
915 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100918
919 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500920 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100921 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922 ip4_add_interface_routes (sw_if_index,
923 im, ip4_af.fib_index,
924 pool_elt_at_index
925 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926
927 /* If pool did not grow/shrink: add duplicate address. */
928 if (elts_before != pool_elts (lm->if_address_pool))
929 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500930 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 vec_foreach (cb, im->add_del_interface_address_callbacks)
932 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500933 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934 }
935
Dave Barachd7cb1b52016-12-09 09:52:16 -0500936done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937 vec_free (addr_fib);
938 return error;
939}
940
941clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000942ip4_add_del_interface_address (vlib_main_t * vm,
943 u32 sw_if_index,
944 ip4_address_t * address,
945 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946{
947 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500948 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949}
950
Dave Barachd6534602016-06-14 18:38:02 -0400951/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100953VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
954{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500955 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100956 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -0800957 .end_node = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100958 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
959};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100960
Dave Barachd7cb1b52016-12-09 09:52:16 -0500961VNET_FEATURE_INIT (ip4_flow_classify, static) =
962{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100963 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700964 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100965 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700966};
967
Dave Barachd7cb1b52016-12-09 09:52:16 -0500968VNET_FEATURE_INIT (ip4_inacl, static) =
969{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100970 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400971 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100972 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400973};
974
Dave Barachd7cb1b52016-12-09 09:52:16 -0500975VNET_FEATURE_INIT (ip4_source_check_1, static) =
976{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100977 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400978 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100979 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400980};
981
Dave Barachd7cb1b52016-12-09 09:52:16 -0500982VNET_FEATURE_INIT (ip4_source_check_2, static) =
983{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100984 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400985 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100986 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400987};
988
Dave Barachd7cb1b52016-12-09 09:52:16 -0500989VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
990{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100991 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400992 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100993 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400994};
995
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996VNET_FEATURE_INIT (ip4_policer_classify, static) =
997{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100998 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700999 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001001};
1002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003VNET_FEATURE_INIT (ip4_ipsec, static) =
1004{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001005 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001006 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001007 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -04001008};
1009
Dave Barachd7cb1b52016-12-09 09:52:16 -05001010VNET_FEATURE_INIT (ip4_vpath, static) =
1011{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001012 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001013 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -05001014 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1015};
1016
Dave Barachd7cb1b52016-12-09 09:52:16 -05001017VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1018{
John Lo37682e12016-11-30 12:51:39 -05001019 .arc_name = "ip4-unicast",
1020 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001021 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001022};
1023
Dave Barachd7cb1b52016-12-09 09:52:16 -05001024VNET_FEATURE_INIT (ip4_lookup, static) =
1025{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001026 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001027 .node_name = "ip4-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001028 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001029};
1030
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031VNET_FEATURE_INIT (ip4_drop, static) =
1032{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001033 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001034 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 .runs_before = 0, /* not before any other features */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001036};
1037
1038
Dave Barachd6534602016-06-14 18:38:02 -04001039/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001040VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1041{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001043 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -08001044 .end_node = "ip4-lookup-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001045 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1046};
1047
Dave Barachd7cb1b52016-12-09 09:52:16 -05001048VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1049{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001050 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001051 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001052 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001053};
1054
Dave Barachd7cb1b52016-12-09 09:52:16 -05001055VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1056{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001057 .arc_name = "ip4-multicast",
Neale Ranns32e1c012016-11-22 17:07:28 +00001058 .node_name = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001059 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001060};
1061
Dave Barachd7cb1b52016-12-09 09:52:16 -05001062VNET_FEATURE_INIT (ip4_mc_drop, static) =
1063{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001064 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001065 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001066 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001067};
Dave Barach5331c722016-08-17 11:54:30 -04001068
1069/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001070VNET_FEATURE_ARC_INIT (ip4_output, static) =
1071{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001072 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001073 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion892e0762016-12-09 18:52:05 +01001074 .end_node = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001075 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1076};
Dave Barach5331c722016-08-17 11:54:30 -04001077
Dave Barachd7cb1b52016-12-09 09:52:16 -05001078VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1079{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001080 .arc_name = "ip4-output",
1081 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001082 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1083};
1084
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1086{
Matus Fabian08a6f012016-11-15 06:08:51 -08001087 .arc_name = "ip4-output",
1088 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001089 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001090};
1091
1092/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001093VNET_FEATURE_INIT (ip4_interface_output, static) =
1094{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001095 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001096 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001097 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001098};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001099/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001100
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001102ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001104 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001106 /* Fill in lookup tables with default table (0). */
1107 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001108 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001109
Damjan Marion8b3191e2016-11-09 19:54:20 +01001110 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1111 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112
Damjan Marion8b3191e2016-11-09 19:54:20 +01001113 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1114 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 return /* no error */ 0;
1117}
1118
1119VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1120
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121/* Global IP4 main. */
1122ip4_main_t ip4_main;
1123
1124clib_error_t *
1125ip4_lookup_init (vlib_main_t * vm)
1126{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001127 ip4_main_t *im = &ip4_main;
1128 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129 uword i;
1130
Damjan Marion8b3191e2016-11-09 19:54:20 +01001131 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1132 return error;
1133
Ed Warnickecb9cada2015-12-08 15:45:58 -07001134 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1135 {
1136 u32 m;
1137
1138 if (i < 32)
1139 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001140 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141 m = ~0;
1142 im->fib_masks[i] = clib_host_to_net_u32 (m);
1143 }
1144
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1146
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001147 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001149 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001150
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001152 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 pn = pg_get_node (ip4_lookup_node.index);
1154 pn->unformat_edit = unformat_pg_ip4_header;
1155 }
1156
1157 {
1158 ethernet_arp_header_t h;
1159
1160 memset (&h, 0, sizeof (h));
1161
1162 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163 memset (h.ip4_over_ethernet[1].ethernet, 0,
1164 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165
1166#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1167#define _8(f,v) h.f = v;
1168 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1169 _16 (l3_type, ETHERNET_TYPE_IP4);
1170 _8 (n_l2_address_bytes, 6);
1171 _8 (n_l3_address_bytes, 4);
1172 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1173#undef _16
1174#undef _8
1175
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177 /* data */ &h,
1178 sizeof (h),
1179 /* alloc chunk size */ 8,
1180 "ip4 arp");
1181 }
1182
Dave Barach203c6322016-06-26 10:29:03 -04001183 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184}
1185
1186VLIB_INIT_FUNCTION (ip4_lookup_init);
1187
Dave Barachd7cb1b52016-12-09 09:52:16 -05001188typedef struct
1189{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001191 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192 u32 flow_hash;
1193 u32 fib_index;
1194
1195 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001196 u8 packet_data[64 - 1 * sizeof (u32)];
1197}
1198ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
Dave Barachd7cb1b52016-12-09 09:52:16 -05001200u8 *
1201format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202{
1203 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1204 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001205 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001206 uword indent = format_get_indent (s);
1207 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001208 format_white_space, indent,
1209 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001210 return s;
1211}
1212
Dave Barachd7cb1b52016-12-09 09:52:16 -05001213static u8 *
1214format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001215{
1216 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1217 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001218 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 uword indent = format_get_indent (s);
1220
John Loac8146c2016-09-27 17:44:02 -04001221 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001223 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001224 format_white_space, indent,
1225 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001226 return s;
1227}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228
Dave Barachd7cb1b52016-12-09 09:52:16 -05001229static u8 *
1230format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001231{
1232 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1233 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001234 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1235 vnet_main_t *vnm = vnet_get_main ();
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001236 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237
Vengada Govindanf1544482016-09-28 02:45:57 -07001238 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001239 t->fib_index, t->dpo_index, format_ip_adjacency,
1240 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001241 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001242 format_white_space, indent,
1243 format_ip_adjacency_packet_data,
1244 vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245 return s;
1246}
1247
1248/* Common trace function for all ip4-forward next nodes. */
1249void
1250ip4_forward_next_trace (vlib_main_t * vm,
1251 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001252 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001254 u32 *from, n_left;
1255 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256
1257 n_left = frame->n_vectors;
1258 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001259
Ed Warnickecb9cada2015-12-08 15:45:58 -07001260 while (n_left >= 4)
1261 {
1262 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001263 vlib_buffer_t *b0, *b1;
1264 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001265
1266 /* Prefetch next iteration. */
1267 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1268 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1269
1270 bi0 = from[0];
1271 bi1 = from[1];
1272
1273 b0 = vlib_get_buffer (vm, bi0);
1274 b1 = vlib_get_buffer (vm, bi1);
1275
1276 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1277 {
1278 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001279 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001280 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001281 t0->fib_index =
1282 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1283 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1284 vec_elt (im->fib_index_by_sw_if_index,
1285 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001286
Damjan Marionf1213b82016-03-13 02:22:06 +01001287 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001288 vlib_buffer_get_current (b0),
1289 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290 }
1291 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1292 {
1293 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001294 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001296 t1->fib_index =
1297 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1298 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1299 vec_elt (im->fib_index_by_sw_if_index,
1300 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1301 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1302 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303 }
1304 from += 2;
1305 n_left -= 2;
1306 }
1307
1308 while (n_left >= 1)
1309 {
1310 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001311 vlib_buffer_t *b0;
1312 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313
1314 bi0 = from[0];
1315
1316 b0 = vlib_get_buffer (vm, bi0);
1317
1318 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1319 {
1320 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001321 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001322 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001323 t0->fib_index =
1324 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1325 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1326 vec_elt (im->fib_index_by_sw_if_index,
1327 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1328 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1329 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001330 }
1331 from += 1;
1332 n_left -= 1;
1333 }
1334}
1335
1336static uword
1337ip4_drop_or_punt (vlib_main_t * vm,
1338 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001339 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001341 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342 uword n_packets = frame->n_vectors;
1343
Dave Barachd7cb1b52016-12-09 09:52:16 -05001344 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001345 /* stride */ 1,
1346 n_packets,
1347 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001348 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349
1350 if (node->flags & VLIB_NODE_FLAG_TRACE)
1351 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1352
1353 return n_packets;
1354}
1355
1356static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001357ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1358{
1359 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1360}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001361
1362static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001363ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1364{
1365 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1366}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367
Neale Ranns32e1c012016-11-22 17:07:28 +00001368/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001369VLIB_REGISTER_NODE (ip4_drop_node, static) =
1370{
Neale Ranns32e1c012016-11-22 17:07:28 +00001371 .function = ip4_drop,.
1372 name = "ip4-drop",
1373 .vector_size = sizeof (u32),
1374 .format_trace = format_ip4_forward_next_trace,
1375 .n_next_nodes = 1,
1376 .next_nodes = {
1377 [0] = "error-drop",
1378 },
1379};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380
Dave Barachd7cb1b52016-12-09 09:52:16 -05001381VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382
Dave Barachd7cb1b52016-12-09 09:52:16 -05001383VLIB_REGISTER_NODE (ip4_punt_node, static) =
1384{
Neale Ranns32e1c012016-11-22 17:07:28 +00001385 .function = ip4_punt,
1386 .name = "ip4-punt",
1387 .vector_size = sizeof (u32),
1388 .format_trace = format_ip4_forward_next_trace,
1389 .n_next_nodes = 1,
1390 .next_nodes = {
1391 [0] = "error-punt",
1392 },
1393};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394
Dave Barachd7cb1b52016-12-09 09:52:16 -05001395VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Neale Ranns32e1c012016-11-22 17:07:28 +00001396/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02001397
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398/* Compute TCP/UDP/ICMP4 checksum in software. */
1399u16
1400ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1401 ip4_header_t * ip0)
1402{
1403 ip_csum_t sum0;
1404 u32 ip_header_length, payload_length_host_byte_order;
1405 u32 n_this_buffer, n_bytes_left;
1406 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001407 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001408
Ed Warnickecb9cada2015-12-08 15:45:58 -07001409 /* Initialize checksum with ip header. */
1410 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001411 payload_length_host_byte_order =
1412 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1413 sum0 =
1414 clib_host_to_net_u32 (payload_length_host_byte_order +
1415 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416
1417 if (BITS (uword) == 32)
1418 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001419 sum0 =
1420 ip_csum_with_carry (sum0,
1421 clib_mem_unaligned (&ip0->src_address, u32));
1422 sum0 =
1423 ip_csum_with_carry (sum0,
1424 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425 }
1426 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001427 sum0 =
1428 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429
1430 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1431 data_this_buffer = (void *) ip0 + ip_header_length;
1432 if (n_this_buffer + ip_header_length > p0->current_length)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001433 n_this_buffer =
1434 p0->current_length >
1435 ip_header_length ? p0->current_length - ip_header_length : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436 while (1)
1437 {
1438 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1439 n_bytes_left -= n_this_buffer;
1440 if (n_bytes_left == 0)
1441 break;
1442
1443 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1444 p0 = vlib_get_buffer (vm, p0->next_buffer);
1445 data_this_buffer = vlib_buffer_get_current (p0);
1446 n_this_buffer = p0->current_length;
1447 }
1448
Dave Barachd7cb1b52016-12-09 09:52:16 -05001449 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450
1451 return sum16;
1452}
1453
John Lo37682e12016-11-30 12:51:39 -05001454u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001455ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1456{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001457 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1458 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001459 u16 sum16;
1460
1461 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1462 || ip0->protocol == IP_PROTOCOL_UDP);
1463
1464 udp0 = (void *) (ip0 + 1);
1465 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1466 {
1467 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1468 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1469 return p0->flags;
1470 }
1471
1472 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1473
1474 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1475 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1476
1477 return p0->flags;
1478}
1479
Dave Barach68b0fb02017-02-28 15:15:56 -05001480/* *INDENT-OFF* */
1481VNET_FEATURE_ARC_INIT (ip4_local) =
1482{
1483 .arc_name = "ip4-local",
1484 .start_nodes = VNET_FEATURES ("ip4-local"),
1485};
1486/* *INDENT-ON* */
1487
1488static inline uword
1489ip4_local_inline (vlib_main_t * vm,
1490 vlib_node_runtime_t * node,
1491 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001493 ip4_main_t *im = &ip4_main;
1494 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001495 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001496 u32 *from, *to_next, n_left_from, n_left_to_next;
1497 vlib_node_runtime_t *error_node =
1498 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001499 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001500
1501 from = vlib_frame_vector_args (frame);
1502 n_left_from = frame->n_vectors;
1503 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001504
Ed Warnickecb9cada2015-12-08 15:45:58 -07001505 if (node->flags & VLIB_NODE_FLAG_TRACE)
1506 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1507
1508 while (n_left_from > 0)
1509 {
1510 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1511
1512 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001513 {
1514 vlib_buffer_t *p0, *p1;
1515 ip4_header_t *ip0, *ip1;
1516 udp_header_t *udp0, *udp1;
1517 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1518 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1519 const dpo_id_t *dpo0, *dpo1;
1520 const load_balance_t *lb0, *lb1;
1521 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1522 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1523 i32 len_diff0, len_diff1;
1524 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1525 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001526 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001527
Dave Barachd7cb1b52016-12-09 09:52:16 -05001528 pi0 = to_next[0] = from[0];
1529 pi1 = to_next[1] = from[1];
1530 from += 2;
1531 n_left_from -= 2;
1532 to_next += 2;
1533 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001534
Dave Barach68b0fb02017-02-28 15:15:56 -05001535 next0 = next1 = IP_LOCAL_NEXT_DROP;
1536
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537 p0 = vlib_get_buffer (vm, pi0);
1538 p1 = vlib_get_buffer (vm, pi1);
1539
1540 ip0 = vlib_buffer_get_current (p0);
1541 ip1 = vlib_buffer_get_current (p1);
1542
Dave Barachd7cb1b52016-12-09 09:52:16 -05001543 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1544 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001545
Dave Barach68b0fb02017-02-28 15:15:56 -05001546 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1547 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1548
1549 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1550 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1551
1552 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001553 fib_index0 =
1554 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1555 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001556
Dave Barach68b0fb02017-02-28 15:15:56 -05001557 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001558 fib_index1 =
1559 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1560 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001561
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001562 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1563 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001564
1565 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1566
Dave Barachd7cb1b52016-12-09 09:52:16 -05001567 leaf0 =
1568 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1569 leaf1 =
1570 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001571
John Lo3419d0b2016-06-02 09:28:37 -04001572 /* Treat IP frag packets as "experimental" protocol for now
1573 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001574 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1575 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001576
1577 if (head_of_feature_arc == 0)
1578 {
1579 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1580 goto skip_checks;
1581 }
1582
Ed Warnickecb9cada2015-12-08 15:45:58 -07001583 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1584 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1585 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1586 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1587
1588 flags0 = p0->flags;
1589 flags1 = p1->flags;
1590
1591 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1592 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1593
1594 udp0 = ip4_next_header (ip0);
1595 udp1 = ip4_next_header (ip1);
1596
1597 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1598 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1599 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1600
Dave Barachd7cb1b52016-12-09 09:52:16 -05001601 leaf0 =
1602 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1603 leaf1 =
1604 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605
1606 /* Verify UDP length. */
1607 ip_len0 = clib_net_to_host_u16 (ip0->length);
1608 ip_len1 = clib_net_to_host_u16 (ip1->length);
1609 udp_len0 = clib_net_to_host_u16 (udp0->length);
1610 udp_len1 = clib_net_to_host_u16 (udp1->length);
1611
1612 len_diff0 = ip_len0 - udp_len0;
1613 len_diff1 = ip_len1 - udp_len1;
1614
1615 len_diff0 = is_udp0 ? len_diff0 : 0;
1616 len_diff1 = is_udp1 ? len_diff1 : 0;
1617
Dave Barachd7cb1b52016-12-09 09:52:16 -05001618 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1619 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620 {
1621 if (is_tcp_udp0)
1622 {
1623 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001624 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1626 good_tcp_udp0 =
1627 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1628 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1629 }
1630 if (is_tcp_udp1)
1631 {
1632 if (is_tcp_udp1
Dave Barachd7cb1b52016-12-09 09:52:16 -05001633 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001634 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1635 good_tcp_udp1 =
1636 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1637 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1638 }
1639 }
1640
1641 good_tcp_udp0 &= len_diff0 >= 0;
1642 good_tcp_udp1 &= len_diff1 >= 0;
1643
Dave Barachd7cb1b52016-12-09 09:52:16 -05001644 leaf0 =
1645 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1646 leaf1 =
1647 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648
1649 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1650
1651 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1652 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1653
1654 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001655 error0 = (is_tcp_udp0 && !good_tcp_udp0
1656 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1657 error1 = (is_tcp_udp1 && !good_tcp_udp1
1658 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659
Dave Barachd7cb1b52016-12-09 09:52:16 -05001660 leaf0 =
1661 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1662 leaf1 =
1663 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
1664 leaf0 =
1665 (leaf0 ==
1666 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1667 leaf1 =
1668 (leaf1 ==
1669 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001670
Dave Barachd7cb1b52016-12-09 09:52:16 -05001671 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1672 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1673 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001674
Dave Barachd7cb1b52016-12-09 09:52:16 -05001675 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1676 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1677 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001678
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679 lb0 = load_balance_get (lbi0);
1680 lb1 = load_balance_get (lbi1);
1681 dpo0 = load_balance_get_bucket_i (lb0, 0);
1682 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001683
Dave Barach75fc8542016-10-11 16:16:02 -04001684 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001685 * Must have a route to source otherwise we drop the packet.
1686 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001687 *
1688 * The checks are:
1689 * - the source is a recieve => it's from us => bogus, do this
1690 * first since it sets a different error code.
1691 * - uRPF check for any route to source - accept if passes.
1692 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001693 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001694 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001695 dpo0->dpoi_type == DPO_RECEIVE) ?
1696 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1697 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1698 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001699 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001700 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001701 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 dpo1->dpoi_type == DPO_RECEIVE) ?
1703 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1704 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1705 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001706 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001707 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708
Florin Corasa0b34a72017-03-07 01:20:52 -08001709 skip_checks:
1710
Ed Warnickecb9cada2015-12-08 15:45:58 -07001711 next0 = lm->local_next_by_ip_protocol[proto0];
1712 next1 = lm->local_next_by_ip_protocol[proto1];
1713
Dave Barachd7cb1b52016-12-09 09:52:16 -05001714 next0 =
1715 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1716 next1 =
1717 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001718
1719 p0->error = error0 ? error_node->errors[error0] : 0;
1720 p1->error = error1 ? error_node->errors[error1] : 0;
1721
Dave Barach68b0fb02017-02-28 15:15:56 -05001722 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001723 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001724 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1725 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1726 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1727 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001729
1730 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1731 n_left_to_next, pi0, pi1,
1732 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733 }
1734
1735 while (n_left_from > 0 && n_left_to_next > 0)
1736 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001737 vlib_buffer_t *p0;
1738 ip4_header_t *ip0;
1739 udp_header_t *udp0;
1740 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001741 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001742 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743 i32 len_diff0;
1744 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001745 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001746 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001747 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001748
Ed Warnickecb9cada2015-12-08 15:45:58 -07001749 pi0 = to_next[0] = from[0];
1750 from += 1;
1751 n_left_from -= 1;
1752 to_next += 1;
1753 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001754
Dave Barach68b0fb02017-02-28 15:15:56 -05001755 next0 = IP_LOCAL_NEXT_DROP;
1756
Ed Warnickecb9cada2015-12-08 15:45:58 -07001757 p0 = vlib_get_buffer (vm, pi0);
1758
1759 ip0 = vlib_buffer_get_current (p0);
1760
Dave Barachd7cb1b52016-12-09 09:52:16 -05001761 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001762
Dave Barach68b0fb02017-02-28 15:15:56 -05001763 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1764
1765 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1766
Neale Ranns32e1c012016-11-22 17:07:28 +00001767 fib_index0 =
1768 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1769 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001770
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001771 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772
1773 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
1774
Dave Barachd7cb1b52016-12-09 09:52:16 -05001775 leaf0 =
1776 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777
John Lo3419d0b2016-06-02 09:28:37 -04001778 /* Treat IP frag packets as "experimental" protocol for now
1779 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001780 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001781
1782 if (head_of_feature_arc == 0)
1783 {
1784 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1785 goto skip_check;
1786 }
1787
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1789 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1790
1791 flags0 = p0->flags;
1792
1793 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1794
1795 udp0 = ip4_next_header (ip0);
1796
1797 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1798 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1799
Dave Barachd7cb1b52016-12-09 09:52:16 -05001800 leaf0 =
1801 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001802
1803 /* Verify UDP length. */
1804 ip_len0 = clib_net_to_host_u16 (ip0->length);
1805 udp_len0 = clib_net_to_host_u16 (udp0->length);
1806
1807 len_diff0 = ip_len0 - udp_len0;
1808
1809 len_diff0 = is_udp0 ? len_diff0 : 0;
1810
Dave Barachd7cb1b52016-12-09 09:52:16 -05001811 if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001812 {
1813 if (is_tcp_udp0)
1814 {
1815 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001816 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001817 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1818 good_tcp_udp0 =
1819 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1820 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1821 }
1822 }
1823
1824 good_tcp_udp0 &= len_diff0 >= 0;
1825
Dave Barachd7cb1b52016-12-09 09:52:16 -05001826 leaf0 =
1827 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001828
1829 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1830
1831 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1832
1833 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001834 error0 = (is_tcp_udp0 && !good_tcp_udp0
1835 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836
Dave Barachd7cb1b52016-12-09 09:52:16 -05001837 leaf0 =
1838 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1839 leaf0 =
1840 (leaf0 ==
1841 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001843 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001844 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001845
Dave Barachd7cb1b52016-12-09 09:52:16 -05001846 lb0 = load_balance_get (lbi0);
1847 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001848
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001849 vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001850 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851
Neale Ranns3ee44042016-10-03 13:05:48 +01001852 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001853 dpo0->dpoi_type == DPO_RECEIVE) ?
1854 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1855 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1856 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001857 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001858 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859
Dave Barach68b0fb02017-02-28 15:15:56 -05001860 skip_check:
1861
Ed Warnickecb9cada2015-12-08 15:45:58 -07001862 next0 = lm->local_next_by_ip_protocol[proto0];
1863
Dave Barachd7cb1b52016-12-09 09:52:16 -05001864 next0 =
1865 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868
Dave Barach68b0fb02017-02-28 15:15:56 -05001869 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001871 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1872 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001874
1875 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1876 n_left_to_next, pi0, next0);
1877
Ed Warnickecb9cada2015-12-08 15:45:58 -07001878 }
Dave Barach75fc8542016-10-11 16:16:02 -04001879
Ed Warnickecb9cada2015-12-08 15:45:58 -07001880 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1881 }
1882
1883 return frame->n_vectors;
1884}
1885
Dave Barach68b0fb02017-02-28 15:15:56 -05001886static uword
1887ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1888{
1889 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1890}
1891
1892/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001893VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001894{
Dave Barach68b0fb02017-02-28 15:15:56 -05001895 .function = ip4_local,
1896 .name = "ip4-local",
1897 .vector_size = sizeof (u32),
1898 .format_trace = format_ip4_forward_next_trace,
1899 .n_next_nodes = IP_LOCAL_N_NEXT,
1900 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001901 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001902 [IP_LOCAL_NEXT_DROP] = "error-drop",
1903 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1904 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1905 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",},
1906};
1907/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001908
1909VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1910
Dave Barach68b0fb02017-02-28 15:15:56 -05001911static uword
1912ip4_local_end_of_arc (vlib_main_t * vm,
1913 vlib_node_runtime_t * node, vlib_frame_t * frame)
1914{
1915 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1916}
1917
1918/* *INDENT-OFF* */
1919VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1920 .function = ip4_local_end_of_arc,
1921 .name = "ip4-local-end-of-arc",
1922 .vector_size = sizeof (u32),
1923
1924 .format_trace = format_ip4_forward_next_trace,
1925 .sibling_of = "ip4-local",
1926};
1927
1928VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1929
1930VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1931 .arc_name = "ip4-local",
1932 .node_name = "ip4-local-end-of-arc",
1933 .runs_before = 0, /* not before any other features */
1934};
1935/* *INDENT-ON* */
1936
Dave Barachd7cb1b52016-12-09 09:52:16 -05001937void
1938ip4_register_protocol (u32 protocol, u32 node_index)
1939{
1940 vlib_main_t *vm = vlib_get_main ();
1941 ip4_main_t *im = &ip4_main;
1942 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001943
1944 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001945 lm->local_next_by_ip_protocol[protocol] =
1946 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001947}
1948
1949static clib_error_t *
1950show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001951 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001952{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001953 ip4_main_t *im = &ip4_main;
1954 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001955 int i;
1956
1957 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001958 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001959 {
1960 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001961 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962 }
1963 return 0;
1964}
1965
1966
1967
Billy McFall0683c9c2016-10-13 08:27:31 -04001968/*?
1969 * Display the set of protocols handled by the local IPv4 stack.
1970 *
1971 * @cliexpar
1972 * Example of how to display local protocol table:
1973 * @cliexstart{show ip local}
1974 * Protocols handled by ip4_local
1975 * 1
1976 * 17
1977 * 47
1978 * @cliexend
1979?*/
1980/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981VLIB_CLI_COMMAND (show_ip_local, static) =
1982{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983 .path = "show ip local",
1984 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001985 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001986};
Billy McFall0683c9c2016-10-13 08:27:31 -04001987/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001988
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001989always_inline uword
1990ip4_arp_inline (vlib_main_t * vm,
1991 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001992 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001993{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001994 vnet_main_t *vnm = vnet_get_main ();
1995 ip4_main_t *im = &ip4_main;
1996 ip_lookup_main_t *lm = &im->lookup_main;
1997 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998 uword n_left_from, n_left_to_next_drop, next_index;
1999 static f64 time_last_seed_change = -1e100;
2000 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04002001 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002 f64 time_now;
2003
2004 if (node->flags & VLIB_NODE_FLAG_TRACE)
2005 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2006
2007 time_now = vlib_time_now (vm);
2008 if (time_now - time_last_seed_change > 1e-3)
2009 {
2010 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002011 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
2012 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
2014 hash_seeds[i] = r[i];
2015
2016 /* Mark all hash keys as been no-seen before. */
2017 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
2018 hash_bitmap[i] = 0;
2019
2020 time_last_seed_change = time_now;
2021 }
2022
2023 from = vlib_frame_vector_args (frame);
2024 n_left_from = frame->n_vectors;
2025 next_index = node->cached_next_index;
2026 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002027 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028
2029 while (n_left_from > 0)
2030 {
2031 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
2032 to_next_drop, n_left_to_next_drop);
2033
2034 while (n_left_from > 0 && n_left_to_next_drop > 0)
2035 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002036 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002037 ip_adjacency_t *adj0;
2038 vlib_buffer_t *p0;
2039 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002040 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041
2042 pi0 = from[0];
2043
2044 p0 = vlib_get_buffer (vm, pi0);
2045
2046 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2047 adj0 = ip_get_adjacency (lm, adj_index0);
2048 ip0 = vlib_buffer_get_current (p0);
2049
Ed Warnickecb9cada2015-12-08 15:45:58 -07002050 a0 = hash_seeds[0];
2051 b0 = hash_seeds[1];
2052 c0 = hash_seeds[2];
2053
2054 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2055 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2056
Dave Barachd7cb1b52016-12-09 09:52:16 -05002057 if (is_glean)
2058 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002059 /*
2060 * this is the Glean case, so we are ARPing for the
2061 * packet's destination
2062 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002063 a0 ^= ip0->dst_address.data_u32;
2064 }
2065 else
2066 {
2067 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2068 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069 b0 ^= sw_if_index0;
2070
2071 hash_v3_finalize32 (a0, b0, c0);
2072
2073 c0 &= BITS (hash_bitmap) - 1;
2074 c0 = c0 / BITS (uword);
2075 m0 = (uword) 1 << (c0 % BITS (uword));
2076
2077 bm0 = hash_bitmap[c0];
2078 drop0 = (bm0 & m0) != 0;
2079
2080 /* Mark it as seen. */
2081 hash_bitmap[c0] = bm0 | m0;
2082
2083 from += 1;
2084 n_left_from -= 1;
2085 to_next_drop[0] = pi0;
2086 to_next_drop += 1;
2087 n_left_to_next_drop -= 1;
2088
Dave Barachd7cb1b52016-12-09 09:52:16 -05002089 p0->error =
2090 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2091 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002092
Neale Rannsb80c5362016-10-08 13:03:40 +01002093 /*
2094 * the adj has been updated to a rewrite but the node the DPO that got
2095 * us here hasn't - yet. no big deal. we'll drop while we wait.
2096 */
2097 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2098 continue;
2099
Ed Warnickecb9cada2015-12-08 15:45:58 -07002100 if (drop0)
2101 continue;
2102
Dave Barachd7cb1b52016-12-09 09:52:16 -05002103 /*
2104 * Can happen if the control-plane is programming tables
2105 * with traffic flowing; at least that's today's lame excuse.
2106 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002107 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2108 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002109 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002110 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002111 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002112 else
2113 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002114 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002115 u32 bi0 = 0;
2116 vlib_buffer_t *b0;
2117 ethernet_arp_header_t *h0;
2118 vnet_hw_interface_t *hw_if0;
2119
2120 h0 =
2121 vlib_packet_template_get_packet (vm,
2122 &im->ip4_arp_request_packet_template,
2123 &bi0);
2124
2125 /* Add rewrite/encap string for ARP packet. */
2126 vnet_rewrite_one_header (adj0[0], h0,
2127 sizeof (ethernet_header_t));
2128
2129 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2130
2131 /* Src ethernet address in ARP header. */
2132 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2133 hw_if0->hw_address,
2134 sizeof (h0->ip4_over_ethernet[0].ethernet));
2135
2136 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002137 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002138 /* The interface's source address is stashed in the Glean Adj */
2139 h0->ip4_over_ethernet[0].ip4 =
2140 adj0->sub_type.glean.receive_addr.ip4;
2141
2142 /* Copy in destination address we are requesting. This is the
2143 * glean case, so it's the packet's destination.*/
2144 h0->ip4_over_ethernet[1].ip4.data_u32 =
2145 ip0->dst_address.data_u32;
2146 }
2147 else
2148 {
2149 /* Src IP address in ARP header. */
2150 if (ip4_src_address_for_packet (lm, sw_if_index0,
2151 &h0->
2152 ip4_over_ethernet[0].ip4))
2153 {
2154 /* No source address available */
2155 p0->error =
2156 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2157 vlib_buffer_free (vm, &bi0, 1);
2158 continue;
2159 }
2160
2161 /* Copy in destination address we are requesting from the
2162 incomplete adj */
2163 h0->ip4_over_ethernet[1].ip4.data_u32 =
2164 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002165 }
2166
Dave Barachd7cb1b52016-12-09 09:52:16 -05002167 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2168 b0 = vlib_get_buffer (vm, bi0);
2169 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2170
2171 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2172
2173 vlib_set_next_frame_buffer (vm, node,
2174 adj0->rewrite_header.next_index,
2175 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002176 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002177 }
2178
2179 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2180 }
2181
2182 return frame->n_vectors;
2183}
2184
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002185static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002186ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002187{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002188 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002189}
2190
2191static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002192ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002193{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002194 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002195}
2196
Dave Barachd7cb1b52016-12-09 09:52:16 -05002197static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2199 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2200 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2201 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2202 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002203 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204};
2205
Dave Barachd7cb1b52016-12-09 09:52:16 -05002206VLIB_REGISTER_NODE (ip4_arp_node) =
2207{
2208 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2209 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2210 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2211 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2212 {
2213 [IP4_ARP_NEXT_DROP] = "error-drop",}
2214,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002215
Dave Barachd7cb1b52016-12-09 09:52:16 -05002216VLIB_REGISTER_NODE (ip4_glean_node) =
2217{
2218 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2219 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2220 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2221 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2222 {
2223 [IP4_ARP_NEXT_DROP] = "error-drop",}
2224,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002225
Ed Warnickecb9cada2015-12-08 15:45:58 -07002226#define foreach_notrace_ip4_arp_error \
2227_(DROP) \
2228_(REQUEST_SENT) \
2229_(REPLICATE_DROP) \
2230_(REPLICATE_FAIL)
2231
Dave Barachd7cb1b52016-12-09 09:52:16 -05002232clib_error_t *
2233arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002234{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002235 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236
2237 /* don't trace ARP request packets */
2238#define _(a) \
2239 vnet_pcap_drop_trace_filter_add_del \
2240 (rt->errors[IP4_ARP_ERROR_##a], \
2241 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002242 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243#undef _
2244 return 0;
2245}
2246
Dave Barachd7cb1b52016-12-09 09:52:16 -05002247VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248
2249
2250/* Send an ARP request to see if given destination is reachable on given interface. */
2251clib_error_t *
2252ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2253{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002254 vnet_main_t *vnm = vnet_get_main ();
2255 ip4_main_t *im = &ip4_main;
2256 ethernet_arp_header_t *h;
2257 ip4_address_t *src;
2258 ip_interface_address_t *ia;
2259 ip_adjacency_t *adj;
2260 vnet_hw_interface_t *hi;
2261 vnet_sw_interface_t *si;
2262 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263 u32 bi = 0;
2264
2265 si = vnet_get_sw_interface (vnm, sw_if_index);
2266
2267 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2268 {
2269 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002270 format_ip4_address, dst,
2271 format_vnet_sw_if_index_name, vnm,
2272 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002273 }
2274
Dave Barachd7cb1b52016-12-09 09:52:16 -05002275 src =
2276 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2277 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 {
2279 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002280 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002281 (0,
2282 "no matching interface address for destination %U (interface %U)",
2283 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2284 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002285 }
2286
2287 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2288
Dave Barachd7cb1b52016-12-09 09:52:16 -05002289 h =
Neale Ranns32e1c012016-11-22 17:07:28 +00002290 vlib_packet_template_get_packet (vm,
2291 &im->ip4_arp_request_packet_template,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002292 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002293
2294 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2295
Dave Barachd7cb1b52016-12-09 09:52:16 -05002296 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2297 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298
2299 h->ip4_over_ethernet[0].ip4 = src[0];
2300 h->ip4_over_ethernet[1].ip4 = dst[0];
2301
2302 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002303 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2304 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002305
2306 /* Add encapsulation string for software interface (e.g. ethernet header). */
2307 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2308 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2309
2310 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002311 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2312 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313 to_next[0] = bi;
2314 f->n_vectors = 1;
2315 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2316 }
2317
2318 return /* no error */ 0;
2319}
2320
Dave Barachd7cb1b52016-12-09 09:52:16 -05002321typedef enum
2322{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002323 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002324 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002325} ip4_rewrite_next_t;
2326
2327always_inline uword
2328ip4_rewrite_inline (vlib_main_t * vm,
2329 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002330 vlib_frame_t * frame,
2331 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002333 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2334 u32 *from = vlib_frame_vector_args (frame);
2335 u32 n_left_from, n_left_to_next, *to_next, next_index;
2336 vlib_node_runtime_t *error_node =
2337 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002338
2339 n_left_from = frame->n_vectors;
2340 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002341 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04002342
Ed Warnickecb9cada2015-12-08 15:45:58 -07002343 while (n_left_from > 0)
2344 {
2345 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2346
2347 while (n_left_from >= 4 && n_left_to_next >= 2)
2348 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002349 ip_adjacency_t *adj0, *adj1;
2350 vlib_buffer_t *p0, *p1;
2351 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002352 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2353 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002354 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002355
Ed Warnickecb9cada2015-12-08 15:45:58 -07002356 /* Prefetch next iteration. */
2357 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002358 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002359
2360 p2 = vlib_get_buffer (vm, from[2]);
2361 p3 = vlib_get_buffer (vm, from[3]);
2362
2363 vlib_prefetch_buffer_header (p2, STORE);
2364 vlib_prefetch_buffer_header (p3, STORE);
2365
2366 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2367 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2368 }
2369
2370 pi0 = to_next[0] = from[0];
2371 pi1 = to_next[1] = from[1];
2372
2373 from += 2;
2374 n_left_from -= 2;
2375 to_next += 2;
2376 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002377
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378 p0 = vlib_get_buffer (vm, pi0);
2379 p1 = vlib_get_buffer (vm, pi1);
2380
Neale Rannsf06aea52016-11-29 06:51:37 -08002381 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2382 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002383
Dave Barachd7cb1b52016-12-09 09:52:16 -05002384 /* We should never rewrite a pkt using the MISS adjacency */
2385 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386
2387 ip0 = vlib_buffer_get_current (p0);
2388 ip1 = vlib_buffer_get_current (p1);
2389
2390 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002391 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392
2393 /* Decrement TTL & update checksum.
2394 Works either endian, so no need for byte swap. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002395 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002396 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002397 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398
2399 /* Input node should have reject packets with ttl 0. */
2400 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401
2402 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002404
2405 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002407 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002408
Dave Barachd7cb1b52016-12-09 09:52:16 -05002409 /*
2410 * If the ttl drops below 1 when forwarding, generate
2411 * an ICMP response.
2412 */
2413 if (PREDICT_FALSE (ttl0 <= 0))
2414 {
2415 error0 = IP4_ERROR_TIME_EXPIRED;
2416 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2417 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2418 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2419 0);
2420 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2421 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002422
2423 /* Verify checksum. */
2424 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2425 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002426 else
2427 {
2428 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2429 }
2430 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002431 {
2432 i32 ttl1 = ip1->ttl;
2433
2434 /* Input node should have reject packets with ttl 0. */
2435 ASSERT (ip1->ttl > 0);
2436
2437 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2438 checksum1 += checksum1 >= 0xffff;
2439
2440 ip1->checksum = checksum1;
2441 ttl1 -= 1;
2442 ip1->ttl = ttl1;
2443
Dave Barachd7cb1b52016-12-09 09:52:16 -05002444 /*
2445 * If the ttl drops below 1 when forwarding, generate
2446 * an ICMP response.
2447 */
2448 if (PREDICT_FALSE (ttl1 <= 0))
2449 {
2450 error1 = IP4_ERROR_TIME_EXPIRED;
2451 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2452 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2453 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2454 0);
2455 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2456 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002457
2458 /* Verify checksum. */
2459 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2460 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2461 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002462 else
2463 {
2464 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2465 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002466
2467 /* Rewrite packet header and updates lengths. */
2468 adj0 = ip_get_adjacency (lm, adj_index0);
2469 adj1 = ip_get_adjacency (lm, adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002470
Dave Barachd7cb1b52016-12-09 09:52:16 -05002471 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002472 rw_len0 = adj0[0].rewrite_header.data_bytes;
2473 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002474 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2475 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002476
Dave Barachd7cb1b52016-12-09 09:52:16 -05002477 /* Check MTU of outgoing interface. */
2478 error0 =
2479 (vlib_buffer_length_in_chain (vm, p0) >
2480 adj0[0].
2481 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2482 error0);
2483 error1 =
2484 (vlib_buffer_length_in_chain (vm, p1) >
2485 adj1[0].
2486 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2487 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002488
Dave Barachd7cb1b52016-12-09 09:52:16 -05002489 /*
Neale Ranns044183f2017-01-24 01:34:25 -08002490 * pre-fetch the per-adjacency counters
Dave Barachd7cb1b52016-12-09 09:52:16 -05002491 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002492 if (do_counters)
2493 {
2494 vlib_prefetch_combined_counter (&adjacency_counters,
2495 cpu_index, adj_index0);
2496 vlib_prefetch_combined_counter (&adjacency_counters,
2497 cpu_index, adj_index1);
2498 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499
Dave Barachd7cb1b52016-12-09 09:52:16 -05002500 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2501 * to see the IP headerr */
2502 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2503 {
Damjan Marion892e0762016-12-09 18:52:05 +01002504 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002505 p0->current_data -= rw_len0;
2506 p0->current_length += rw_len0;
2507 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2508 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002509
Dave Barachd7cb1b52016-12-09 09:52:16 -05002510 vnet_feature_arc_start (lm->output_feature_arc_index,
2511 tx_sw_if_index0, &next0, p0);
2512 }
2513 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2514 {
Damjan Marion892e0762016-12-09 18:52:05 +01002515 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002516 p1->current_data -= rw_len1;
2517 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002518
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2520 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002521
Dave Barachd7cb1b52016-12-09 09:52:16 -05002522 vnet_feature_arc_start (lm->output_feature_arc_index,
2523 tx_sw_if_index1, &next1, p1);
2524 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002525
2526 /* Guess we are only writing on simple Ethernet header. */
2527 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002528 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002529
Neale Ranns044183f2017-01-24 01:34:25 -08002530 /*
2531 * Bump the per-adjacency counters
2532 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002533 if (do_counters)
2534 {
2535 vlib_increment_combined_counter
2536 (&adjacency_counters,
2537 cpu_index,
2538 adj_index0, 1,
2539 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002540
Neale Ranns9c6a6132017-02-21 05:33:14 -08002541 vlib_increment_combined_counter
2542 (&adjacency_counters,
2543 cpu_index,
2544 adj_index1, 1,
2545 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2546 }
Neale Ranns044183f2017-01-24 01:34:25 -08002547
Neale Ranns5e575b12016-10-03 09:40:25 +01002548 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002549 {
2550 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2551 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2552 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002553 if (is_mcast)
2554 {
2555 /*
2556 * copy bytes from the IP address into the MAC rewrite
2557 */
2558 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2559 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 1);
2560 }
Dave Barach75fc8542016-10-11 16:16:02 -04002561
Ed Warnickecb9cada2015-12-08 15:45:58 -07002562 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2563 to_next, n_left_to_next,
2564 pi0, pi1, next0, next1);
2565 }
2566
2567 while (n_left_from > 0 && n_left_to_next > 0)
2568 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002569 ip_adjacency_t *adj0;
2570 vlib_buffer_t *p0;
2571 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002572 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002573 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002574
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575 pi0 = to_next[0] = from[0];
2576
2577 p0 = vlib_get_buffer (vm, pi0);
2578
Neale Rannsf06aea52016-11-29 06:51:37 -08002579 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002580
Dave Barachd7cb1b52016-12-09 09:52:16 -05002581 /* We should never rewrite a pkt using the MISS adjacency */
2582 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002583
2584 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002585
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586 ip0 = vlib_buffer_get_current (p0);
2587
2588 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002589 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002590
2591 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002592 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002593 {
2594 i32 ttl0 = ip0->ttl;
2595
2596 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2597
2598 checksum0 += checksum0 >= 0xffff;
2599
2600 ip0->checksum = checksum0;
2601
2602 ASSERT (ip0->ttl > 0);
2603
2604 ttl0 -= 1;
2605
2606 ip0->ttl = ttl0;
2607
2608 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2609
Dave Barachd7cb1b52016-12-09 09:52:16 -05002610 if (PREDICT_FALSE (ttl0 <= 0))
2611 {
2612 /*
2613 * If the ttl drops below 1 when forwarding, generate
2614 * an ICMP response.
2615 */
2616 error0 = IP4_ERROR_TIME_EXPIRED;
2617 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2618 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2619 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2620 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2621 0);
2622 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002623 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002624 else
2625 {
2626 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2627 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002628
Neale Ranns044183f2017-01-24 01:34:25 -08002629 vlib_prefetch_combined_counter (&adjacency_counters,
2630 cpu_index, adj_index0);
2631
Ed Warnickecb9cada2015-12-08 15:45:58 -07002632 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002633 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002634 if (is_mcast)
2635 {
2636 /*
2637 * copy bytes from the IP address into the MAC rewrite
2638 */
2639 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2640 }
Dave Barach75fc8542016-10-11 16:16:02 -04002641
Dave Barachd7cb1b52016-12-09 09:52:16 -05002642 /* Update packet buffer attributes/set output interface. */
2643 rw_len0 = adj0[0].rewrite_header.data_bytes;
2644 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002645
Neale Ranns044183f2017-01-24 01:34:25 -08002646 vlib_increment_combined_counter
2647 (&adjacency_counters,
2648 cpu_index,
2649 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002650
Dave Barachd7cb1b52016-12-09 09:52:16 -05002651 /* Check MTU of outgoing interface. */
2652 error0 = (vlib_buffer_length_in_chain (vm, p0)
2653 > adj0[0].rewrite_header.max_l3_packet_bytes
2654 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002655
Ed Warnickecb9cada2015-12-08 15:45:58 -07002656 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002657
Dave Barachd7cb1b52016-12-09 09:52:16 -05002658 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2659 * to see the IP headerr */
2660 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2661 {
2662 p0->current_data -= rw_len0;
2663 p0->current_length += rw_len0;
2664 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002665
Dave Barachd7cb1b52016-12-09 09:52:16 -05002666 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2667 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002668
Neale Ranns5e575b12016-10-03 09:40:25 +01002669 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002670 {
2671 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002672 }
2673
Dave Barachd7cb1b52016-12-09 09:52:16 -05002674 vnet_feature_arc_start (lm->output_feature_arc_index,
2675 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002676
Dave Barachd7cb1b52016-12-09 09:52:16 -05002677 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002678
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679 from += 1;
2680 n_left_from -= 1;
2681 to_next += 1;
2682 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002683
Ed Warnickecb9cada2015-12-08 15:45:58 -07002684 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2685 to_next, n_left_to_next,
2686 pi0, next0);
2687 }
Dave Barach75fc8542016-10-11 16:16:02 -04002688
Ed Warnickecb9cada2015-12-08 15:45:58 -07002689 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2690 }
2691
2692 /* Need to do trace after rewrites to pick up new packet data. */
2693 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002694 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002695
2696 return frame->n_vectors;
2697}
2698
Dave Barach132d51d2016-07-07 10:10:17 -04002699
Neale Rannsf06aea52016-11-29 06:51:37 -08002700/** @brief IPv4 rewrite node.
2701 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002702
2703 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2704 header checksum, fetch the ip adjacency, check the outbound mtu,
2705 apply the adjacency rewrite, and send pkts to the adjacency
2706 rewrite header's rewrite_next_index.
2707
2708 @param vm vlib_main_t corresponding to the current thread
2709 @param node vlib_node_runtime_t
2710 @param frame vlib_frame_t whose contents should be dispatched
2711
2712 @par Graph mechanics: buffer metadata, next index usage
2713
2714 @em Uses:
2715 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2716 - the rewrite adjacency index
2717 - <code>adj->lookup_next_index</code>
2718 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002719 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002720 - <code>adj->rewrite_header</code>
2721 - Rewrite string length, rewrite string, next_index
2722
2723 @em Sets:
2724 - <code>b->current_data, b->current_length</code>
2725 - Updated net of applying the rewrite string
2726
2727 <em>Next Indices:</em>
2728 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002729 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002730*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002731static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002732ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002733 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002734{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002735 if (adj_are_counters_enabled ())
2736 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2737 else
2738 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002739}
2740
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002741static uword
2742ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002743 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002744{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002745 if (adj_are_counters_enabled ())
2746 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2747 else
2748 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002749}
2750
Neale Ranns32e1c012016-11-22 17:07:28 +00002751static uword
2752ip4_rewrite_mcast (vlib_main_t * vm,
2753 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002754{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002755 if (adj_are_counters_enabled ())
2756 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2757 else
2758 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002759}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002760
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
2787VLIB_REGISTER_NODE (ip4_midchain_node) = {
2788 .function = ip4_midchain,
2789 .name = "ip4-midchain",
2790 .vector_size = sizeof (u32),
2791 .format_trace = format_ip4_forward_next_trace,
2792 .sibling_of = "ip4-rewrite",
2793};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002794VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002795/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002796
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797static clib_error_t *
2798add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002799 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002801 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002802 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002803 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002804 u32 sw_if_index, table_id;
2805
2806 sw_if_index = ~0;
2807
Dave Barachd7cb1b52016-12-09 09:52:16 -05002808 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002809 {
2810 error = clib_error_return (0, "unknown interface `%U'",
2811 format_unformat_error, input);
2812 goto done;
2813 }
2814
2815 if (unformat (input, "%d", &table_id))
2816 ;
2817 else
2818 {
2819 error = clib_error_return (0, "expected table id `%U'",
2820 format_unformat_error, input);
2821 goto done;
2822 }
2823
Neale Ranns4008ac92017-02-13 23:20:04 -08002824 /*
2825 * If the interface already has in IP address, then a change int
2826 * VRF is not allowed. The IP address applied must first be removed.
2827 * We do not do that automatically here, since VPP has no knowledge
2828 * of whether thoses subnets are valid in the destination VRF.
2829 */
2830 /* *INDENT-OFF* */
2831 foreach_ip_interface_address (&ip4_main.lookup_main,
2832 ia, sw_if_index,
2833 1 /* honor unnumbered */,
2834 ({
2835 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002836
Neale Ranns4008ac92017-02-13 23:20:04 -08002837 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2838 error = clib_error_return (0, "interface %U has address %U",
2839 format_vnet_sw_if_index_name, vnm,
2840 sw_if_index,
2841 format_ip4_address, a);
2842 goto done;
2843 }));
2844 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002845
Neale Ranns4008ac92017-02-13 23:20:04 -08002846{
2847 ip4_main_t *im = &ip4_main;
2848 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002849
Neale Ranns4008ac92017-02-13 23:20:04 -08002850 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2851
2852 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2853 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2854
2855 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2856 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2857 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2858}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002859
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002861return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002862}
2863
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002864/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002865 * Place the indicated interface into the supplied IPv4 FIB table (also known
2866 * as a VRF). If the FIB table does not exist, this command creates it. To
2867 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2868 * FIB table will only be displayed if a route has been added to the table, or
2869 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002870 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002871 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002872 * @note IP addresses added after setting the interface IP table are added to
2873 * the indicated FIB table. If an IP address is added prior to changing the
2874 * table then this is an error. The control plane must remove these addresses
2875 * first and then change the table. VPP will not automatically move the
2876 * addresses from the old to the new table as it does not know the validity
2877 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002878 *
2879 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002880 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2881 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002882 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002883/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002884VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2885{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002886 .path = "set interface ip table",
2887 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002888 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889};
Billy McFall0683c9c2016-10-13 08:27:31 -04002890/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002891
Dave Barachd7cb1b52016-12-09 09:52:16 -05002892int
2893ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2894{
2895 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002896 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002897 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002898
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002899 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002900
2901 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2902 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
2903 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
2904 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2905 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002906
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907 /* Handle default route. */
2908 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002909
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002910 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002911
Dave Barachd7cb1b52016-12-09 09:52:16 -05002912 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002913}
Dave Barach75fc8542016-10-11 16:16:02 -04002914
Ed Warnickecb9cada2015-12-08 15:45:58 -07002915static clib_error_t *
2916test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002917 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002918{
Billy McFall309fe062016-10-14 07:37:33 -04002919 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002920 u32 table_id = 0;
2921 f64 count = 1;
2922 u32 n;
2923 int i;
2924 ip4_address_t ip4_base_address;
2925 u64 errors = 0;
2926
Dave Barachd7cb1b52016-12-09 09:52:16 -05002927 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2928 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002929 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002930 {
2931 /* Make sure the entry exists. */
2932 fib = ip4_fib_get (table_id);
2933 if ((fib) && (fib->index != table_id))
2934 return clib_error_return (0, "<fib-index> %d does not exist",
2935 table_id);
2936 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002937 else if (unformat (input, "count %f", &count))
2938 ;
2939
2940 else if (unformat (input, "%U",
2941 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002942 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002943 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002944 return clib_error_return (0, "unknown input `%U'",
2945 format_unformat_error, input);
2946 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002947
2948 n = count;
2949
2950 for (i = 0; i < n; i++)
2951 {
2952 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002953 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954
Dave Barach75fc8542016-10-11 16:16:02 -04002955 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002956 clib_host_to_net_u32 (1 +
2957 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002958 }
2959
Dave Barach75fc8542016-10-11 16:16:02 -04002960 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002961 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2962 else
2963 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2964
2965 return 0;
2966}
2967
Billy McFall0683c9c2016-10-13 08:27:31 -04002968/*?
2969 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2970 * given FIB table to determine if there is a conflict with the
2971 * adjacency table. The fib-id can be determined by using the
2972 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2973 * of 0 is used.
2974 *
2975 * @todo This command uses fib-id, other commands use table-id (not
2976 * just a name, they are different indexes). Would like to change this
2977 * to table-id for consistency.
2978 *
2979 * @cliexpar
2980 * Example of how to run the test lookup command:
2981 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2982 * No errors in 2 lookups
2983 * @cliexend
2984?*/
2985/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002986VLIB_CLI_COMMAND (lookup_test_command, static) =
2987{
2988 .path = "test lookup",
2989 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2990 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991};
Billy McFall0683c9c2016-10-13 08:27:31 -04002992/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002993
Dave Barachd7cb1b52016-12-09 09:52:16 -05002994int
2995vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002996{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002997 ip4_main_t *im4 = &ip4_main;
2998 ip4_fib_t *fib;
2999 uword *p = hash_get (im4->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003000
3001 if (p == 0)
3002 return VNET_API_ERROR_NO_SUCH_FIB;
3003
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003004 fib = ip4_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003005
3006 fib->flow_hash_config = flow_hash_config;
3007 return 0;
3008}
Dave Barach75fc8542016-10-11 16:16:02 -04003009
Ed Warnickecb9cada2015-12-08 15:45:58 -07003010static clib_error_t *
3011set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003012 unformat_input_t * input,
3013 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014{
3015 int matched = 0;
3016 u32 table_id = 0;
3017 u32 flow_hash_config = 0;
3018 int rv;
3019
Dave Barachd7cb1b52016-12-09 09:52:16 -05003020 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3021 {
3022 if (unformat (input, "table %d", &table_id))
3023 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024#define _(a,v) \
3025 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003026 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003028 else
3029 break;
3030 }
Dave Barach75fc8542016-10-11 16:16:02 -04003031
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032 if (matched == 0)
3033 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003034 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003035
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3037 switch (rv)
3038 {
3039 case 0:
3040 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003041
Ed Warnickecb9cada2015-12-08 15:45:58 -07003042 case VNET_API_ERROR_NO_SUCH_FIB:
3043 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003044
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045 default:
3046 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3047 break;
3048 }
Dave Barach75fc8542016-10-11 16:16:02 -04003049
Ed Warnickecb9cada2015-12-08 15:45:58 -07003050 return 0;
3051}
Dave Barach75fc8542016-10-11 16:16:02 -04003052
Billy McFall0683c9c2016-10-13 08:27:31 -04003053/*?
3054 * Configure the set of IPv4 fields used by the flow hash.
3055 *
3056 * @cliexpar
3057 * Example of how to set the flow hash on a given table:
3058 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3059 * Example of display the configured flow hash:
3060 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003061 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3062 * 0.0.0.0/0
3063 * unicast-ip4-chain
3064 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3065 * [0] [@0]: dpo-drop ip6
3066 * 0.0.0.0/32
3067 * unicast-ip4-chain
3068 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3069 * [0] [@0]: dpo-drop ip6
3070 * 224.0.0.0/8
3071 * unicast-ip4-chain
3072 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3073 * [0] [@0]: dpo-drop ip6
3074 * 6.0.1.2/32
3075 * unicast-ip4-chain
3076 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3077 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3078 * 7.0.0.1/32
3079 * unicast-ip4-chain
3080 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3081 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3082 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3083 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3084 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3085 * 240.0.0.0/8
3086 * unicast-ip4-chain
3087 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3088 * [0] [@0]: dpo-drop ip6
3089 * 255.255.255.255/32
3090 * unicast-ip4-chain
3091 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3092 * [0] [@0]: dpo-drop ip6
3093 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3094 * 0.0.0.0/0
3095 * unicast-ip4-chain
3096 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3097 * [0] [@0]: dpo-drop ip6
3098 * 0.0.0.0/32
3099 * unicast-ip4-chain
3100 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3101 * [0] [@0]: dpo-drop ip6
3102 * 172.16.1.0/24
3103 * unicast-ip4-chain
3104 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3105 * [0] [@4]: ipv4-glean: af_packet0
3106 * 172.16.1.1/32
3107 * unicast-ip4-chain
3108 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3109 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3110 * 172.16.1.2/32
3111 * unicast-ip4-chain
3112 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3113 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3114 * 172.16.2.0/24
3115 * unicast-ip4-chain
3116 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3117 * [0] [@4]: ipv4-glean: af_packet1
3118 * 172.16.2.1/32
3119 * unicast-ip4-chain
3120 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3121 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3122 * 224.0.0.0/8
3123 * unicast-ip4-chain
3124 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3125 * [0] [@0]: dpo-drop ip6
3126 * 240.0.0.0/8
3127 * unicast-ip4-chain
3128 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3129 * [0] [@0]: dpo-drop ip6
3130 * 255.255.255.255/32
3131 * unicast-ip4-chain
3132 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3133 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003134 * @cliexend
3135?*/
3136/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003137VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3138{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003140 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003141 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003142 .function = set_ip_flow_hash_command_fn,
3143};
Billy McFall0683c9c2016-10-13 08:27:31 -04003144/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003145
Dave Barachd7cb1b52016-12-09 09:52:16 -05003146int
3147vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3148 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003150 vnet_main_t *vnm = vnet_get_main ();
3151 vnet_interface_main_t *im = &vnm->interface_main;
3152 ip4_main_t *ipm = &ip4_main;
3153 ip_lookup_main_t *lm = &ipm->lookup_main;
3154 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003155 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003156
3157 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3158 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3159
3160 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3161 return VNET_API_ERROR_NO_SUCH_ENTRY;
3162
3163 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003164 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003165
Neale Rannsdf089a82016-10-02 16:39:06 +01003166 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3167
3168 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003169 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003170 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003171 .fp_len = 32,
3172 .fp_proto = FIB_PROTOCOL_IP4,
3173 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003174 };
3175 u32 fib_index;
3176
Dave Barachd7cb1b52016-12-09 09:52:16 -05003177 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3178 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003179
3180
Dave Barachd7cb1b52016-12-09 09:52:16 -05003181 if (table_index != (u32) ~ 0)
3182 {
3183 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003184
Dave Barachd7cb1b52016-12-09 09:52:16 -05003185 dpo_set (&dpo,
3186 DPO_CLASSIFY,
3187 DPO_PROTO_IP4,
3188 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003189
Dave Barachd7cb1b52016-12-09 09:52:16 -05003190 fib_table_entry_special_dpo_add (fib_index,
3191 &pfx,
3192 FIB_SOURCE_CLASSIFY,
3193 FIB_ENTRY_FLAG_NONE, &dpo);
3194 dpo_reset (&dpo);
3195 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003196 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003197 {
3198 fib_table_entry_special_remove (fib_index,
3199 &pfx, FIB_SOURCE_CLASSIFY);
3200 }
3201 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003202
Ed Warnickecb9cada2015-12-08 15:45:58 -07003203 return 0;
3204}
3205
3206static clib_error_t *
3207set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003208 unformat_input_t * input,
3209 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003210{
3211 u32 table_index = ~0;
3212 int table_index_set = 0;
3213 u32 sw_if_index = ~0;
3214 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003215
Dave Barachd7cb1b52016-12-09 09:52:16 -05003216 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3217 {
3218 if (unformat (input, "table-index %d", &table_index))
3219 table_index_set = 1;
3220 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3221 vnet_get_main (), &sw_if_index))
3222 ;
3223 else
3224 break;
3225 }
Dave Barach75fc8542016-10-11 16:16:02 -04003226
Ed Warnickecb9cada2015-12-08 15:45:58 -07003227 if (table_index_set == 0)
3228 return clib_error_return (0, "classify table-index must be specified");
3229
3230 if (sw_if_index == ~0)
3231 return clib_error_return (0, "interface / subif must be specified");
3232
3233 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3234
3235 switch (rv)
3236 {
3237 case 0:
3238 break;
3239
3240 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3241 return clib_error_return (0, "No such interface");
3242
3243 case VNET_API_ERROR_NO_SUCH_ENTRY:
3244 return clib_error_return (0, "No such classifier table");
3245 }
3246 return 0;
3247}
3248
Billy McFall0683c9c2016-10-13 08:27:31 -04003249/*?
3250 * Assign a classification table to an interface. The classification
3251 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3252 * commands. Once the table is create, use this command to filter packets
3253 * on an interface.
3254 *
3255 * @cliexpar
3256 * Example of how to assign a classification table to an interface:
3257 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3258?*/
3259/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003260VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3261{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003262 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003263 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003264 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003265 .function = set_ip_classify_command_fn,
3266};
Billy McFall0683c9c2016-10-13 08:27:31 -04003267/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003268
3269/*
3270 * fd.io coding-style-patch-verification: ON
3271 *
3272 * Local Variables:
3273 * eval: (c-set-style "gnu")
3274 * End:
3275 */