blob: fe4d6767d0c686e3d3cdaa3387b02bb2b6e7c211 [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 */
589 hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
590 hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000591
Dave Barachd7cb1b52016-12-09 09:52:16 -0500592 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
593 {
594 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
595 {
596 hc0 = vnet_buffer (p0)->ip.flow_hash =
597 vnet_buffer (p0)->ip.flow_hash >> 1;
598 }
599 else
600 {
601 hc0 = vnet_buffer (p0)->ip.flow_hash =
602 ip4_compute_flow_hash (ip0, hc0);
603 }
604 }
605 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
606 {
607 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
608 {
609 hc1 = vnet_buffer (p1)->ip.flow_hash =
610 vnet_buffer (p1)->ip.flow_hash >> 1;
611 }
612 else
613 {
614 hc1 = vnet_buffer (p1)->ip.flow_hash =
615 ip4_compute_flow_hash (ip1, hc1);
616 }
617 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000618
Dave Barachd7cb1b52016-12-09 09:52:16 -0500619 dpo0 =
620 load_balance_get_bucket_i (lb0,
621 hc0 & (lb0->lb_n_buckets_minus_1));
622 dpo1 =
623 load_balance_get_bucket_i (lb1,
624 hc1 & (lb1->lb_n_buckets_minus_1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000625
626 next0 = dpo0->dpoi_next_node;
627 next1 = dpo1->dpoi_next_node;
628
629 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
630 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
631
632 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500633 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000634 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500635 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000636
637 vlib_validate_buffer_enqueue_x2 (vm, node, next,
638 to_next, n_left_to_next,
639 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500640 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000641
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642 while (n_left_from > 0 && n_left_to_next > 0)
643 {
644 ip_lookup_next_t next0;
645 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500646 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100647 u32 pi0, lbi0, hc0;
648 const ip4_header_t *ip0;
649 const dpo_id_t *dpo0;
650
651 pi0 = from[0];
652 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000653 from += 1;
654 to_next += 1;
655 n_left_to_next -= 1;
656 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100657
658 p0 = vlib_get_buffer (vm, pi0);
659
660 ip0 = vlib_buffer_get_current (p0);
661 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
662
Dave Barachd7cb1b52016-12-09 09:52:16 -0500663 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100664
Dave Barachd7cb1b52016-12-09 09:52:16 -0500665 hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
666 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
667 {
668 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
669 {
670 hc0 = vnet_buffer (p0)->ip.flow_hash =
671 vnet_buffer (p0)->ip.flow_hash >> 1;
672 }
673 else
674 {
675 hc0 = vnet_buffer (p0)->ip.flow_hash =
676 ip4_compute_flow_hash (ip0, hc0);
677 }
678 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000679
Dave Barachd7cb1b52016-12-09 09:52:16 -0500680 dpo0 =
681 load_balance_get_bucket_i (lb0,
682 hc0 & (lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100683
684 next0 = dpo0->dpoi_next_node;
685 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
686
Dave Barach75fc8542016-10-11 16:16:02 -0400687 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500688 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100689
Neale Ranns2be95c12016-11-19 13:50:04 +0000690 vlib_validate_buffer_enqueue_x1 (vm, node, next,
691 to_next, n_left_to_next,
692 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100693 }
694
695 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696 }
697
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100698 return frame->n_vectors;
699}
700
Dave Barachd7cb1b52016-12-09 09:52:16 -0500701VLIB_REGISTER_NODE (ip4_load_balance_node) =
702{
703.function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
704 sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
705 format_ip4_lookup_trace,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100706
Dave Barachd7cb1b52016-12-09 09:52:16 -0500707VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100708
709/* get first interface address */
710ip4_address_t *
711ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500712 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100713{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500714 ip_lookup_main_t *lm = &im->lookup_main;
715 ip_interface_address_t *ia = 0;
716 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100717
Neale Ranns32e1c012016-11-22 17:07:28 +0000718 /* *INDENT-OFF* */
719 foreach_ip_interface_address
720 (lm, ia, sw_if_index,
721 1 /* honor unnumbered */ ,
722 ({
723 ip4_address_t * a =
724 ip_interface_address_get_address (lm, ia);
725 result = a;
726 break;
727 }));
728 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100729 if (result_ia)
730 *result_ia = result ? ia : 0;
731 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700732}
733
734static void
735ip4_add_interface_routes (u32 sw_if_index,
736 ip4_main_t * im, u32 fib_index,
737 ip_interface_address_t * a)
738{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739 ip_lookup_main_t *lm = &im->lookup_main;
740 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100741 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500742 .fp_len = a->address_length,
743 .fp_proto = FIB_PROTOCOL_IP4,
744 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100745 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746
747 a->neighbor_probe_adj_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100749 if (pfx.fp_len < 32)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500750 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100751 fib_node_index_t fei;
752
Neale Ranns32e1c012016-11-22 17:07:28 +0000753 fei = fib_table_entry_update_one_path (fib_index, &pfx,
754 FIB_SOURCE_INTERFACE,
755 (FIB_ENTRY_FLAG_CONNECTED |
756 FIB_ENTRY_FLAG_ATTACHED),
757 FIB_PROTOCOL_IP4,
758 /* No next-hop address */
759 NULL,
760 sw_if_index,
761 // invalid FIB index
762 ~0,
763 1,
764 // no out-label stack
765 NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500766 FIB_ROUTE_PATH_FLAG_NONE);
767 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
768 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100769
770 pfx.fp_len = 32;
771
772 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500773 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100774 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500775 lm->classify_table_index_by_sw_if_index[sw_if_index];
776 if (classify_table_index != (u32) ~ 0)
777 {
778 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100779
Dave Barachd7cb1b52016-12-09 09:52:16 -0500780 dpo_set (&dpo,
781 DPO_CLASSIFY,
782 DPO_PROTO_IP4,
783 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100784
Dave Barachd7cb1b52016-12-09 09:52:16 -0500785 fib_table_entry_special_dpo_add (fib_index,
786 &pfx,
787 FIB_SOURCE_CLASSIFY,
788 FIB_ENTRY_FLAG_NONE, &dpo);
789 dpo_reset (&dpo);
790 }
791 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100792
Neale Ranns32e1c012016-11-22 17:07:28 +0000793 fib_table_entry_update_one_path (fib_index, &pfx,
794 FIB_SOURCE_INTERFACE,
795 (FIB_ENTRY_FLAG_CONNECTED |
796 FIB_ENTRY_FLAG_LOCAL),
797 FIB_PROTOCOL_IP4,
798 &pfx.fp_addr,
799 sw_if_index,
800 // invalid FIB index
801 ~0,
802 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500803 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804}
805
806static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100807ip4_del_interface_routes (ip4_main_t * im,
808 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500811 fib_prefix_t pfx = {
812 .fp_len = address_length,
813 .fp_proto = FIB_PROTOCOL_IP4,
814 .fp_addr.ip4 = *address,
815 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816
Dave Barachd7cb1b52016-12-09 09:52:16 -0500817 if (pfx.fp_len < 32)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100818 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500819 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100820 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821
Dave Barachd7cb1b52016-12-09 09:52:16 -0500822 pfx.fp_len = 32;
823 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824}
825
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100826void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500827ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100828{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500829 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100831 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
832
833 /*
834 * enable/disable only on the 1<->0 transition
835 */
836 if (is_enable)
837 {
838 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500839 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100840 }
841 else
842 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500843 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100844 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500845 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100846 }
Damjan Marion4d489932016-12-09 03:21:27 -0800847 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
848 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100849
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100850
Neale Ranns32e1c012016-11-22 17:07:28 +0000851 vnet_feature_enable_disable ("ip4-multicast",
852 "ip4-mfib-forward-lookup",
853 sw_if_index, is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100854}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856static clib_error_t *
857ip4_add_del_interface_address_internal (vlib_main_t * vm,
858 u32 sw_if_index,
859 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500860 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700861{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862 vnet_main_t *vnm = vnet_get_main ();
863 ip4_main_t *im = &ip4_main;
864 ip_lookup_main_t *lm = &im->lookup_main;
865 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700866 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500867 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868
869 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
870 ip4_addr_fib_init (&ip4_af, address,
871 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
872 vec_add1 (addr_fib, ip4_af);
873
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100874 /* FIXME-LATER
875 * there is no support for adj-fib handling in the presence of overlapping
876 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
877 * most routers do.
878 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000879 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500880 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100882 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500883 with an existing address. */
884 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000885 foreach_ip_interface_address
886 (&im->lookup_main, ia, sw_if_index,
887 0 /* honor unnumbered */ ,
888 ({
889 ip4_address_t * x =
890 ip_interface_address_get_address
891 (&im->lookup_main, ia);
892 if (ip4_destination_matches_route
893 (im, address, x, ia->address_length) ||
894 ip4_destination_matches_route (im,
895 x,
896 address,
897 address_length))
898 return
899 clib_error_create
900 ("failed to add %U which conflicts with %U for interface %U",
901 format_ip4_address_and_length, address,
902 address_length,
903 format_ip4_address_and_length, x,
904 ia->address_length,
905 format_vnet_sw_if_index_name, vnm,
906 sw_if_index);
907 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000909 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910
Ed Warnickecb9cada2015-12-08 15:45:58 -0700911 elts_before = pool_elts (lm->if_address_pool);
912
913 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500914 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915 if (error)
916 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400917
Dave Barachd7cb1b52016-12-09 09:52:16 -0500918 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100919
920 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500921 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100922 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500923 ip4_add_interface_routes (sw_if_index,
924 im, ip4_af.fib_index,
925 pool_elt_at_index
926 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700927
928 /* If pool did not grow/shrink: add duplicate address. */
929 if (elts_before != pool_elts (lm->if_address_pool))
930 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500931 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932 vec_foreach (cb, im->add_del_interface_address_callbacks)
933 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500934 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700935 }
936
Dave Barachd7cb1b52016-12-09 09:52:16 -0500937done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938 vec_free (addr_fib);
939 return error;
940}
941
942clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000943ip4_add_del_interface_address (vlib_main_t * vm,
944 u32 sw_if_index,
945 ip4_address_t * address,
946 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947{
948 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500949 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700950}
951
Dave Barachd6534602016-06-14 18:38:02 -0400952/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500953/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100954VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
955{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500956 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100957 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -0800958 .end_node = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100959 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
960};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100961
Dave Barachd7cb1b52016-12-09 09:52:16 -0500962VNET_FEATURE_INIT (ip4_flow_classify, static) =
963{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100964 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700965 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100966 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700967};
968
Dave Barachd7cb1b52016-12-09 09:52:16 -0500969VNET_FEATURE_INIT (ip4_inacl, static) =
970{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100971 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400972 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100973 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400974};
975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976VNET_FEATURE_INIT (ip4_source_check_1, static) =
977{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100978 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400979 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100980 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400981};
982
Dave Barachd7cb1b52016-12-09 09:52:16 -0500983VNET_FEATURE_INIT (ip4_source_check_2, static) =
984{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100985 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400986 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100987 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400988};
989
Dave Barachd7cb1b52016-12-09 09:52:16 -0500990VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
991{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100992 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400993 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100994 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400995};
996
Dave Barachd7cb1b52016-12-09 09:52:16 -0500997VNET_FEATURE_INIT (ip4_policer_classify, static) =
998{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100999 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001000 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001001 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001002};
1003
Dave Barachd7cb1b52016-12-09 09:52:16 -05001004VNET_FEATURE_INIT (ip4_ipsec, static) =
1005{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001006 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001007 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001008 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -04001009};
1010
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011VNET_FEATURE_INIT (ip4_vpath, static) =
1012{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001013 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001014 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -05001015 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
1016};
1017
Dave Barachd7cb1b52016-12-09 09:52:16 -05001018VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
1019{
John Lo37682e12016-11-30 12:51:39 -05001020 .arc_name = "ip4-unicast",
1021 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001022 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001023};
1024
Dave Barachd7cb1b52016-12-09 09:52:16 -05001025VNET_FEATURE_INIT (ip4_lookup, static) =
1026{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001027 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001028 .node_name = "ip4-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001029 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001030};
1031
Dave Barachd7cb1b52016-12-09 09:52:16 -05001032VNET_FEATURE_INIT (ip4_drop, static) =
1033{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001034 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001035 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001036 .runs_before = 0, /* not before any other features */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001037};
1038
1039
Dave Barachd6534602016-06-14 18:38:02 -04001040/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001041VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1042{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001043 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001044 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -08001045 .end_node = "ip4-lookup-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001046 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1047};
1048
Dave Barachd7cb1b52016-12-09 09:52:16 -05001049VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1050{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001051 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001052 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001053 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001054};
1055
Dave Barachd7cb1b52016-12-09 09:52:16 -05001056VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1057{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001058 .arc_name = "ip4-multicast",
Neale Ranns32e1c012016-11-22 17:07:28 +00001059 .node_name = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001060 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001061};
1062
Dave Barachd7cb1b52016-12-09 09:52:16 -05001063VNET_FEATURE_INIT (ip4_mc_drop, static) =
1064{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001065 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001066 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001067 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001068};
Dave Barach5331c722016-08-17 11:54:30 -04001069
1070/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001071VNET_FEATURE_ARC_INIT (ip4_output, static) =
1072{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001073 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001074 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion892e0762016-12-09 18:52:05 +01001075 .end_node = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001076 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1077};
Dave Barach5331c722016-08-17 11:54:30 -04001078
Dave Barachd7cb1b52016-12-09 09:52:16 -05001079VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1080{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001081 .arc_name = "ip4-output",
1082 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001083 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1084};
1085
Dave Barachd7cb1b52016-12-09 09:52:16 -05001086VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1087{
Matus Fabian08a6f012016-11-15 06:08:51 -08001088 .arc_name = "ip4-output",
1089 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001090 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001091};
1092
1093/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001094VNET_FEATURE_INIT (ip4_interface_output, static) =
1095{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001096 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001097 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001098 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001099};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001100/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001101
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001103ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001105 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001107 /* Fill in lookup tables with default table (0). */
1108 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001109 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001110
Damjan Marion8b3191e2016-11-09 19:54:20 +01001111 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1112 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113
Damjan Marion8b3191e2016-11-09 19:54:20 +01001114 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1115 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117 return /* no error */ 0;
1118}
1119
1120VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1121
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122/* Global IP4 main. */
1123ip4_main_t ip4_main;
1124
1125clib_error_t *
1126ip4_lookup_init (vlib_main_t * vm)
1127{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 ip4_main_t *im = &ip4_main;
1129 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001130 uword i;
1131
Damjan Marion8b3191e2016-11-09 19:54:20 +01001132 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1133 return error;
1134
Ed Warnickecb9cada2015-12-08 15:45:58 -07001135 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1136 {
1137 u32 m;
1138
1139 if (i < 32)
1140 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001141 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 m = ~0;
1143 im->fib_masks[i] = clib_host_to_net_u32 (m);
1144 }
1145
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1147
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001148 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001149 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001150 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001151
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001153 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154 pn = pg_get_node (ip4_lookup_node.index);
1155 pn->unformat_edit = unformat_pg_ip4_header;
1156 }
1157
1158 {
1159 ethernet_arp_header_t h;
1160
1161 memset (&h, 0, sizeof (h));
1162
1163 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001164 memset (h.ip4_over_ethernet[1].ethernet, 0,
1165 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166
1167#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1168#define _8(f,v) h.f = v;
1169 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1170 _16 (l3_type, ETHERNET_TYPE_IP4);
1171 _8 (n_l2_address_bytes, 6);
1172 _8 (n_l3_address_bytes, 4);
1173 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1174#undef _16
1175#undef _8
1176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 /* data */ &h,
1179 sizeof (h),
1180 /* alloc chunk size */ 8,
1181 "ip4 arp");
1182 }
1183
Dave Barach203c6322016-06-26 10:29:03 -04001184 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185}
1186
1187VLIB_INIT_FUNCTION (ip4_lookup_init);
1188
Dave Barachd7cb1b52016-12-09 09:52:16 -05001189typedef struct
1190{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001192 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193 u32 flow_hash;
1194 u32 fib_index;
1195
1196 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001197 u8 packet_data[64 - 1 * sizeof (u32)];
1198}
1199ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200
Dave Barachd7cb1b52016-12-09 09:52:16 -05001201u8 *
1202format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203{
1204 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1205 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001206 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001207 uword indent = format_get_indent (s);
1208 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001209 format_white_space, indent,
1210 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001211 return s;
1212}
1213
Dave Barachd7cb1b52016-12-09 09:52:16 -05001214static u8 *
1215format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001216{
1217 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1218 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001219 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001220 uword indent = format_get_indent (s);
1221
John Loac8146c2016-09-27 17:44:02 -04001222 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001223 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001224 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001225 format_white_space, indent,
1226 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001227 return s;
1228}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229
Dave Barachd7cb1b52016-12-09 09:52:16 -05001230static u8 *
1231format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001232{
1233 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1234 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001235 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1236 vnet_main_t *vnm = vnet_get_main ();
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001237 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238
Vengada Govindanf1544482016-09-28 02:45:57 -07001239 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001240 t->fib_index, t->dpo_index, format_ip_adjacency,
1241 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001242 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001243 format_white_space, indent,
1244 format_ip_adjacency_packet_data,
1245 vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001246 return s;
1247}
1248
1249/* Common trace function for all ip4-forward next nodes. */
1250void
1251ip4_forward_next_trace (vlib_main_t * vm,
1252 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001253 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001255 u32 *from, n_left;
1256 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001257
1258 n_left = frame->n_vectors;
1259 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001260
Ed Warnickecb9cada2015-12-08 15:45:58 -07001261 while (n_left >= 4)
1262 {
1263 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001264 vlib_buffer_t *b0, *b1;
1265 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266
1267 /* Prefetch next iteration. */
1268 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1269 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1270
1271 bi0 = from[0];
1272 bi1 = from[1];
1273
1274 b0 = vlib_get_buffer (vm, bi0);
1275 b1 = vlib_get_buffer (vm, bi1);
1276
1277 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1278 {
1279 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001280 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001282 t0->fib_index =
1283 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1284 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1285 vec_elt (im->fib_index_by_sw_if_index,
1286 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001287
Damjan Marionf1213b82016-03-13 02:22:06 +01001288 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 vlib_buffer_get_current (b0),
1290 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291 }
1292 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1293 {
1294 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001295 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001297 t1->fib_index =
1298 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1299 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1300 vec_elt (im->fib_index_by_sw_if_index,
1301 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1302 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1303 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304 }
1305 from += 2;
1306 n_left -= 2;
1307 }
1308
1309 while (n_left >= 1)
1310 {
1311 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001312 vlib_buffer_t *b0;
1313 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001314
1315 bi0 = from[0];
1316
1317 b0 = vlib_get_buffer (vm, bi0);
1318
1319 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1320 {
1321 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001322 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001324 t0->fib_index =
1325 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1326 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1327 vec_elt (im->fib_index_by_sw_if_index,
1328 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1329 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1330 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001331 }
1332 from += 1;
1333 n_left -= 1;
1334 }
1335}
1336
1337static uword
1338ip4_drop_or_punt (vlib_main_t * vm,
1339 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001340 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001341{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001342 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343 uword n_packets = frame->n_vectors;
1344
Dave Barachd7cb1b52016-12-09 09:52:16 -05001345 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346 /* stride */ 1,
1347 n_packets,
1348 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001349 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001350
1351 if (node->flags & VLIB_NODE_FLAG_TRACE)
1352 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1353
1354 return n_packets;
1355}
1356
1357static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001358ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1359{
1360 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1361}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362
1363static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001364ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1365{
1366 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1367}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001368
Neale Ranns32e1c012016-11-22 17:07:28 +00001369/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001370VLIB_REGISTER_NODE (ip4_drop_node, static) =
1371{
Neale Ranns32e1c012016-11-22 17:07:28 +00001372 .function = ip4_drop,.
1373 name = "ip4-drop",
1374 .vector_size = sizeof (u32),
1375 .format_trace = format_ip4_forward_next_trace,
1376 .n_next_nodes = 1,
1377 .next_nodes = {
1378 [0] = "error-drop",
1379 },
1380};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381
Dave Barachd7cb1b52016-12-09 09:52:16 -05001382VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383
Dave Barachd7cb1b52016-12-09 09:52:16 -05001384VLIB_REGISTER_NODE (ip4_punt_node, static) =
1385{
Neale Ranns32e1c012016-11-22 17:07:28 +00001386 .function = ip4_punt,
1387 .name = "ip4-punt",
1388 .vector_size = sizeof (u32),
1389 .format_trace = format_ip4_forward_next_trace,
1390 .n_next_nodes = 1,
1391 .next_nodes = {
1392 [0] = "error-punt",
1393 },
1394};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395
Dave Barachd7cb1b52016-12-09 09:52:16 -05001396VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Neale Ranns32e1c012016-11-22 17:07:28 +00001397/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02001398
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399/* Compute TCP/UDP/ICMP4 checksum in software. */
1400u16
1401ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1402 ip4_header_t * ip0)
1403{
1404 ip_csum_t sum0;
1405 u32 ip_header_length, payload_length_host_byte_order;
1406 u32 n_this_buffer, n_bytes_left;
1407 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001408 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001409
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410 /* Initialize checksum with ip header. */
1411 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001412 payload_length_host_byte_order =
1413 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1414 sum0 =
1415 clib_host_to_net_u32 (payload_length_host_byte_order +
1416 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417
1418 if (BITS (uword) == 32)
1419 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001420 sum0 =
1421 ip_csum_with_carry (sum0,
1422 clib_mem_unaligned (&ip0->src_address, u32));
1423 sum0 =
1424 ip_csum_with_carry (sum0,
1425 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426 }
1427 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001428 sum0 =
1429 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430
1431 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1432 data_this_buffer = (void *) ip0 + ip_header_length;
1433 if (n_this_buffer + ip_header_length > p0->current_length)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001434 n_this_buffer =
1435 p0->current_length >
1436 ip_header_length ? p0->current_length - ip_header_length : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437 while (1)
1438 {
1439 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1440 n_bytes_left -= n_this_buffer;
1441 if (n_bytes_left == 0)
1442 break;
1443
1444 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1445 p0 = vlib_get_buffer (vm, p0->next_buffer);
1446 data_this_buffer = vlib_buffer_get_current (p0);
1447 n_this_buffer = p0->current_length;
1448 }
1449
Dave Barachd7cb1b52016-12-09 09:52:16 -05001450 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001451
1452 return sum16;
1453}
1454
John Lo37682e12016-11-30 12:51:39 -05001455u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001456ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1457{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001458 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1459 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001460 u16 sum16;
1461
1462 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1463 || ip0->protocol == IP_PROTOCOL_UDP);
1464
1465 udp0 = (void *) (ip0 + 1);
1466 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1467 {
1468 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1469 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1470 return p0->flags;
1471 }
1472
1473 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1474
1475 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1476 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1477
1478 return p0->flags;
1479}
1480
Dave Barach68b0fb02017-02-28 15:15:56 -05001481/* *INDENT-OFF* */
1482VNET_FEATURE_ARC_INIT (ip4_local) =
1483{
1484 .arc_name = "ip4-local",
1485 .start_nodes = VNET_FEATURES ("ip4-local"),
1486};
1487/* *INDENT-ON* */
1488
1489static inline uword
1490ip4_local_inline (vlib_main_t * vm,
1491 vlib_node_runtime_t * node,
1492 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001493{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001494 ip4_main_t *im = &ip4_main;
1495 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001496 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001497 u32 *from, *to_next, n_left_from, n_left_to_next;
1498 vlib_node_runtime_t *error_node =
1499 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001500 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001501
1502 from = vlib_frame_vector_args (frame);
1503 n_left_from = frame->n_vectors;
1504 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001505
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506 if (node->flags & VLIB_NODE_FLAG_TRACE)
1507 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1508
1509 while (n_left_from > 0)
1510 {
1511 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1512
1513 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001514 {
1515 vlib_buffer_t *p0, *p1;
1516 ip4_header_t *ip0, *ip1;
1517 udp_header_t *udp0, *udp1;
1518 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1519 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1520 const dpo_id_t *dpo0, *dpo1;
1521 const load_balance_t *lb0, *lb1;
1522 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1523 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1524 i32 len_diff0, len_diff1;
1525 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1526 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001527 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001528
Dave Barachd7cb1b52016-12-09 09:52:16 -05001529 pi0 = to_next[0] = from[0];
1530 pi1 = to_next[1] = from[1];
1531 from += 2;
1532 n_left_from -= 2;
1533 to_next += 2;
1534 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001535
Dave Barach68b0fb02017-02-28 15:15:56 -05001536 next0 = next1 = IP_LOCAL_NEXT_DROP;
1537
Ed Warnickecb9cada2015-12-08 15:45:58 -07001538 p0 = vlib_get_buffer (vm, pi0);
1539 p1 = vlib_get_buffer (vm, pi1);
1540
1541 ip0 = vlib_buffer_get_current (p0);
1542 ip1 = vlib_buffer_get_current (p1);
1543
Dave Barachd7cb1b52016-12-09 09:52:16 -05001544 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1545 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001546
Dave Barach68b0fb02017-02-28 15:15:56 -05001547 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1548 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1549
1550 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1551 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
1552
1553 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001554 fib_index0 =
1555 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1556 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001557
Dave Barach68b0fb02017-02-28 15:15:56 -05001558 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001559 fib_index1 =
1560 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1561 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001563 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1564 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001565
1566 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1567
Dave Barachd7cb1b52016-12-09 09:52:16 -05001568 leaf0 =
1569 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1570 leaf1 =
1571 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001572
John Lo3419d0b2016-06-02 09:28:37 -04001573 /* Treat IP frag packets as "experimental" protocol for now
1574 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001575 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1576 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001577
1578 if (head_of_feature_arc == 0)
1579 {
1580 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1581 goto skip_checks;
1582 }
1583
Ed Warnickecb9cada2015-12-08 15:45:58 -07001584 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1585 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1586 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1587 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1588
1589 flags0 = p0->flags;
1590 flags1 = p1->flags;
1591
1592 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1593 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1594
1595 udp0 = ip4_next_header (ip0);
1596 udp1 = ip4_next_header (ip1);
1597
1598 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1599 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1600 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1601
Dave Barachd7cb1b52016-12-09 09:52:16 -05001602 leaf0 =
1603 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1604 leaf1 =
1605 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001606
1607 /* Verify UDP length. */
1608 ip_len0 = clib_net_to_host_u16 (ip0->length);
1609 ip_len1 = clib_net_to_host_u16 (ip1->length);
1610 udp_len0 = clib_net_to_host_u16 (udp0->length);
1611 udp_len1 = clib_net_to_host_u16 (udp1->length);
1612
1613 len_diff0 = ip_len0 - udp_len0;
1614 len_diff1 = ip_len1 - udp_len1;
1615
1616 len_diff0 = is_udp0 ? len_diff0 : 0;
1617 len_diff1 = is_udp1 ? len_diff1 : 0;
1618
Dave Barachd7cb1b52016-12-09 09:52:16 -05001619 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1620 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001621 {
1622 if (is_tcp_udp0)
1623 {
1624 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001625 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1627 good_tcp_udp0 =
1628 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1629 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1630 }
1631 if (is_tcp_udp1)
1632 {
1633 if (is_tcp_udp1
Dave Barachd7cb1b52016-12-09 09:52:16 -05001634 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1636 good_tcp_udp1 =
1637 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1638 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1639 }
1640 }
1641
1642 good_tcp_udp0 &= len_diff0 >= 0;
1643 good_tcp_udp1 &= len_diff1 >= 0;
1644
Dave Barachd7cb1b52016-12-09 09:52:16 -05001645 leaf0 =
1646 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1647 leaf1 =
1648 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649
1650 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1651
1652 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1653 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1654
1655 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001656 error0 = (is_tcp_udp0 && !good_tcp_udp0
1657 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1658 error1 = (is_tcp_udp1 && !good_tcp_udp1
1659 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001660
Dave Barachd7cb1b52016-12-09 09:52:16 -05001661 leaf0 =
1662 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1663 leaf1 =
1664 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
1665 leaf0 =
1666 (leaf0 ==
1667 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1668 leaf1 =
1669 (leaf1 ==
1670 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001671
Dave Barachd7cb1b52016-12-09 09:52:16 -05001672 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1673 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1674 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001675
Dave Barachd7cb1b52016-12-09 09:52:16 -05001676 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1677 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1678 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001679
Dave Barachd7cb1b52016-12-09 09:52:16 -05001680 lb0 = load_balance_get (lbi0);
1681 lb1 = load_balance_get (lbi1);
1682 dpo0 = load_balance_get_bucket_i (lb0, 0);
1683 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001684
Dave Barach75fc8542016-10-11 16:16:02 -04001685 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001686 * Must have a route to source otherwise we drop the packet.
1687 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001688 *
1689 * The checks are:
1690 * - the source is a recieve => it's from us => bogus, do this
1691 * first since it sets a different error code.
1692 * - uRPF check for any route to source - accept if passes.
1693 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001694 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001695 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001696 dpo0->dpoi_type == DPO_RECEIVE) ?
1697 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1698 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1699 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001700 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001701 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001702 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001703 dpo1->dpoi_type == DPO_RECEIVE) ?
1704 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1705 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1706 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001707 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001708 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001709
1710 next0 = lm->local_next_by_ip_protocol[proto0];
1711 next1 = lm->local_next_by_ip_protocol[proto1];
1712
Dave Barach68b0fb02017-02-28 15:15:56 -05001713 skip_checks:
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 Ranns32e1c012016-11-22 17:07:28 +00002330 vlib_frame_t * frame, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002331{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002332 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2333 u32 *from = vlib_frame_vector_args (frame);
2334 u32 n_left_from, n_left_to_next, *to_next, next_index;
2335 vlib_node_runtime_t *error_node =
2336 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002337
2338 n_left_from = frame->n_vectors;
2339 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002340 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04002341
Ed Warnickecb9cada2015-12-08 15:45:58 -07002342 while (n_left_from > 0)
2343 {
2344 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2345
2346 while (n_left_from >= 4 && n_left_to_next >= 2)
2347 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002348 ip_adjacency_t *adj0, *adj1;
2349 vlib_buffer_t *p0, *p1;
2350 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002351 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2352 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002353 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002354
Ed Warnickecb9cada2015-12-08 15:45:58 -07002355 /* Prefetch next iteration. */
2356 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002357 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002358
2359 p2 = vlib_get_buffer (vm, from[2]);
2360 p3 = vlib_get_buffer (vm, from[3]);
2361
2362 vlib_prefetch_buffer_header (p2, STORE);
2363 vlib_prefetch_buffer_header (p3, STORE);
2364
2365 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2366 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2367 }
2368
2369 pi0 = to_next[0] = from[0];
2370 pi1 = to_next[1] = from[1];
2371
2372 from += 2;
2373 n_left_from -= 2;
2374 to_next += 2;
2375 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002376
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 p0 = vlib_get_buffer (vm, pi0);
2378 p1 = vlib_get_buffer (vm, pi1);
2379
Neale Rannsf06aea52016-11-29 06:51:37 -08002380 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2381 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382
Dave Barachd7cb1b52016-12-09 09:52:16 -05002383 /* We should never rewrite a pkt using the MISS adjacency */
2384 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385
2386 ip0 = vlib_buffer_get_current (p0);
2387 ip1 = vlib_buffer_get_current (p1);
2388
2389 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002390 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391
2392 /* Decrement TTL & update checksum.
2393 Works either endian, so no need for byte swap. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002394 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002396 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397
2398 /* Input node should have reject packets with ttl 0. */
2399 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002400
2401 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002402 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403
2404 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002407
Dave Barachd7cb1b52016-12-09 09:52:16 -05002408 /*
2409 * If the ttl drops below 1 when forwarding, generate
2410 * an ICMP response.
2411 */
2412 if (PREDICT_FALSE (ttl0 <= 0))
2413 {
2414 error0 = IP4_ERROR_TIME_EXPIRED;
2415 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2416 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2417 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2418 0);
2419 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2420 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002421
2422 /* Verify checksum. */
2423 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2424 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002425 else
2426 {
2427 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2428 }
2429 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002430 {
2431 i32 ttl1 = ip1->ttl;
2432
2433 /* Input node should have reject packets with ttl 0. */
2434 ASSERT (ip1->ttl > 0);
2435
2436 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2437 checksum1 += checksum1 >= 0xffff;
2438
2439 ip1->checksum = checksum1;
2440 ttl1 -= 1;
2441 ip1->ttl = ttl1;
2442
Dave Barachd7cb1b52016-12-09 09:52:16 -05002443 /*
2444 * If the ttl drops below 1 when forwarding, generate
2445 * an ICMP response.
2446 */
2447 if (PREDICT_FALSE (ttl1 <= 0))
2448 {
2449 error1 = IP4_ERROR_TIME_EXPIRED;
2450 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2451 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2452 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2453 0);
2454 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2455 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456
2457 /* Verify checksum. */
2458 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2459 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2460 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002461 else
2462 {
2463 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2464 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465
2466 /* Rewrite packet header and updates lengths. */
2467 adj0 = ip_get_adjacency (lm, adj_index0);
2468 adj1 = ip_get_adjacency (lm, adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002469
Dave Barachd7cb1b52016-12-09 09:52:16 -05002470 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 rw_len0 = adj0[0].rewrite_header.data_bytes;
2472 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002473 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2474 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002475
Dave Barachd7cb1b52016-12-09 09:52:16 -05002476 /* Check MTU of outgoing interface. */
2477 error0 =
2478 (vlib_buffer_length_in_chain (vm, p0) >
2479 adj0[0].
2480 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2481 error0);
2482 error1 =
2483 (vlib_buffer_length_in_chain (vm, p1) >
2484 adj1[0].
2485 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2486 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002487
Dave Barachd7cb1b52016-12-09 09:52:16 -05002488 /*
Neale Ranns044183f2017-01-24 01:34:25 -08002489 * pre-fetch the per-adjacency counters
Dave Barachd7cb1b52016-12-09 09:52:16 -05002490 */
Neale Ranns044183f2017-01-24 01:34:25 -08002491 vlib_prefetch_combined_counter (&adjacency_counters,
2492 cpu_index, adj_index0);
2493 vlib_prefetch_combined_counter (&adjacency_counters,
2494 cpu_index, adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002495
Dave Barachd7cb1b52016-12-09 09:52:16 -05002496 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2497 * to see the IP headerr */
2498 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2499 {
Damjan Marion892e0762016-12-09 18:52:05 +01002500 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002501 p0->current_data -= rw_len0;
2502 p0->current_length += rw_len0;
2503 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2504 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002505
Dave Barachd7cb1b52016-12-09 09:52:16 -05002506 vnet_feature_arc_start (lm->output_feature_arc_index,
2507 tx_sw_if_index0, &next0, p0);
2508 }
2509 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2510 {
Damjan Marion892e0762016-12-09 18:52:05 +01002511 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002512 p1->current_data -= rw_len1;
2513 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002514
Dave Barachd7cb1b52016-12-09 09:52:16 -05002515 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2516 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002517
Dave Barachd7cb1b52016-12-09 09:52:16 -05002518 vnet_feature_arc_start (lm->output_feature_arc_index,
2519 tx_sw_if_index1, &next1, p1);
2520 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002521
2522 /* Guess we are only writing on simple Ethernet header. */
2523 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002524 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002525
Neale Ranns044183f2017-01-24 01:34:25 -08002526 /*
2527 * Bump the per-adjacency counters
2528 */
2529 vlib_increment_combined_counter
2530 (&adjacency_counters,
2531 cpu_index,
2532 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2533
2534 vlib_increment_combined_counter
2535 (&adjacency_counters,
2536 cpu_index,
2537 adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2538
Neale Ranns5e575b12016-10-03 09:40:25 +01002539 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002540 {
2541 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2542 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2543 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002544 if (is_mcast)
2545 {
2546 /*
2547 * copy bytes from the IP address into the MAC rewrite
2548 */
2549 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2550 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 1);
2551 }
Dave Barach75fc8542016-10-11 16:16:02 -04002552
Ed Warnickecb9cada2015-12-08 15:45:58 -07002553 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2554 to_next, n_left_to_next,
2555 pi0, pi1, next0, next1);
2556 }
2557
2558 while (n_left_from > 0 && n_left_to_next > 0)
2559 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002560 ip_adjacency_t *adj0;
2561 vlib_buffer_t *p0;
2562 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002563 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002564 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002565
Ed Warnickecb9cada2015-12-08 15:45:58 -07002566 pi0 = to_next[0] = from[0];
2567
2568 p0 = vlib_get_buffer (vm, pi0);
2569
Neale Rannsf06aea52016-11-29 06:51:37 -08002570 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 /* We should never rewrite a pkt using the MISS adjacency */
2573 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002574
2575 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002576
Ed Warnickecb9cada2015-12-08 15:45:58 -07002577 ip0 = vlib_buffer_get_current (p0);
2578
2579 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002580 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002581
2582 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002583 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002584 {
2585 i32 ttl0 = ip0->ttl;
2586
2587 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2588
2589 checksum0 += checksum0 >= 0xffff;
2590
2591 ip0->checksum = checksum0;
2592
2593 ASSERT (ip0->ttl > 0);
2594
2595 ttl0 -= 1;
2596
2597 ip0->ttl = ttl0;
2598
2599 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2600
Dave Barachd7cb1b52016-12-09 09:52:16 -05002601 if (PREDICT_FALSE (ttl0 <= 0))
2602 {
2603 /*
2604 * If the ttl drops below 1 when forwarding, generate
2605 * an ICMP response.
2606 */
2607 error0 = IP4_ERROR_TIME_EXPIRED;
2608 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2609 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2610 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2611 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2612 0);
2613 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002614 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002615 else
2616 {
2617 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2618 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002619
Neale Ranns044183f2017-01-24 01:34:25 -08002620 vlib_prefetch_combined_counter (&adjacency_counters,
2621 cpu_index, adj_index0);
2622
Ed Warnickecb9cada2015-12-08 15:45:58 -07002623 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002624 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002625 if (is_mcast)
2626 {
2627 /*
2628 * copy bytes from the IP address into the MAC rewrite
2629 */
2630 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2631 }
Dave Barach75fc8542016-10-11 16:16:02 -04002632
Dave Barachd7cb1b52016-12-09 09:52:16 -05002633 /* Update packet buffer attributes/set output interface. */
2634 rw_len0 = adj0[0].rewrite_header.data_bytes;
2635 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002636
Neale Ranns044183f2017-01-24 01:34:25 -08002637 vlib_increment_combined_counter
2638 (&adjacency_counters,
2639 cpu_index,
2640 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002641
Dave Barachd7cb1b52016-12-09 09:52:16 -05002642 /* Check MTU of outgoing interface. */
2643 error0 = (vlib_buffer_length_in_chain (vm, p0)
2644 > adj0[0].rewrite_header.max_l3_packet_bytes
2645 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002646
Ed Warnickecb9cada2015-12-08 15:45:58 -07002647 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002648
Dave Barachd7cb1b52016-12-09 09:52:16 -05002649 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2650 * to see the IP headerr */
2651 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2652 {
2653 p0->current_data -= rw_len0;
2654 p0->current_length += rw_len0;
2655 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002656
Dave Barachd7cb1b52016-12-09 09:52:16 -05002657 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2658 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002659
Neale Ranns5e575b12016-10-03 09:40:25 +01002660 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002661 {
2662 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002663 }
2664
Dave Barachd7cb1b52016-12-09 09:52:16 -05002665 vnet_feature_arc_start (lm->output_feature_arc_index,
2666 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002667
Dave Barachd7cb1b52016-12-09 09:52:16 -05002668 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669
Ed Warnickecb9cada2015-12-08 15:45:58 -07002670 from += 1;
2671 n_left_from -= 1;
2672 to_next += 1;
2673 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002674
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2676 to_next, n_left_to_next,
2677 pi0, next0);
2678 }
Dave Barach75fc8542016-10-11 16:16:02 -04002679
Ed Warnickecb9cada2015-12-08 15:45:58 -07002680 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2681 }
2682
2683 /* Need to do trace after rewrites to pick up new packet data. */
2684 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002685 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002686
2687 return frame->n_vectors;
2688}
2689
Dave Barach132d51d2016-07-07 10:10:17 -04002690
Neale Rannsf06aea52016-11-29 06:51:37 -08002691/** @brief IPv4 rewrite node.
2692 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002693
2694 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2695 header checksum, fetch the ip adjacency, check the outbound mtu,
2696 apply the adjacency rewrite, and send pkts to the adjacency
2697 rewrite header's rewrite_next_index.
2698
2699 @param vm vlib_main_t corresponding to the current thread
2700 @param node vlib_node_runtime_t
2701 @param frame vlib_frame_t whose contents should be dispatched
2702
2703 @par Graph mechanics: buffer metadata, next index usage
2704
2705 @em Uses:
2706 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2707 - the rewrite adjacency index
2708 - <code>adj->lookup_next_index</code>
2709 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002710 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002711 - <code>adj->rewrite_header</code>
2712 - Rewrite string length, rewrite string, next_index
2713
2714 @em Sets:
2715 - <code>b->current_data, b->current_length</code>
2716 - Updated net of applying the rewrite string
2717
2718 <em>Next Indices:</em>
2719 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002720 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002721*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002722static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002723ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002724 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725{
Neale Ranns32e1c012016-11-22 17:07:28 +00002726 return ip4_rewrite_inline (vm, node, frame, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727}
2728
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002729static uword
2730ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002731 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002732{
Neale Ranns32e1c012016-11-22 17:07:28 +00002733 return ip4_rewrite_inline (vm, node, frame, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002734}
2735
Neale Ranns32e1c012016-11-22 17:07:28 +00002736static uword
2737ip4_rewrite_mcast (vlib_main_t * vm,
2738 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002739{
Neale Ranns32e1c012016-11-22 17:07:28 +00002740 return ip4_rewrite_inline (vm, node, frame, 0, 1);
2741}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742
Neale Ranns32e1c012016-11-22 17:07:28 +00002743/* *INDENT-OFF* */
2744VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2745 .function = ip4_rewrite,
2746 .name = "ip4-rewrite",
2747 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002748
Neale Ranns32e1c012016-11-22 17:07:28 +00002749 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002750
Neale Ranns32e1c012016-11-22 17:07:28 +00002751 .n_next_nodes = 2,
2752 .next_nodes = {
2753 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2754 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2755 },
2756};
2757VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2758
2759VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2760 .function = ip4_rewrite_mcast,
2761 .name = "ip4-rewrite-mcast",
2762 .vector_size = sizeof (u32),
2763
2764 .format_trace = format_ip4_rewrite_trace,
2765 .sibling_of = "ip4-rewrite",
2766};
2767VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2768
2769VLIB_REGISTER_NODE (ip4_midchain_node) = {
2770 .function = ip4_midchain,
2771 .name = "ip4-midchain",
2772 .vector_size = sizeof (u32),
2773 .format_trace = format_ip4_forward_next_trace,
2774 .sibling_of = "ip4-rewrite",
2775};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002776VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002777/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002778
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779static clib_error_t *
2780add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002781 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002782{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002783 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002784 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002785 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002786 u32 sw_if_index, table_id;
2787
2788 sw_if_index = ~0;
2789
Dave Barachd7cb1b52016-12-09 09:52:16 -05002790 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002791 {
2792 error = clib_error_return (0, "unknown interface `%U'",
2793 format_unformat_error, input);
2794 goto done;
2795 }
2796
2797 if (unformat (input, "%d", &table_id))
2798 ;
2799 else
2800 {
2801 error = clib_error_return (0, "expected table id `%U'",
2802 format_unformat_error, input);
2803 goto done;
2804 }
2805
Neale Ranns4008ac92017-02-13 23:20:04 -08002806 /*
2807 * If the interface already has in IP address, then a change int
2808 * VRF is not allowed. The IP address applied must first be removed.
2809 * We do not do that automatically here, since VPP has no knowledge
2810 * of whether thoses subnets are valid in the destination VRF.
2811 */
2812 /* *INDENT-OFF* */
2813 foreach_ip_interface_address (&ip4_main.lookup_main,
2814 ia, sw_if_index,
2815 1 /* honor unnumbered */,
2816 ({
2817 ip4_address_t * a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002818
Neale Ranns4008ac92017-02-13 23:20:04 -08002819 a = ip_interface_address_get_address (&ip4_main.lookup_main, ia);
2820 error = clib_error_return (0, "interface %U has address %U",
2821 format_vnet_sw_if_index_name, vnm,
2822 sw_if_index,
2823 format_ip4_address, a);
2824 goto done;
2825 }));
2826 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002827
Neale Ranns4008ac92017-02-13 23:20:04 -08002828{
2829 ip4_main_t *im = &ip4_main;
2830 u32 fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002831
Neale Ranns4008ac92017-02-13 23:20:04 -08002832 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2833
2834 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2835 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2836
2837 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
2838 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2839 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
2840}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002841
Dave Barachd7cb1b52016-12-09 09:52:16 -05002842done:
Neale Ranns4008ac92017-02-13 23:20:04 -08002843return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002844}
2845
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002846/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002847 * Place the indicated interface into the supplied IPv4 FIB table (also known
2848 * as a VRF). If the FIB table does not exist, this command creates it. To
2849 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2850 * FIB table will only be displayed if a route has been added to the table, or
2851 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002852 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002853 *
Neale Ranns4008ac92017-02-13 23:20:04 -08002854 * @note IP addresses added after setting the interface IP table are added to
2855 * the indicated FIB table. If an IP address is added prior to changing the
2856 * table then this is an error. The control plane must remove these addresses
2857 * first and then change the table. VPP will not automatically move the
2858 * addresses from the old to the new table as it does not know the validity
2859 * of such a change.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002860 *
2861 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002862 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2863 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002864 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002865/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002866VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2867{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002868 .path = "set interface ip table",
2869 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002870 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002871};
Billy McFall0683c9c2016-10-13 08:27:31 -04002872/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002873
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874int
2875ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2876{
2877 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002878 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002879 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002880
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002881 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002882
2883 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2884 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
2885 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
2886 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2887 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002888
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889 /* Handle default route. */
2890 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002891
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002892 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002893
Dave Barachd7cb1b52016-12-09 09:52:16 -05002894 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002895}
Dave Barach75fc8542016-10-11 16:16:02 -04002896
Ed Warnickecb9cada2015-12-08 15:45:58 -07002897static clib_error_t *
2898test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002899 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002900{
Billy McFall309fe062016-10-14 07:37:33 -04002901 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002902 u32 table_id = 0;
2903 f64 count = 1;
2904 u32 n;
2905 int i;
2906 ip4_address_t ip4_base_address;
2907 u64 errors = 0;
2908
Dave Barachd7cb1b52016-12-09 09:52:16 -05002909 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2910 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002911 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002912 {
2913 /* Make sure the entry exists. */
2914 fib = ip4_fib_get (table_id);
2915 if ((fib) && (fib->index != table_id))
2916 return clib_error_return (0, "<fib-index> %d does not exist",
2917 table_id);
2918 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919 else if (unformat (input, "count %f", &count))
2920 ;
2921
2922 else if (unformat (input, "%U",
2923 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002924 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002926 return clib_error_return (0, "unknown input `%U'",
2927 format_unformat_error, input);
2928 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002929
2930 n = count;
2931
2932 for (i = 0; i < n; i++)
2933 {
2934 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002935 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002936
Dave Barach75fc8542016-10-11 16:16:02 -04002937 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 clib_host_to_net_u32 (1 +
2939 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002940 }
2941
Dave Barach75fc8542016-10-11 16:16:02 -04002942 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002943 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2944 else
2945 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2946
2947 return 0;
2948}
2949
Billy McFall0683c9c2016-10-13 08:27:31 -04002950/*?
2951 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2952 * given FIB table to determine if there is a conflict with the
2953 * adjacency table. The fib-id can be determined by using the
2954 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2955 * of 0 is used.
2956 *
2957 * @todo This command uses fib-id, other commands use table-id (not
2958 * just a name, they are different indexes). Would like to change this
2959 * to table-id for consistency.
2960 *
2961 * @cliexpar
2962 * Example of how to run the test lookup command:
2963 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2964 * No errors in 2 lookups
2965 * @cliexend
2966?*/
2967/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002968VLIB_CLI_COMMAND (lookup_test_command, static) =
2969{
2970 .path = "test lookup",
2971 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2972 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002973};
Billy McFall0683c9c2016-10-13 08:27:31 -04002974/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002975
Dave Barachd7cb1b52016-12-09 09:52:16 -05002976int
2977vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002978{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002979 ip4_main_t *im4 = &ip4_main;
2980 ip4_fib_t *fib;
2981 uword *p = hash_get (im4->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002982
2983 if (p == 0)
2984 return VNET_API_ERROR_NO_SUCH_FIB;
2985
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002986 fib = ip4_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002987
2988 fib->flow_hash_config = flow_hash_config;
2989 return 0;
2990}
Dave Barach75fc8542016-10-11 16:16:02 -04002991
Ed Warnickecb9cada2015-12-08 15:45:58 -07002992static clib_error_t *
2993set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002994 unformat_input_t * input,
2995 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002996{
2997 int matched = 0;
2998 u32 table_id = 0;
2999 u32 flow_hash_config = 0;
3000 int rv;
3001
Dave Barachd7cb1b52016-12-09 09:52:16 -05003002 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3003 {
3004 if (unformat (input, "table %d", &table_id))
3005 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003006#define _(a,v) \
3007 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003008 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003009#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003010 else
3011 break;
3012 }
Dave Barach75fc8542016-10-11 16:16:02 -04003013
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014 if (matched == 0)
3015 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003016 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003017
Ed Warnickecb9cada2015-12-08 15:45:58 -07003018 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3019 switch (rv)
3020 {
3021 case 0:
3022 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003023
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024 case VNET_API_ERROR_NO_SUCH_FIB:
3025 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003026
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027 default:
3028 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3029 break;
3030 }
Dave Barach75fc8542016-10-11 16:16:02 -04003031
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032 return 0;
3033}
Dave Barach75fc8542016-10-11 16:16:02 -04003034
Billy McFall0683c9c2016-10-13 08:27:31 -04003035/*?
3036 * Configure the set of IPv4 fields used by the flow hash.
3037 *
3038 * @cliexpar
3039 * Example of how to set the flow hash on a given table:
3040 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3041 * Example of display the configured flow hash:
3042 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003043 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3044 * 0.0.0.0/0
3045 * unicast-ip4-chain
3046 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3047 * [0] [@0]: dpo-drop ip6
3048 * 0.0.0.0/32
3049 * unicast-ip4-chain
3050 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3051 * [0] [@0]: dpo-drop ip6
3052 * 224.0.0.0/8
3053 * unicast-ip4-chain
3054 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3055 * [0] [@0]: dpo-drop ip6
3056 * 6.0.1.2/32
3057 * unicast-ip4-chain
3058 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3059 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3060 * 7.0.0.1/32
3061 * unicast-ip4-chain
3062 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3063 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3064 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3065 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3066 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3067 * 240.0.0.0/8
3068 * unicast-ip4-chain
3069 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3070 * [0] [@0]: dpo-drop ip6
3071 * 255.255.255.255/32
3072 * unicast-ip4-chain
3073 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3074 * [0] [@0]: dpo-drop ip6
3075 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3076 * 0.0.0.0/0
3077 * unicast-ip4-chain
3078 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3079 * [0] [@0]: dpo-drop ip6
3080 * 0.0.0.0/32
3081 * unicast-ip4-chain
3082 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3083 * [0] [@0]: dpo-drop ip6
3084 * 172.16.1.0/24
3085 * unicast-ip4-chain
3086 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3087 * [0] [@4]: ipv4-glean: af_packet0
3088 * 172.16.1.1/32
3089 * unicast-ip4-chain
3090 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3091 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3092 * 172.16.1.2/32
3093 * unicast-ip4-chain
3094 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3095 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3096 * 172.16.2.0/24
3097 * unicast-ip4-chain
3098 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3099 * [0] [@4]: ipv4-glean: af_packet1
3100 * 172.16.2.1/32
3101 * unicast-ip4-chain
3102 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3103 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3104 * 224.0.0.0/8
3105 * unicast-ip4-chain
3106 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3107 * [0] [@0]: dpo-drop ip6
3108 * 240.0.0.0/8
3109 * unicast-ip4-chain
3110 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3111 * [0] [@0]: dpo-drop ip6
3112 * 255.255.255.255/32
3113 * unicast-ip4-chain
3114 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3115 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003116 * @cliexend
3117?*/
3118/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003119VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3120{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003121 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003122 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003123 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003124 .function = set_ip_flow_hash_command_fn,
3125};
Billy McFall0683c9c2016-10-13 08:27:31 -04003126/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003127
Dave Barachd7cb1b52016-12-09 09:52:16 -05003128int
3129vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3130 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003131{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003132 vnet_main_t *vnm = vnet_get_main ();
3133 vnet_interface_main_t *im = &vnm->interface_main;
3134 ip4_main_t *ipm = &ip4_main;
3135 ip_lookup_main_t *lm = &ipm->lookup_main;
3136 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003137 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138
3139 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3140 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3141
3142 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3143 return VNET_API_ERROR_NO_SUCH_ENTRY;
3144
3145 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003146 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003147
Neale Rannsdf089a82016-10-02 16:39:06 +01003148 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3149
3150 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003151 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003152 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003153 .fp_len = 32,
3154 .fp_proto = FIB_PROTOCOL_IP4,
3155 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003156 };
3157 u32 fib_index;
3158
Dave Barachd7cb1b52016-12-09 09:52:16 -05003159 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3160 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003161
3162
Dave Barachd7cb1b52016-12-09 09:52:16 -05003163 if (table_index != (u32) ~ 0)
3164 {
3165 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003166
Dave Barachd7cb1b52016-12-09 09:52:16 -05003167 dpo_set (&dpo,
3168 DPO_CLASSIFY,
3169 DPO_PROTO_IP4,
3170 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003171
Dave Barachd7cb1b52016-12-09 09:52:16 -05003172 fib_table_entry_special_dpo_add (fib_index,
3173 &pfx,
3174 FIB_SOURCE_CLASSIFY,
3175 FIB_ENTRY_FLAG_NONE, &dpo);
3176 dpo_reset (&dpo);
3177 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003178 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003179 {
3180 fib_table_entry_special_remove (fib_index,
3181 &pfx, FIB_SOURCE_CLASSIFY);
3182 }
3183 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003184
Ed Warnickecb9cada2015-12-08 15:45:58 -07003185 return 0;
3186}
3187
3188static clib_error_t *
3189set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003190 unformat_input_t * input,
3191 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003192{
3193 u32 table_index = ~0;
3194 int table_index_set = 0;
3195 u32 sw_if_index = ~0;
3196 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003197
Dave Barachd7cb1b52016-12-09 09:52:16 -05003198 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3199 {
3200 if (unformat (input, "table-index %d", &table_index))
3201 table_index_set = 1;
3202 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3203 vnet_get_main (), &sw_if_index))
3204 ;
3205 else
3206 break;
3207 }
Dave Barach75fc8542016-10-11 16:16:02 -04003208
Ed Warnickecb9cada2015-12-08 15:45:58 -07003209 if (table_index_set == 0)
3210 return clib_error_return (0, "classify table-index must be specified");
3211
3212 if (sw_if_index == ~0)
3213 return clib_error_return (0, "interface / subif must be specified");
3214
3215 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3216
3217 switch (rv)
3218 {
3219 case 0:
3220 break;
3221
3222 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3223 return clib_error_return (0, "No such interface");
3224
3225 case VNET_API_ERROR_NO_SUCH_ENTRY:
3226 return clib_error_return (0, "No such classifier table");
3227 }
3228 return 0;
3229}
3230
Billy McFall0683c9c2016-10-13 08:27:31 -04003231/*?
3232 * Assign a classification table to an interface. The classification
3233 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3234 * commands. Once the table is create, use this command to filter packets
3235 * on an interface.
3236 *
3237 * @cliexpar
3238 * Example of how to assign a classification table to an interface:
3239 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3240?*/
3241/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003242VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3243{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003244 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003245 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003246 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003247 .function = set_ip_classify_command_fn,
3248};
Billy McFall0683c9c2016-10-13 08:27:31 -04003249/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003250
3251/*
3252 * fd.io coding-style-patch-verification: ON
3253 *
3254 * Local Variables:
3255 * eval: (c-set-style "gnu")
3256 * End:
3257 */