blob: 8081b34b3dc861722c5df0c6c76d4439cd01073b [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
1481static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001482ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001483{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001484 ip4_main_t *im = &ip4_main;
1485 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001486 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001487 u32 *from, *to_next, n_left_from, n_left_to_next;
1488 vlib_node_runtime_t *error_node =
1489 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490
1491 from = vlib_frame_vector_args (frame);
1492 n_left_from = frame->n_vectors;
1493 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001494
Ed Warnickecb9cada2015-12-08 15:45:58 -07001495 if (node->flags & VLIB_NODE_FLAG_TRACE)
1496 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1497
1498 while (n_left_from > 0)
1499 {
1500 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1501
1502 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001503 {
1504 vlib_buffer_t *p0, *p1;
1505 ip4_header_t *ip0, *ip1;
1506 udp_header_t *udp0, *udp1;
1507 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1508 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1509 const dpo_id_t *dpo0, *dpo1;
1510 const load_balance_t *lb0, *lb1;
1511 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1512 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1513 i32 len_diff0, len_diff1;
1514 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1515 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1516 u8 enqueue_code;
Dave Barach75fc8542016-10-11 16:16:02 -04001517
Dave Barachd7cb1b52016-12-09 09:52:16 -05001518 pi0 = to_next[0] = from[0];
1519 pi1 = to_next[1] = from[1];
1520 from += 2;
1521 n_left_from -= 2;
1522 to_next += 2;
1523 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001524
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525 p0 = vlib_get_buffer (vm, pi0);
1526 p1 = vlib_get_buffer (vm, pi1);
1527
1528 ip0 = vlib_buffer_get_current (p0);
1529 ip1 = vlib_buffer_get_current (p1);
1530
Dave Barachd7cb1b52016-12-09 09:52:16 -05001531 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1532 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001533
Dave Barachd7cb1b52016-12-09 09:52:16 -05001534 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1535 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
Neale Ranns32e1c012016-11-22 17:07:28 +00001536 fib_index0 =
1537 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1538 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001539
Dave Barachd7cb1b52016-12-09 09:52:16 -05001540 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1541 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Neale Ranns32e1c012016-11-22 17:07:28 +00001542 fib_index1 =
1543 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1544 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001545
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001546 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1547 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548
1549 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1550
Dave Barachd7cb1b52016-12-09 09:52:16 -05001551 leaf0 =
1552 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1553 leaf1 =
1554 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001555
John Lo3419d0b2016-06-02 09:28:37 -04001556 /* Treat IP frag packets as "experimental" protocol for now
1557 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001558 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1559 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001560 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1561 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1562 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1563 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1564
1565 flags0 = p0->flags;
1566 flags1 = p1->flags;
1567
1568 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1569 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1570
1571 udp0 = ip4_next_header (ip0);
1572 udp1 = ip4_next_header (ip1);
1573
1574 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1575 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1576 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1577
Dave Barachd7cb1b52016-12-09 09:52:16 -05001578 leaf0 =
1579 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1580 leaf1 =
1581 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001582
1583 /* Verify UDP length. */
1584 ip_len0 = clib_net_to_host_u16 (ip0->length);
1585 ip_len1 = clib_net_to_host_u16 (ip1->length);
1586 udp_len0 = clib_net_to_host_u16 (udp0->length);
1587 udp_len1 = clib_net_to_host_u16 (udp1->length);
1588
1589 len_diff0 = ip_len0 - udp_len0;
1590 len_diff1 = ip_len1 - udp_len1;
1591
1592 len_diff0 = is_udp0 ? len_diff0 : 0;
1593 len_diff1 = is_udp1 ? len_diff1 : 0;
1594
Dave Barachd7cb1b52016-12-09 09:52:16 -05001595 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1596 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 {
1598 if (is_tcp_udp0)
1599 {
1600 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001601 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001602 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1603 good_tcp_udp0 =
1604 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1605 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1606 }
1607 if (is_tcp_udp1)
1608 {
1609 if (is_tcp_udp1
Dave Barachd7cb1b52016-12-09 09:52:16 -05001610 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1612 good_tcp_udp1 =
1613 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1614 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1615 }
1616 }
1617
1618 good_tcp_udp0 &= len_diff0 >= 0;
1619 good_tcp_udp1 &= len_diff1 >= 0;
1620
Dave Barachd7cb1b52016-12-09 09:52:16 -05001621 leaf0 =
1622 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1623 leaf1 =
1624 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625
1626 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1627
1628 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1629 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1630
1631 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001632 error0 = (is_tcp_udp0 && !good_tcp_udp0
1633 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1634 error1 = (is_tcp_udp1 && !good_tcp_udp1
1635 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001636
Dave Barachd7cb1b52016-12-09 09:52:16 -05001637 leaf0 =
1638 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1639 leaf1 =
1640 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
1641 leaf0 =
1642 (leaf0 ==
1643 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1644 leaf1 =
1645 (leaf1 ==
1646 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001647
Dave Barachd7cb1b52016-12-09 09:52:16 -05001648 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1649 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1650 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001651
Dave Barachd7cb1b52016-12-09 09:52:16 -05001652 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1653 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1654 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001655
Dave Barachd7cb1b52016-12-09 09:52:16 -05001656 lb0 = load_balance_get (lbi0);
1657 lb1 = load_balance_get (lbi1);
1658 dpo0 = load_balance_get_bucket_i (lb0, 0);
1659 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001660
Dave Barach75fc8542016-10-11 16:16:02 -04001661 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001662 * Must have a route to source otherwise we drop the packet.
1663 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001664 *
1665 * The checks are:
1666 * - the source is a recieve => it's from us => bogus, do this
1667 * first since it sets a different error code.
1668 * - uRPF check for any route to source - accept if passes.
1669 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001670 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001671 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001672 dpo0->dpoi_type == DPO_RECEIVE) ?
1673 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1674 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1675 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001676 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001677 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001678 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679 dpo1->dpoi_type == DPO_RECEIVE) ?
1680 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1681 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1682 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001683 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001684 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685
1686 next0 = lm->local_next_by_ip_protocol[proto0];
1687 next1 = lm->local_next_by_ip_protocol[proto1];
1688
Dave Barachd7cb1b52016-12-09 09:52:16 -05001689 next0 =
1690 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1691 next1 =
1692 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001693
1694 p0->error = error0 ? error_node->errors[error0] : 0;
1695 p1->error = error1 ? error_node->errors[error1] : 0;
1696
Dave Barachd7cb1b52016-12-09 09:52:16 -05001697 enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001698
1699 if (PREDICT_FALSE (enqueue_code != 0))
1700 {
1701 switch (enqueue_code)
1702 {
1703 case 1:
1704 /* A B A */
1705 to_next[-2] = pi1;
1706 to_next -= 1;
1707 n_left_to_next += 1;
1708 vlib_set_next_frame_buffer (vm, node, next0, pi0);
1709 break;
1710
1711 case 2:
1712 /* A A B */
1713 to_next -= 1;
1714 n_left_to_next += 1;
1715 vlib_set_next_frame_buffer (vm, node, next1, pi1);
1716 break;
1717
1718 case 3:
1719 /* A B B or A B C */
1720 to_next -= 2;
1721 n_left_to_next += 2;
1722 vlib_set_next_frame_buffer (vm, node, next0, pi0);
1723 vlib_set_next_frame_buffer (vm, node, next1, pi1);
1724 if (next0 == next1)
1725 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001726 vlib_put_next_frame (vm, node, next_index,
1727 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 next_index = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001729 vlib_get_next_frame (vm, node, next_index, to_next,
1730 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001731 }
1732 break;
1733 }
1734 }
1735 }
1736
1737 while (n_left_from > 0 && n_left_to_next > 0)
1738 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001739 vlib_buffer_t *p0;
1740 ip4_header_t *ip0;
1741 udp_header_t *udp0;
1742 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001744 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001745 i32 len_diff0;
1746 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001747 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001748 const dpo_id_t *dpo0;
1749
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750 pi0 = to_next[0] = from[0];
1751 from += 1;
1752 n_left_from -= 1;
1753 to_next += 1;
1754 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001755
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756 p0 = vlib_get_buffer (vm, pi0);
1757
1758 ip0 = vlib_buffer_get_current (p0);
1759
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001761
Dave Barach75fc8542016-10-11 16:16:02 -04001762 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001763 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
Neale Ranns32e1c012016-11-22 17:07:28 +00001764 fib_index0 =
1765 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1766 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001767
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001768 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769
1770 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
1771
Dave Barachd7cb1b52016-12-09 09:52:16 -05001772 leaf0 =
1773 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774
John Lo3419d0b2016-06-02 09:28:37 -04001775 /* Treat IP frag packets as "experimental" protocol for now
1776 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001777 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1779 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1780
1781 flags0 = p0->flags;
1782
1783 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1784
1785 udp0 = ip4_next_header (ip0);
1786
1787 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1788 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1789
Dave Barachd7cb1b52016-12-09 09:52:16 -05001790 leaf0 =
1791 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001792
1793 /* Verify UDP length. */
1794 ip_len0 = clib_net_to_host_u16 (ip0->length);
1795 udp_len0 = clib_net_to_host_u16 (udp0->length);
1796
1797 len_diff0 = ip_len0 - udp_len0;
1798
1799 len_diff0 = is_udp0 ? len_diff0 : 0;
1800
Dave Barachd7cb1b52016-12-09 09:52:16 -05001801 if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001802 {
1803 if (is_tcp_udp0)
1804 {
1805 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001806 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001807 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1808 good_tcp_udp0 =
1809 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1810 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1811 }
1812 }
1813
1814 good_tcp_udp0 &= len_diff0 >= 0;
1815
Dave Barachd7cb1b52016-12-09 09:52:16 -05001816 leaf0 =
1817 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818
1819 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1820
1821 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1822
1823 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001824 error0 = (is_tcp_udp0 && !good_tcp_udp0
1825 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001826
Dave Barachd7cb1b52016-12-09 09:52:16 -05001827 leaf0 =
1828 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1829 leaf0 =
1830 (leaf0 ==
1831 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001832
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001833 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001834 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001835
Dave Barachd7cb1b52016-12-09 09:52:16 -05001836 lb0 = load_balance_get (lbi0);
1837 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001838
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001839 vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001840 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841
Neale Ranns3ee44042016-10-03 13:05:48 +01001842 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001843 dpo0->dpoi_type == DPO_RECEIVE) ?
1844 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1845 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1846 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001847 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001848 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001849
1850 next0 = lm->local_next_by_ip_protocol[proto0];
1851
Dave Barachd7cb1b52016-12-09 09:52:16 -05001852 next0 =
1853 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001854
Dave Barachd7cb1b52016-12-09 09:52:16 -05001855 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856
1857 if (PREDICT_FALSE (next0 != next_index))
1858 {
1859 n_left_to_next += 1;
1860 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1861
1862 next_index = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001863 vlib_get_next_frame (vm, node, next_index, to_next,
1864 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865 to_next[0] = pi0;
1866 to_next += 1;
1867 n_left_to_next -= 1;
1868 }
1869 }
Dave Barach75fc8542016-10-11 16:16:02 -04001870
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1872 }
1873
1874 return frame->n_vectors;
1875}
1876
Neale Ranns32e1c012016-11-22 17:07:28 +00001877VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001878{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001879 .function = ip4_local,.name = "ip4-local",.vector_size =
Neale Ranns32e1c012016-11-22 17:07:28 +00001880 sizeof (u32),.format_trace =
1881 format_ip4_forward_next_trace,.n_next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001882 IP_LOCAL_N_NEXT,.next_nodes =
1883 {
1884 [IP_LOCAL_NEXT_DROP] = "error-drop",
1885 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1886 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1887 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",}
1888,};
1889
1890VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1891
1892void
1893ip4_register_protocol (u32 protocol, u32 node_index)
1894{
1895 vlib_main_t *vm = vlib_get_main ();
1896 ip4_main_t *im = &ip4_main;
1897 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001898
1899 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001900 lm->local_next_by_ip_protocol[protocol] =
1901 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902}
1903
1904static clib_error_t *
1905show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001906 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001908 ip4_main_t *im = &ip4_main;
1909 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001910 int i;
1911
1912 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001913 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001914 {
1915 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001916 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001917 }
1918 return 0;
1919}
1920
1921
1922
Billy McFall0683c9c2016-10-13 08:27:31 -04001923/*?
1924 * Display the set of protocols handled by the local IPv4 stack.
1925 *
1926 * @cliexpar
1927 * Example of how to display local protocol table:
1928 * @cliexstart{show ip local}
1929 * Protocols handled by ip4_local
1930 * 1
1931 * 17
1932 * 47
1933 * @cliexend
1934?*/
1935/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936VLIB_CLI_COMMAND (show_ip_local, static) =
1937{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001938 .path = "show ip local",
1939 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001940 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941};
Billy McFall0683c9c2016-10-13 08:27:31 -04001942/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001943
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001944always_inline uword
1945ip4_arp_inline (vlib_main_t * vm,
1946 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001947 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001949 vnet_main_t *vnm = vnet_get_main ();
1950 ip4_main_t *im = &ip4_main;
1951 ip_lookup_main_t *lm = &im->lookup_main;
1952 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001953 uword n_left_from, n_left_to_next_drop, next_index;
1954 static f64 time_last_seed_change = -1e100;
1955 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001956 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001957 f64 time_now;
1958
1959 if (node->flags & VLIB_NODE_FLAG_TRACE)
1960 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1961
1962 time_now = vlib_time_now (vm);
1963 if (time_now - time_last_seed_change > 1e-3)
1964 {
1965 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001966 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1967 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1969 hash_seeds[i] = r[i];
1970
1971 /* Mark all hash keys as been no-seen before. */
1972 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1973 hash_bitmap[i] = 0;
1974
1975 time_last_seed_change = time_now;
1976 }
1977
1978 from = vlib_frame_vector_args (frame);
1979 n_left_from = frame->n_vectors;
1980 next_index = node->cached_next_index;
1981 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001982 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983
1984 while (n_left_from > 0)
1985 {
1986 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1987 to_next_drop, n_left_to_next_drop);
1988
1989 while (n_left_from > 0 && n_left_to_next_drop > 0)
1990 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001991 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001992 ip_adjacency_t *adj0;
1993 vlib_buffer_t *p0;
1994 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001996
1997 pi0 = from[0];
1998
1999 p0 = vlib_get_buffer (vm, pi0);
2000
2001 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2002 adj0 = ip_get_adjacency (lm, adj_index0);
2003 ip0 = vlib_buffer_get_current (p0);
2004
Ed Warnickecb9cada2015-12-08 15:45:58 -07002005 a0 = hash_seeds[0];
2006 b0 = hash_seeds[1];
2007 c0 = hash_seeds[2];
2008
2009 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2010 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2011
Dave Barachd7cb1b52016-12-09 09:52:16 -05002012 if (is_glean)
2013 {
Neale Ranns948e00f2016-10-20 13:39:34 +01002014 /*
2015 * this is the Glean case, so we are ARPing for the
2016 * packet's destination
2017 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002018 a0 ^= ip0->dst_address.data_u32;
2019 }
2020 else
2021 {
2022 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
2023 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002024 b0 ^= sw_if_index0;
2025
2026 hash_v3_finalize32 (a0, b0, c0);
2027
2028 c0 &= BITS (hash_bitmap) - 1;
2029 c0 = c0 / BITS (uword);
2030 m0 = (uword) 1 << (c0 % BITS (uword));
2031
2032 bm0 = hash_bitmap[c0];
2033 drop0 = (bm0 & m0) != 0;
2034
2035 /* Mark it as seen. */
2036 hash_bitmap[c0] = bm0 | m0;
2037
2038 from += 1;
2039 n_left_from -= 1;
2040 to_next_drop[0] = pi0;
2041 to_next_drop += 1;
2042 n_left_to_next_drop -= 1;
2043
Dave Barachd7cb1b52016-12-09 09:52:16 -05002044 p0->error =
2045 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2046 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047
Neale Rannsb80c5362016-10-08 13:03:40 +01002048 /*
2049 * the adj has been updated to a rewrite but the node the DPO that got
2050 * us here hasn't - yet. no big deal. we'll drop while we wait.
2051 */
2052 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2053 continue;
2054
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055 if (drop0)
2056 continue;
2057
Dave Barachd7cb1b52016-12-09 09:52:16 -05002058 /*
2059 * Can happen if the control-plane is programming tables
2060 * with traffic flowing; at least that's today's lame excuse.
2061 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002062 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2063 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002064 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002065 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002066 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002067 else
2068 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002069 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002070 u32 bi0 = 0;
2071 vlib_buffer_t *b0;
2072 ethernet_arp_header_t *h0;
2073 vnet_hw_interface_t *hw_if0;
2074
2075 h0 =
2076 vlib_packet_template_get_packet (vm,
2077 &im->ip4_arp_request_packet_template,
2078 &bi0);
2079
2080 /* Add rewrite/encap string for ARP packet. */
2081 vnet_rewrite_one_header (adj0[0], h0,
2082 sizeof (ethernet_header_t));
2083
2084 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2085
2086 /* Src ethernet address in ARP header. */
2087 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2088 hw_if0->hw_address,
2089 sizeof (h0->ip4_over_ethernet[0].ethernet));
2090
2091 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002092 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002093 /* The interface's source address is stashed in the Glean Adj */
2094 h0->ip4_over_ethernet[0].ip4 =
2095 adj0->sub_type.glean.receive_addr.ip4;
2096
2097 /* Copy in destination address we are requesting. This is the
2098 * glean case, so it's the packet's destination.*/
2099 h0->ip4_over_ethernet[1].ip4.data_u32 =
2100 ip0->dst_address.data_u32;
2101 }
2102 else
2103 {
2104 /* Src IP address in ARP header. */
2105 if (ip4_src_address_for_packet (lm, sw_if_index0,
2106 &h0->
2107 ip4_over_ethernet[0].ip4))
2108 {
2109 /* No source address available */
2110 p0->error =
2111 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2112 vlib_buffer_free (vm, &bi0, 1);
2113 continue;
2114 }
2115
2116 /* Copy in destination address we are requesting from the
2117 incomplete adj */
2118 h0->ip4_over_ethernet[1].ip4.data_u32 =
2119 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002120 }
2121
Dave Barachd7cb1b52016-12-09 09:52:16 -05002122 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2123 b0 = vlib_get_buffer (vm, bi0);
2124 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2125
2126 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2127
2128 vlib_set_next_frame_buffer (vm, node,
2129 adj0->rewrite_header.next_index,
2130 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002131 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132 }
2133
2134 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2135 }
2136
2137 return frame->n_vectors;
2138}
2139
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002140static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002141ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002142{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002143 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002144}
2145
2146static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002147ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002148{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002149 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002150}
2151
Dave Barachd7cb1b52016-12-09 09:52:16 -05002152static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002153 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2154 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2155 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2156 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2157 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002158 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002159};
2160
Dave Barachd7cb1b52016-12-09 09:52:16 -05002161VLIB_REGISTER_NODE (ip4_arp_node) =
2162{
2163 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2164 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2165 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2166 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2167 {
2168 [IP4_ARP_NEXT_DROP] = "error-drop",}
2169,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170
Dave Barachd7cb1b52016-12-09 09:52:16 -05002171VLIB_REGISTER_NODE (ip4_glean_node) =
2172{
2173 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2174 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2175 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2176 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2177 {
2178 [IP4_ARP_NEXT_DROP] = "error-drop",}
2179,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002180
Ed Warnickecb9cada2015-12-08 15:45:58 -07002181#define foreach_notrace_ip4_arp_error \
2182_(DROP) \
2183_(REQUEST_SENT) \
2184_(REPLICATE_DROP) \
2185_(REPLICATE_FAIL)
2186
Dave Barachd7cb1b52016-12-09 09:52:16 -05002187clib_error_t *
2188arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002189{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002190 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002191
2192 /* don't trace ARP request packets */
2193#define _(a) \
2194 vnet_pcap_drop_trace_filter_add_del \
2195 (rt->errors[IP4_ARP_ERROR_##a], \
2196 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002197 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198#undef _
2199 return 0;
2200}
2201
Dave Barachd7cb1b52016-12-09 09:52:16 -05002202VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203
2204
2205/* Send an ARP request to see if given destination is reachable on given interface. */
2206clib_error_t *
2207ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2208{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002209 vnet_main_t *vnm = vnet_get_main ();
2210 ip4_main_t *im = &ip4_main;
2211 ethernet_arp_header_t *h;
2212 ip4_address_t *src;
2213 ip_interface_address_t *ia;
2214 ip_adjacency_t *adj;
2215 vnet_hw_interface_t *hi;
2216 vnet_sw_interface_t *si;
2217 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002218 u32 bi = 0;
2219
2220 si = vnet_get_sw_interface (vnm, sw_if_index);
2221
2222 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2223 {
2224 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002225 format_ip4_address, dst,
2226 format_vnet_sw_if_index_name, vnm,
2227 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228 }
2229
Dave Barachd7cb1b52016-12-09 09:52:16 -05002230 src =
2231 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2232 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002233 {
2234 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002235 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002236 (0,
2237 "no matching interface address for destination %U (interface %U)",
2238 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2239 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002240 }
2241
2242 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2243
Dave Barachd7cb1b52016-12-09 09:52:16 -05002244 h =
Neale Ranns32e1c012016-11-22 17:07:28 +00002245 vlib_packet_template_get_packet (vm,
2246 &im->ip4_arp_request_packet_template,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002247 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248
2249 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2250
Dave Barachd7cb1b52016-12-09 09:52:16 -05002251 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2252 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002253
2254 h->ip4_over_ethernet[0].ip4 = src[0];
2255 h->ip4_over_ethernet[1].ip4 = dst[0];
2256
2257 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002258 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2259 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260
2261 /* Add encapsulation string for software interface (e.g. ethernet header). */
2262 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2263 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2264
2265 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002266 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2267 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002268 to_next[0] = bi;
2269 f->n_vectors = 1;
2270 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2271 }
2272
2273 return /* no error */ 0;
2274}
2275
Dave Barachd7cb1b52016-12-09 09:52:16 -05002276typedef enum
2277{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002279 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280} ip4_rewrite_next_t;
2281
2282always_inline uword
2283ip4_rewrite_inline (vlib_main_t * vm,
2284 vlib_node_runtime_t * node,
Neale Ranns32e1c012016-11-22 17:07:28 +00002285 vlib_frame_t * frame, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002287 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2288 u32 *from = vlib_frame_vector_args (frame);
2289 u32 n_left_from, n_left_to_next, *to_next, next_index;
2290 vlib_node_runtime_t *error_node =
2291 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292
2293 n_left_from = frame->n_vectors;
2294 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002295 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04002296
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 while (n_left_from > 0)
2298 {
2299 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2300
2301 while (n_left_from >= 4 && n_left_to_next >= 2)
2302 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002303 ip_adjacency_t *adj0, *adj1;
2304 vlib_buffer_t *p0, *p1;
2305 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2307 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002308 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002309
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 /* Prefetch next iteration. */
2311 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002312 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
2314 p2 = vlib_get_buffer (vm, from[2]);
2315 p3 = vlib_get_buffer (vm, from[3]);
2316
2317 vlib_prefetch_buffer_header (p2, STORE);
2318 vlib_prefetch_buffer_header (p3, STORE);
2319
2320 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2321 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2322 }
2323
2324 pi0 = to_next[0] = from[0];
2325 pi1 = to_next[1] = from[1];
2326
2327 from += 2;
2328 n_left_from -= 2;
2329 to_next += 2;
2330 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002331
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332 p0 = vlib_get_buffer (vm, pi0);
2333 p1 = vlib_get_buffer (vm, pi1);
2334
Neale Rannsf06aea52016-11-29 06:51:37 -08002335 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2336 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002337
Dave Barachd7cb1b52016-12-09 09:52:16 -05002338 /* We should never rewrite a pkt using the MISS adjacency */
2339 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002340
2341 ip0 = vlib_buffer_get_current (p0);
2342 ip1 = vlib_buffer_get_current (p1);
2343
2344 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002345 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346
2347 /* Decrement TTL & update checksum.
2348 Works either endian, so no need for byte swap. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002349 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002350 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002351 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002352
2353 /* Input node should have reject packets with ttl 0. */
2354 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002355
2356 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002357 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002358
2359 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002361 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002362
Dave Barachd7cb1b52016-12-09 09:52:16 -05002363 /*
2364 * If the ttl drops below 1 when forwarding, generate
2365 * an ICMP response.
2366 */
2367 if (PREDICT_FALSE (ttl0 <= 0))
2368 {
2369 error0 = IP4_ERROR_TIME_EXPIRED;
2370 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2371 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2372 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2373 0);
2374 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2375 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002376
2377 /* Verify checksum. */
2378 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2379 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002380 else
2381 {
2382 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2383 }
2384 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002385 {
2386 i32 ttl1 = ip1->ttl;
2387
2388 /* Input node should have reject packets with ttl 0. */
2389 ASSERT (ip1->ttl > 0);
2390
2391 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2392 checksum1 += checksum1 >= 0xffff;
2393
2394 ip1->checksum = checksum1;
2395 ttl1 -= 1;
2396 ip1->ttl = ttl1;
2397
Dave Barachd7cb1b52016-12-09 09:52:16 -05002398 /*
2399 * If the ttl drops below 1 when forwarding, generate
2400 * an ICMP response.
2401 */
2402 if (PREDICT_FALSE (ttl1 <= 0))
2403 {
2404 error1 = IP4_ERROR_TIME_EXPIRED;
2405 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2406 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2407 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2408 0);
2409 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2410 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002411
2412 /* Verify checksum. */
2413 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2414 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2415 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002416 else
2417 {
2418 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2419 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002420
2421 /* Rewrite packet header and updates lengths. */
2422 adj0 = ip_get_adjacency (lm, adj_index0);
2423 adj1 = ip_get_adjacency (lm, adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002424
Dave Barachd7cb1b52016-12-09 09:52:16 -05002425 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002426 rw_len0 = adj0[0].rewrite_header.data_bytes;
2427 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002428 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2429 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002430
Dave Barachd7cb1b52016-12-09 09:52:16 -05002431 /* Check MTU of outgoing interface. */
2432 error0 =
2433 (vlib_buffer_length_in_chain (vm, p0) >
2434 adj0[0].
2435 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2436 error0);
2437 error1 =
2438 (vlib_buffer_length_in_chain (vm, p1) >
2439 adj1[0].
2440 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2441 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002442
Dave Barachd7cb1b52016-12-09 09:52:16 -05002443 /*
Neale Ranns044183f2017-01-24 01:34:25 -08002444 * pre-fetch the per-adjacency counters
Dave Barachd7cb1b52016-12-09 09:52:16 -05002445 */
Neale Ranns044183f2017-01-24 01:34:25 -08002446 vlib_prefetch_combined_counter (&adjacency_counters,
2447 cpu_index, adj_index0);
2448 vlib_prefetch_combined_counter (&adjacency_counters,
2449 cpu_index, adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002450
Dave Barachd7cb1b52016-12-09 09:52:16 -05002451 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2452 * to see the IP headerr */
2453 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2454 {
Damjan Marion892e0762016-12-09 18:52:05 +01002455 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002456 p0->current_data -= rw_len0;
2457 p0->current_length += rw_len0;
2458 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2459 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002460
Dave Barachd7cb1b52016-12-09 09:52:16 -05002461 vnet_feature_arc_start (lm->output_feature_arc_index,
2462 tx_sw_if_index0, &next0, p0);
2463 }
2464 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2465 {
Damjan Marion892e0762016-12-09 18:52:05 +01002466 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002467 p1->current_data -= rw_len1;
2468 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002469
Dave Barachd7cb1b52016-12-09 09:52:16 -05002470 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2471 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002472
Dave Barachd7cb1b52016-12-09 09:52:16 -05002473 vnet_feature_arc_start (lm->output_feature_arc_index,
2474 tx_sw_if_index1, &next1, p1);
2475 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476
2477 /* Guess we are only writing on simple Ethernet header. */
2478 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002479 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002480
Neale Ranns044183f2017-01-24 01:34:25 -08002481 /*
2482 * Bump the per-adjacency counters
2483 */
2484 vlib_increment_combined_counter
2485 (&adjacency_counters,
2486 cpu_index,
2487 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2488
2489 vlib_increment_combined_counter
2490 (&adjacency_counters,
2491 cpu_index,
2492 adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2493
Neale Ranns5e575b12016-10-03 09:40:25 +01002494 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002495 {
2496 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2497 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2498 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002499 if (is_mcast)
2500 {
2501 /*
2502 * copy bytes from the IP address into the MAC rewrite
2503 */
2504 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2505 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 1);
2506 }
Dave Barach75fc8542016-10-11 16:16:02 -04002507
Ed Warnickecb9cada2015-12-08 15:45:58 -07002508 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2509 to_next, n_left_to_next,
2510 pi0, pi1, next0, next1);
2511 }
2512
2513 while (n_left_from > 0 && n_left_to_next > 0)
2514 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002515 ip_adjacency_t *adj0;
2516 vlib_buffer_t *p0;
2517 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002518 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002520
Ed Warnickecb9cada2015-12-08 15:45:58 -07002521 pi0 = to_next[0] = from[0];
2522
2523 p0 = vlib_get_buffer (vm, pi0);
2524
Neale Rannsf06aea52016-11-29 06:51:37 -08002525 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002526
Dave Barachd7cb1b52016-12-09 09:52:16 -05002527 /* We should never rewrite a pkt using the MISS adjacency */
2528 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002529
2530 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002531
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532 ip0 = vlib_buffer_get_current (p0);
2533
2534 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002535 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002536
2537 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002538 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002539 {
2540 i32 ttl0 = ip0->ttl;
2541
2542 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2543
2544 checksum0 += checksum0 >= 0xffff;
2545
2546 ip0->checksum = checksum0;
2547
2548 ASSERT (ip0->ttl > 0);
2549
2550 ttl0 -= 1;
2551
2552 ip0->ttl = ttl0;
2553
2554 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2555
Dave Barachd7cb1b52016-12-09 09:52:16 -05002556 if (PREDICT_FALSE (ttl0 <= 0))
2557 {
2558 /*
2559 * If the ttl drops below 1 when forwarding, generate
2560 * an ICMP response.
2561 */
2562 error0 = IP4_ERROR_TIME_EXPIRED;
2563 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2564 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2565 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2566 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2567 0);
2568 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002569 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002570 else
2571 {
2572 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2573 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002574
Neale Ranns044183f2017-01-24 01:34:25 -08002575 vlib_prefetch_combined_counter (&adjacency_counters,
2576 cpu_index, adj_index0);
2577
Ed Warnickecb9cada2015-12-08 15:45:58 -07002578 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002579 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002580 if (is_mcast)
2581 {
2582 /*
2583 * copy bytes from the IP address into the MAC rewrite
2584 */
2585 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1);
2586 }
Dave Barach75fc8542016-10-11 16:16:02 -04002587
Dave Barachd7cb1b52016-12-09 09:52:16 -05002588 /* Update packet buffer attributes/set output interface. */
2589 rw_len0 = adj0[0].rewrite_header.data_bytes;
2590 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002591
Neale Ranns044183f2017-01-24 01:34:25 -08002592 vlib_increment_combined_counter
2593 (&adjacency_counters,
2594 cpu_index,
2595 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002596
Dave Barachd7cb1b52016-12-09 09:52:16 -05002597 /* Check MTU of outgoing interface. */
2598 error0 = (vlib_buffer_length_in_chain (vm, p0)
2599 > adj0[0].rewrite_header.max_l3_packet_bytes
2600 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002601
Ed Warnickecb9cada2015-12-08 15:45:58 -07002602 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002603
Dave Barachd7cb1b52016-12-09 09:52:16 -05002604 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2605 * to see the IP headerr */
2606 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2607 {
2608 p0->current_data -= rw_len0;
2609 p0->current_length += rw_len0;
2610 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002611
Dave Barachd7cb1b52016-12-09 09:52:16 -05002612 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2613 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002614
Neale Ranns5e575b12016-10-03 09:40:25 +01002615 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002616 {
2617 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002618 }
2619
Dave Barachd7cb1b52016-12-09 09:52:16 -05002620 vnet_feature_arc_start (lm->output_feature_arc_index,
2621 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002622
Dave Barachd7cb1b52016-12-09 09:52:16 -05002623 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002624
Ed Warnickecb9cada2015-12-08 15:45:58 -07002625 from += 1;
2626 n_left_from -= 1;
2627 to_next += 1;
2628 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002629
Ed Warnickecb9cada2015-12-08 15:45:58 -07002630 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2631 to_next, n_left_to_next,
2632 pi0, next0);
2633 }
Dave Barach75fc8542016-10-11 16:16:02 -04002634
Ed Warnickecb9cada2015-12-08 15:45:58 -07002635 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2636 }
2637
2638 /* Need to do trace after rewrites to pick up new packet data. */
2639 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002640 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002641
2642 return frame->n_vectors;
2643}
2644
Dave Barach132d51d2016-07-07 10:10:17 -04002645
Neale Rannsf06aea52016-11-29 06:51:37 -08002646/** @brief IPv4 rewrite node.
2647 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002648
2649 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2650 header checksum, fetch the ip adjacency, check the outbound mtu,
2651 apply the adjacency rewrite, and send pkts to the adjacency
2652 rewrite header's rewrite_next_index.
2653
2654 @param vm vlib_main_t corresponding to the current thread
2655 @param node vlib_node_runtime_t
2656 @param frame vlib_frame_t whose contents should be dispatched
2657
2658 @par Graph mechanics: buffer metadata, next index usage
2659
2660 @em Uses:
2661 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2662 - the rewrite adjacency index
2663 - <code>adj->lookup_next_index</code>
2664 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002665 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002666 - <code>adj->rewrite_header</code>
2667 - Rewrite string length, rewrite string, next_index
2668
2669 @em Sets:
2670 - <code>b->current_data, b->current_length</code>
2671 - Updated net of applying the rewrite string
2672
2673 <em>Next Indices:</em>
2674 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002675 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002676*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002678ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002679 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002680{
Neale Ranns32e1c012016-11-22 17:07:28 +00002681 return ip4_rewrite_inline (vm, node, frame, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002682}
2683
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002684static uword
2685ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002686 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002687{
Neale Ranns32e1c012016-11-22 17:07:28 +00002688 return ip4_rewrite_inline (vm, node, frame, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002689}
2690
Neale Ranns32e1c012016-11-22 17:07:28 +00002691static uword
2692ip4_rewrite_mcast (vlib_main_t * vm,
2693 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002694{
Neale Ranns32e1c012016-11-22 17:07:28 +00002695 return ip4_rewrite_inline (vm, node, frame, 0, 1);
2696}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002697
Neale Ranns32e1c012016-11-22 17:07:28 +00002698/* *INDENT-OFF* */
2699VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2700 .function = ip4_rewrite,
2701 .name = "ip4-rewrite",
2702 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002703
Neale Ranns32e1c012016-11-22 17:07:28 +00002704 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002705
Neale Ranns32e1c012016-11-22 17:07:28 +00002706 .n_next_nodes = 2,
2707 .next_nodes = {
2708 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2709 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2710 },
2711};
2712VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2713
2714VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2715 .function = ip4_rewrite_mcast,
2716 .name = "ip4-rewrite-mcast",
2717 .vector_size = sizeof (u32),
2718
2719 .format_trace = format_ip4_rewrite_trace,
2720 .sibling_of = "ip4-rewrite",
2721};
2722VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2723
2724VLIB_REGISTER_NODE (ip4_midchain_node) = {
2725 .function = ip4_midchain,
2726 .name = "ip4-midchain",
2727 .vector_size = sizeof (u32),
2728 .format_trace = format_ip4_forward_next_trace,
2729 .sibling_of = "ip4-rewrite",
2730};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002731VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002732/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002733
Ed Warnickecb9cada2015-12-08 15:45:58 -07002734static clib_error_t *
2735add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002736 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002738 vnet_main_t *vnm = vnet_get_main ();
2739 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002740 u32 sw_if_index, table_id;
2741
2742 sw_if_index = ~0;
2743
Dave Barachd7cb1b52016-12-09 09:52:16 -05002744 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002745 {
2746 error = clib_error_return (0, "unknown interface `%U'",
2747 format_unformat_error, input);
2748 goto done;
2749 }
2750
2751 if (unformat (input, "%d", &table_id))
2752 ;
2753 else
2754 {
2755 error = clib_error_return (0, "expected table id `%U'",
2756 format_unformat_error, input);
2757 goto done;
2758 }
2759
2760 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002761 ip4_main_t *im = &ip4_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002762 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002763
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002764 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002765 table_id);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002766
2767 //
2768 // FIXME-LATER
2769 // changing an interface's table has consequences for any connecteds
2770 // and adj-fibs already installed.
2771 //
2772 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2773 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002774
2775 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2776 table_id);
2777 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
2778 im->mfib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779 }
2780
Dave Barachd7cb1b52016-12-09 09:52:16 -05002781done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002782 return error;
2783}
2784
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002785/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002786 * Place the indicated interface into the supplied IPv4 FIB table (also known
2787 * as a VRF). If the FIB table does not exist, this command creates it. To
2788 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2789 * FIB table will only be displayed if a route has been added to the table, or
2790 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002791 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002792 *
2793 * @note IP addresses added after setting the interface IP table end up in
2794 * the indicated FIB table. If the IP address is added prior to adding the
2795 * interface to the FIB table, it will NOT be part of the FIB table. Predictable
2796 * but potentially counter-intuitive results occur if you provision interface
2797 * addresses in multiple FIBs. Upon RX, packets will be processed in the last
2798 * IP table ID provisioned. It might be marginally useful to evade source RPF
2799 * drops to put an interface address into multiple FIBs.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002800 *
2801 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002802 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2803 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002804 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002805/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002806VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2807{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002808 .path = "set interface ip table",
2809 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002810 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002811};
Billy McFall0683c9c2016-10-13 08:27:31 -04002812/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002813
Dave Barachd7cb1b52016-12-09 09:52:16 -05002814int
2815ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2816{
2817 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002818 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002819 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002820
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002821 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002822
2823 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2824 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
2825 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
2826 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2827 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002828
Ed Warnickecb9cada2015-12-08 15:45:58 -07002829 /* Handle default route. */
2830 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002831
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002832 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002833
Dave Barachd7cb1b52016-12-09 09:52:16 -05002834 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002835}
Dave Barach75fc8542016-10-11 16:16:02 -04002836
Ed Warnickecb9cada2015-12-08 15:45:58 -07002837static clib_error_t *
2838test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002839 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002840{
Billy McFall309fe062016-10-14 07:37:33 -04002841 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842 u32 table_id = 0;
2843 f64 count = 1;
2844 u32 n;
2845 int i;
2846 ip4_address_t ip4_base_address;
2847 u64 errors = 0;
2848
Dave Barachd7cb1b52016-12-09 09:52:16 -05002849 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2850 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002851 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002852 {
2853 /* Make sure the entry exists. */
2854 fib = ip4_fib_get (table_id);
2855 if ((fib) && (fib->index != table_id))
2856 return clib_error_return (0, "<fib-index> %d does not exist",
2857 table_id);
2858 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002859 else if (unformat (input, "count %f", &count))
2860 ;
2861
2862 else if (unformat (input, "%U",
2863 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002864 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002865 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002866 return clib_error_return (0, "unknown input `%U'",
2867 format_unformat_error, input);
2868 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002869
2870 n = count;
2871
2872 for (i = 0; i < n; i++)
2873 {
2874 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002875 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002876
Dave Barach75fc8542016-10-11 16:16:02 -04002877 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002878 clib_host_to_net_u32 (1 +
2879 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002880 }
2881
Dave Barach75fc8542016-10-11 16:16:02 -04002882 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002883 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2884 else
2885 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2886
2887 return 0;
2888}
2889
Billy McFall0683c9c2016-10-13 08:27:31 -04002890/*?
2891 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2892 * given FIB table to determine if there is a conflict with the
2893 * adjacency table. The fib-id can be determined by using the
2894 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2895 * of 0 is used.
2896 *
2897 * @todo This command uses fib-id, other commands use table-id (not
2898 * just a name, they are different indexes). Would like to change this
2899 * to table-id for consistency.
2900 *
2901 * @cliexpar
2902 * Example of how to run the test lookup command:
2903 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2904 * No errors in 2 lookups
2905 * @cliexend
2906?*/
2907/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002908VLIB_CLI_COMMAND (lookup_test_command, static) =
2909{
2910 .path = "test lookup",
2911 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2912 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002913};
Billy McFall0683c9c2016-10-13 08:27:31 -04002914/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002915
Dave Barachd7cb1b52016-12-09 09:52:16 -05002916int
2917vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002918{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002919 ip4_main_t *im4 = &ip4_main;
2920 ip4_fib_t *fib;
2921 uword *p = hash_get (im4->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002922
2923 if (p == 0)
2924 return VNET_API_ERROR_NO_SUCH_FIB;
2925
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002926 fib = ip4_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002927
2928 fib->flow_hash_config = flow_hash_config;
2929 return 0;
2930}
Dave Barach75fc8542016-10-11 16:16:02 -04002931
Ed Warnickecb9cada2015-12-08 15:45:58 -07002932static clib_error_t *
2933set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002934 unformat_input_t * input,
2935 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002936{
2937 int matched = 0;
2938 u32 table_id = 0;
2939 u32 flow_hash_config = 0;
2940 int rv;
2941
Dave Barachd7cb1b52016-12-09 09:52:16 -05002942 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2943 {
2944 if (unformat (input, "table %d", &table_id))
2945 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946#define _(a,v) \
2947 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002948 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002949#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002950 else
2951 break;
2952 }
Dave Barach75fc8542016-10-11 16:16:02 -04002953
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954 if (matched == 0)
2955 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002956 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002957
Ed Warnickecb9cada2015-12-08 15:45:58 -07002958 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2959 switch (rv)
2960 {
2961 case 0:
2962 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002963
Ed Warnickecb9cada2015-12-08 15:45:58 -07002964 case VNET_API_ERROR_NO_SUCH_FIB:
2965 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002966
Ed Warnickecb9cada2015-12-08 15:45:58 -07002967 default:
2968 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2969 break;
2970 }
Dave Barach75fc8542016-10-11 16:16:02 -04002971
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972 return 0;
2973}
Dave Barach75fc8542016-10-11 16:16:02 -04002974
Billy McFall0683c9c2016-10-13 08:27:31 -04002975/*?
2976 * Configure the set of IPv4 fields used by the flow hash.
2977 *
2978 * @cliexpar
2979 * Example of how to set the flow hash on a given table:
2980 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2981 * Example of display the configured flow hash:
2982 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002983 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2984 * 0.0.0.0/0
2985 * unicast-ip4-chain
2986 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2987 * [0] [@0]: dpo-drop ip6
2988 * 0.0.0.0/32
2989 * unicast-ip4-chain
2990 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2991 * [0] [@0]: dpo-drop ip6
2992 * 224.0.0.0/8
2993 * unicast-ip4-chain
2994 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2995 * [0] [@0]: dpo-drop ip6
2996 * 6.0.1.2/32
2997 * unicast-ip4-chain
2998 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2999 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3000 * 7.0.0.1/32
3001 * unicast-ip4-chain
3002 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3003 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3004 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3005 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3006 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3007 * 240.0.0.0/8
3008 * unicast-ip4-chain
3009 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3010 * [0] [@0]: dpo-drop ip6
3011 * 255.255.255.255/32
3012 * unicast-ip4-chain
3013 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3014 * [0] [@0]: dpo-drop ip6
3015 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3016 * 0.0.0.0/0
3017 * unicast-ip4-chain
3018 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3019 * [0] [@0]: dpo-drop ip6
3020 * 0.0.0.0/32
3021 * unicast-ip4-chain
3022 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3023 * [0] [@0]: dpo-drop ip6
3024 * 172.16.1.0/24
3025 * unicast-ip4-chain
3026 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3027 * [0] [@4]: ipv4-glean: af_packet0
3028 * 172.16.1.1/32
3029 * unicast-ip4-chain
3030 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3031 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3032 * 172.16.1.2/32
3033 * unicast-ip4-chain
3034 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3035 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3036 * 172.16.2.0/24
3037 * unicast-ip4-chain
3038 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3039 * [0] [@4]: ipv4-glean: af_packet1
3040 * 172.16.2.1/32
3041 * unicast-ip4-chain
3042 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3043 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3044 * 224.0.0.0/8
3045 * unicast-ip4-chain
3046 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3047 * [0] [@0]: dpo-drop ip6
3048 * 240.0.0.0/8
3049 * unicast-ip4-chain
3050 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3051 * [0] [@0]: dpo-drop ip6
3052 * 255.255.255.255/32
3053 * unicast-ip4-chain
3054 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3055 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003056 * @cliexend
3057?*/
3058/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003059VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3060{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003062 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003063 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003064 .function = set_ip_flow_hash_command_fn,
3065};
Billy McFall0683c9c2016-10-13 08:27:31 -04003066/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003067
Dave Barachd7cb1b52016-12-09 09:52:16 -05003068int
3069vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3070 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003071{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003072 vnet_main_t *vnm = vnet_get_main ();
3073 vnet_interface_main_t *im = &vnm->interface_main;
3074 ip4_main_t *ipm = &ip4_main;
3075 ip_lookup_main_t *lm = &ipm->lookup_main;
3076 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003077 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003078
3079 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3080 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3081
3082 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3083 return VNET_API_ERROR_NO_SUCH_ENTRY;
3084
3085 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003086 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087
Neale Rannsdf089a82016-10-02 16:39:06 +01003088 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3089
3090 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003091 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003092 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003093 .fp_len = 32,
3094 .fp_proto = FIB_PROTOCOL_IP4,
3095 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003096 };
3097 u32 fib_index;
3098
Dave Barachd7cb1b52016-12-09 09:52:16 -05003099 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3100 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003101
3102
Dave Barachd7cb1b52016-12-09 09:52:16 -05003103 if (table_index != (u32) ~ 0)
3104 {
3105 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003106
Dave Barachd7cb1b52016-12-09 09:52:16 -05003107 dpo_set (&dpo,
3108 DPO_CLASSIFY,
3109 DPO_PROTO_IP4,
3110 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003111
Dave Barachd7cb1b52016-12-09 09:52:16 -05003112 fib_table_entry_special_dpo_add (fib_index,
3113 &pfx,
3114 FIB_SOURCE_CLASSIFY,
3115 FIB_ENTRY_FLAG_NONE, &dpo);
3116 dpo_reset (&dpo);
3117 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003118 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003119 {
3120 fib_table_entry_special_remove (fib_index,
3121 &pfx, FIB_SOURCE_CLASSIFY);
3122 }
3123 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003124
Ed Warnickecb9cada2015-12-08 15:45:58 -07003125 return 0;
3126}
3127
3128static clib_error_t *
3129set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003130 unformat_input_t * input,
3131 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003132{
3133 u32 table_index = ~0;
3134 int table_index_set = 0;
3135 u32 sw_if_index = ~0;
3136 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003137
Dave Barachd7cb1b52016-12-09 09:52:16 -05003138 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3139 {
3140 if (unformat (input, "table-index %d", &table_index))
3141 table_index_set = 1;
3142 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3143 vnet_get_main (), &sw_if_index))
3144 ;
3145 else
3146 break;
3147 }
Dave Barach75fc8542016-10-11 16:16:02 -04003148
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149 if (table_index_set == 0)
3150 return clib_error_return (0, "classify table-index must be specified");
3151
3152 if (sw_if_index == ~0)
3153 return clib_error_return (0, "interface / subif must be specified");
3154
3155 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3156
3157 switch (rv)
3158 {
3159 case 0:
3160 break;
3161
3162 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3163 return clib_error_return (0, "No such interface");
3164
3165 case VNET_API_ERROR_NO_SUCH_ENTRY:
3166 return clib_error_return (0, "No such classifier table");
3167 }
3168 return 0;
3169}
3170
Billy McFall0683c9c2016-10-13 08:27:31 -04003171/*?
3172 * Assign a classification table to an interface. The classification
3173 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3174 * commands. Once the table is create, use this command to filter packets
3175 * on an interface.
3176 *
3177 * @cliexpar
3178 * Example of how to assign a classification table to an interface:
3179 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3180?*/
3181/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003182VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3183{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003184 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003185 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003186 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003187 .function = set_ip_classify_command_fn,
3188};
Billy McFall0683c9c2016-10-13 08:27:31 -04003189/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003190
3191/*
3192 * fd.io coding-style-patch-verification: ON
3193 *
3194 * Local Variables:
3195 * eval: (c-set-style "gnu")
3196 * End:
3197 */