blob: 87b345bd3f5d7c7589905dfd482dc92860a18d34 [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>
Ed Warnickecb9cada2015-12-08 15:45:58 -070053
Billy McFall0683c9c2016-10-13 08:27:31 -040054/**
55 * @file
56 * @brief IPv4 Forwarding.
57 *
58 * This file contains the source code for IPv4 forwarding.
59 */
60
Pierre Pfister0febaf12016-06-08 12:23:21 +010061void
62ip4_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050063 vlib_node_runtime_t * node,
64 vlib_frame_t * frame,
65 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010066
Ed Warnickecb9cada2015-12-08 15:45:58 -070067always_inline uword
68ip4_lookup_inline (vlib_main_t * vm,
69 vlib_node_runtime_t * node,
70 vlib_frame_t * frame,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010071 int lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
Dave Barachd7cb1b52016-12-09 09:52:16 -050073 ip4_main_t *im = &ip4_main;
74 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
75 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070076 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -050077 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
79 from = vlib_frame_vector_args (frame);
80 n_left_from = frame->n_vectors;
81 next = node->cached_next_index;
82
83 while (n_left_from > 0)
84 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
Dave Barach670909e2016-10-18 15:25:35 -040087 while (n_left_from >= 8 && n_left_to_next >= 4)
Dave Barachd7cb1b52016-12-09 09:52:16 -050088 {
89 vlib_buffer_t *p0, *p1, *p2, *p3;
90 ip4_header_t *ip0, *ip1, *ip2, *ip3;
91 __attribute__ ((unused)) tcp_header_t *tcp0, *tcp1, *tcp2, *tcp3;
92 ip_lookup_next_t next0, next1, next2, next3;
93 const load_balance_t *lb0, *lb1, *lb2, *lb3;
94 ip4_fib_mtrie_t *mtrie0, *mtrie1, *mtrie2, *mtrie3;
95 ip4_fib_mtrie_leaf_t leaf0, leaf1, leaf2, leaf3;
96 ip4_address_t *dst_addr0, *dst_addr1, *dst_addr2, *dst_addr3;
97 __attribute__ ((unused)) u32 pi0, fib_index0, lb_index0,
98 is_tcp_udp0;
99 __attribute__ ((unused)) u32 pi1, fib_index1, lb_index1,
100 is_tcp_udp1;
101 __attribute__ ((unused)) u32 pi2, fib_index2, lb_index2,
102 is_tcp_udp2;
103 __attribute__ ((unused)) u32 pi3, fib_index3, lb_index3,
104 is_tcp_udp3;
105 flow_hash_config_t flow_hash_config0, flow_hash_config1;
106 flow_hash_config_t flow_hash_config2, flow_hash_config3;
107 u32 hash_c0, hash_c1, hash_c2, hash_c3;
Dave Barach670909e2016-10-18 15:25:35 -0400108 const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700109
Dave Barachd7cb1b52016-12-09 09:52:16 -0500110 /* Prefetch next iteration. */
111 {
112 vlib_buffer_t *p4, *p5, *p6, *p7;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113
Dave Barachd7cb1b52016-12-09 09:52:16 -0500114 p4 = vlib_get_buffer (vm, from[4]);
115 p5 = vlib_get_buffer (vm, from[5]);
116 p6 = vlib_get_buffer (vm, from[6]);
117 p7 = vlib_get_buffer (vm, from[7]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118
Dave Barachd7cb1b52016-12-09 09:52:16 -0500119 vlib_prefetch_buffer_header (p4, LOAD);
120 vlib_prefetch_buffer_header (p5, LOAD);
121 vlib_prefetch_buffer_header (p6, LOAD);
122 vlib_prefetch_buffer_header (p7, LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Dave Barachd7cb1b52016-12-09 09:52:16 -0500124 CLIB_PREFETCH (p4->data, sizeof (ip0[0]), LOAD);
125 CLIB_PREFETCH (p5->data, sizeof (ip0[0]), LOAD);
126 CLIB_PREFETCH (p6->data, sizeof (ip0[0]), LOAD);
127 CLIB_PREFETCH (p7->data, sizeof (ip0[0]), LOAD);
128 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129
Dave Barachd7cb1b52016-12-09 09:52:16 -0500130 pi0 = to_next[0] = from[0];
131 pi1 = to_next[1] = from[1];
132 pi2 = to_next[2] = from[2];
133 pi3 = to_next[3] = from[3];
Dave Barach670909e2016-10-18 15:25:35 -0400134
Dave Barachd7cb1b52016-12-09 09:52:16 -0500135 from += 4;
136 to_next += 4;
137 n_left_to_next -= 4;
138 n_left_from -= 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
Dave Barachd7cb1b52016-12-09 09:52:16 -0500140 p0 = vlib_get_buffer (vm, pi0);
141 p1 = vlib_get_buffer (vm, pi1);
142 p2 = vlib_get_buffer (vm, pi2);
143 p3 = vlib_get_buffer (vm, pi3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
Dave Barachd7cb1b52016-12-09 09:52:16 -0500145 ip0 = vlib_buffer_get_current (p0);
146 ip1 = vlib_buffer_get_current (p1);
147 ip2 = vlib_buffer_get_current (p2);
148 ip3 = vlib_buffer_get_current (p3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149
Dave Barachd7cb1b52016-12-09 09:52:16 -0500150 dst_addr0 = &ip0->dst_address;
151 dst_addr1 = &ip1->dst_address;
152 dst_addr2 = &ip2->dst_address;
153 dst_addr3 = &ip3->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200154
Dave Barachd7cb1b52016-12-09 09:52:16 -0500155 fib_index0 =
156 vec_elt (im->fib_index_by_sw_if_index,
157 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
158 fib_index1 =
159 vec_elt (im->fib_index_by_sw_if_index,
160 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
161 fib_index2 =
162 vec_elt (im->fib_index_by_sw_if_index,
163 vnet_buffer (p2)->sw_if_index[VLIB_RX]);
164 fib_index3 =
165 vec_elt (im->fib_index_by_sw_if_index,
166 vnet_buffer (p3)->sw_if_index[VLIB_RX]);
167 fib_index0 =
168 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
169 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
170 fib_index1 =
171 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
172 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
173 fib_index2 =
174 (vnet_buffer (p2)->sw_if_index[VLIB_TX] ==
175 (u32) ~ 0) ? fib_index2 : vnet_buffer (p2)->sw_if_index[VLIB_TX];
176 fib_index3 =
177 (vnet_buffer (p3)->sw_if_index[VLIB_TX] ==
178 (u32) ~ 0) ? fib_index3 : vnet_buffer (p3)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179
180
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 if (!lookup_for_responses_to_locally_received_packets)
182 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100183 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
184 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Dave Barach670909e2016-10-18 15:25:35 -0400185 mtrie2 = &ip4_fib_get (fib_index2)->mtrie;
186 mtrie3 = &ip4_fib_get (fib_index3)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187
Dave Barachd7cb1b52016-12-09 09:52:16 -0500188 leaf0 = leaf1 = leaf2 = leaf3 = IP4_FIB_MTRIE_LEAF_ROOT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
191 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 0);
192 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 0);
193 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 0);
194 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barachd7cb1b52016-12-09 09:52:16 -0500196 tcp0 = (void *) (ip0 + 1);
197 tcp1 = (void *) (ip1 + 1);
198 tcp2 = (void *) (ip2 + 1);
199 tcp3 = (void *) (ip3 + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200
Dave Barachd7cb1b52016-12-09 09:52:16 -0500201 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
202 || ip0->protocol == IP_PROTOCOL_UDP);
203 is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
204 || ip1->protocol == IP_PROTOCOL_UDP);
205 is_tcp_udp2 = (ip2->protocol == IP_PROTOCOL_TCP
206 || ip2->protocol == IP_PROTOCOL_UDP);
207 is_tcp_udp3 = (ip1->protocol == IP_PROTOCOL_TCP
208 || ip1->protocol == IP_PROTOCOL_UDP);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209
Dave Barachd7cb1b52016-12-09 09:52:16 -0500210 if (!lookup_for_responses_to_locally_received_packets)
211 {
212 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
213 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 1);
214 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 1);
215 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 1);
216 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217
Dave Barachd7cb1b52016-12-09 09:52:16 -0500218 if (!lookup_for_responses_to_locally_received_packets)
219 {
220 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
221 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
222 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 2);
223 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 2);
224 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225
Dave Barachd7cb1b52016-12-09 09:52:16 -0500226 if (!lookup_for_responses_to_locally_received_packets)
227 {
228 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
229 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
230 leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 3);
231 leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 3);
232 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233
Dave Barachd7cb1b52016-12-09 09:52:16 -0500234 if (lookup_for_responses_to_locally_received_packets)
235 {
236 lb_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
237 lb_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
238 lb_index2 = vnet_buffer (p2)->ip.adj_index[VLIB_RX];
239 lb_index3 = vnet_buffer (p3)->ip.adj_index[VLIB_RX];
240 }
241 else
242 {
243 /* Handle default route. */
244 leaf0 =
245 (leaf0 ==
246 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
247 leaf1 =
248 (leaf1 ==
249 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
250 leaf2 =
251 (leaf2 ==
252 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie2->default_leaf : leaf2);
253 leaf3 =
254 (leaf3 ==
255 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie3->default_leaf : leaf3);
256 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
257 lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
258 lb_index2 = ip4_fib_mtrie_leaf_get_adj_index (leaf2);
259 lb_index3 = ip4_fib_mtrie_leaf_get_adj_index (leaf3);
260 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 lb0 = load_balance_get (lb_index0);
263 lb1 = load_balance_get (lb_index1);
Dave Barach670909e2016-10-18 15:25:35 -0400264 lb2 = load_balance_get (lb_index2);
265 lb3 = load_balance_get (lb_index3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266
Dave Barachd7cb1b52016-12-09 09:52:16 -0500267 /* Use flow hash to compute multipath adjacency. */
268 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
269 hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
270 hash_c2 = vnet_buffer (p2)->ip.flow_hash = 0;
271 hash_c3 = vnet_buffer (p3)->ip.flow_hash = 0;
272 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
273 {
274 flow_hash_config0 = lb0->lb_hash_config;
275 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
276 ip4_compute_flow_hash (ip0, flow_hash_config0);
277 }
278 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
279 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280 flow_hash_config1 = lb1->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500281 hash_c1 = vnet_buffer (p1)->ip.flow_hash =
282 ip4_compute_flow_hash (ip1, flow_hash_config1);
283 }
284 if (PREDICT_FALSE (lb2->lb_n_buckets > 1))
285 {
286 flow_hash_config2 = lb2->lb_hash_config;
287 hash_c2 = vnet_buffer (p2)->ip.flow_hash =
288 ip4_compute_flow_hash (ip2, flow_hash_config2);
289 }
290 if (PREDICT_FALSE (lb3->lb_n_buckets > 1))
291 {
Dave Barach670909e2016-10-18 15:25:35 -0400292 flow_hash_config3 = lb3->lb_hash_config;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 hash_c3 = vnet_buffer (p3)->ip.flow_hash =
294 ip4_compute_flow_hash (ip3, flow_hash_config3);
295 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 ASSERT (lb0->lb_n_buckets > 0);
298 ASSERT (is_pow2 (lb0->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500299 ASSERT (lb1->lb_n_buckets > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100300 ASSERT (is_pow2 (lb1->lb_n_buckets));
Dave Barach670909e2016-10-18 15:25:35 -0400301 ASSERT (lb2->lb_n_buckets > 0);
302 ASSERT (is_pow2 (lb2->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500303 ASSERT (lb3->lb_n_buckets > 0);
Dave Barach670909e2016-10-18 15:25:35 -0400304 ASSERT (is_pow2 (lb3->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305
Dave Barachd7cb1b52016-12-09 09:52:16 -0500306 dpo0 = load_balance_get_bucket_i (lb0,
307 (hash_c0 &
308 (lb0->lb_n_buckets_minus_1)));
309 dpo1 = load_balance_get_bucket_i (lb1,
310 (hash_c1 &
311 (lb1->lb_n_buckets_minus_1)));
312 dpo2 = load_balance_get_bucket_i (lb2,
313 (hash_c2 &
314 (lb2->lb_n_buckets_minus_1)));
315 dpo3 = load_balance_get_bucket_i (lb3,
316 (hash_c3 &
317 (lb3->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100319 next0 = dpo0->dpoi_next_node;
320 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
321 next1 = dpo1->dpoi_next_node;
322 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Dave Barach670909e2016-10-18 15:25:35 -0400323 next2 = dpo2->dpoi_next_node;
324 vnet_buffer (p2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
325 next3 = dpo3->dpoi_next_node;
326 vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200327
Dave Barachd7cb1b52016-12-09 09:52:16 -0500328 vlib_increment_combined_counter
329 (cm, cpu_index, lb_index0, 1,
330 vlib_buffer_length_in_chain (vm, p0)
331 + sizeof (ethernet_header_t));
332 vlib_increment_combined_counter
333 (cm, cpu_index, lb_index1, 1,
334 vlib_buffer_length_in_chain (vm, p1)
335 + sizeof (ethernet_header_t));
336 vlib_increment_combined_counter
337 (cm, cpu_index, lb_index2, 1,
338 vlib_buffer_length_in_chain (vm, p2)
339 + sizeof (ethernet_header_t));
340 vlib_increment_combined_counter
341 (cm, cpu_index, lb_index3, 1,
342 vlib_buffer_length_in_chain (vm, p3)
343 + sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344
Dave Barach670909e2016-10-18 15:25:35 -0400345 vlib_validate_buffer_enqueue_x4 (vm, node, next,
346 to_next, n_left_to_next,
347 pi0, pi1, pi2, pi3,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500348 next0, next1, next2, next3);
349 }
Dave Barach75fc8542016-10-11 16:16:02 -0400350
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 while (n_left_from > 0 && n_left_to_next > 0)
352 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500353 vlib_buffer_t *p0;
354 ip4_header_t *ip0;
355 __attribute__ ((unused)) tcp_header_t *tcp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356 ip_lookup_next_t next0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100357 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500358 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 ip4_fib_mtrie_leaf_t leaf0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500360 ip4_address_t *dst_addr0;
361 __attribute__ ((unused)) u32 pi0, fib_index0, is_tcp_udp0, lbi0;
362 flow_hash_config_t flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100363 const dpo_id_t *dpo0;
364 u32 hash_c0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365
366 pi0 = from[0];
367 to_next[0] = pi0;
368
369 p0 = vlib_get_buffer (vm, pi0);
370
371 ip0 = vlib_buffer_get_current (p0);
372
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100373 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200374
Dave Barachd7cb1b52016-12-09 09:52:16 -0500375 fib_index0 =
376 vec_elt (im->fib_index_by_sw_if_index,
377 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
378 fib_index0 =
379 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
380 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381
Dave Barachd7cb1b52016-12-09 09:52:16 -0500382 if (!lookup_for_responses_to_locally_received_packets)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500384 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385
386 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
387
Damjan Marionaca64c92016-04-13 09:48:56 +0200388 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389 }
390
391 tcp0 = (void *) (ip0 + 1);
392
393 is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
394 || ip0->protocol == IP_PROTOCOL_UDP);
395
Dave Barachd7cb1b52016-12-09 09:52:16 -0500396 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200397 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398
Dave Barachd7cb1b52016-12-09 09:52:16 -0500399 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200400 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401
Dave Barachd7cb1b52016-12-09 09:52:16 -0500402 if (!lookup_for_responses_to_locally_received_packets)
Damjan Marionaca64c92016-04-13 09:48:56 +0200403 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404
405 if (lookup_for_responses_to_locally_received_packets)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100406 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407 else
408 {
409 /* Handle default route. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500410 leaf0 =
411 (leaf0 ==
412 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100413 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 }
415
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100416 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417
418 /* Use flow hash to compute multipath adjacency. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500419 hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
420 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
421 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100422 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423
Dave Barachd7cb1b52016-12-09 09:52:16 -0500424 hash_c0 = vnet_buffer (p0)->ip.flow_hash =
425 ip4_compute_flow_hash (ip0, flow_hash_config0);
426 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700427
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100428 ASSERT (lb0->lb_n_buckets > 0);
429 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
Dave Barachd7cb1b52016-12-09 09:52:16 -0500431 dpo0 = load_balance_get_bucket_i (lb0,
432 (hash_c0 &
433 (lb0->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100435 next0 = dpo0->dpoi_next_node;
436 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Florin Corasdf9d3bc2016-09-05 19:54:17 +0200437
Dave Barach75fc8542016-10-11 16:16:02 -0400438 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500439 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700440
441 from += 1;
442 to_next += 1;
443 n_left_to_next -= 1;
444 n_left_from -= 1;
445
446 if (PREDICT_FALSE (next0 != next))
447 {
448 n_left_to_next += 1;
449 vlib_put_next_frame (vm, node, next, n_left_to_next);
450 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500451 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452 to_next[0] = pi0;
453 to_next += 1;
454 n_left_to_next -= 1;
455 }
456 }
457
458 vlib_put_next_frame (vm, node, next, n_left_to_next);
459 }
460
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100461 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100463
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464 return frame->n_vectors;
465}
466
Chris Luke8e5b0412016-07-26 13:06:10 -0400467/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -0400468 @node ip4-lookup
469
470 This is the main IPv4 lookup dispatch node.
471
472 @param vm vlib_main_t corresponding to the current thread
473 @param node vlib_node_runtime_t
474 @param frame vlib_frame_t whose contents should be dispatched
475
476 @par Graph mechanics: buffer metadata, next index usage
477
478 @em Uses:
479 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
480 - Indicates the @c sw_if_index value of the interface that the
481 packet was received on.
482 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
483 - When the value is @c ~0 then the node performs a longest prefix
484 match (LPM) for the packet destination address in the FIB attached
485 to the receive interface.
486 - Otherwise perform LPM for the packet destination address in the
487 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
488 value (0, 1, ...) and not a VRF id.
489
490 @em Sets:
491 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
492 - The lookup result adjacency index.
493
494 <em>Next Index:</em>
495 - Dispatches the packet to the node index found in
496 ip_adjacency_t @c adj->lookup_next_index
497 (where @c adj is the lookup result adjacency).
498*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499static uword
500ip4_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500501 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502{
Damjan Marionaca64c92016-04-13 09:48:56 +0200503 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500504 /* lookup_for_responses_to_locally_received_packets */
505 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506
507}
508
Dave Barachd7cb1b52016-12-09 09:52:16 -0500509static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100510
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511VLIB_REGISTER_NODE (ip4_lookup_node) =
512{
513.function = ip4_lookup,.name = "ip4-lookup",.vector_size =
514 sizeof (u32),.format_trace = format_ip4_lookup_trace,.n_next_nodes =
515 IP_LOOKUP_N_NEXT,.next_nodes = IP4_LOOKUP_NEXT_NODES,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100516
Dave Barachd7cb1b52016-12-09 09:52:16 -0500517VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100518
519always_inline uword
520ip4_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500521 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
524 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100525 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500526 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100528 from = vlib_frame_vector_args (frame);
529 n_left_from = frame->n_vectors;
530 next = node->cached_next_index;
531
532 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500533 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100534
535 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500537 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100538
Dave Barach75fc8542016-10-11 16:16:02 -0400539
Neale Ranns2be95c12016-11-19 13:50:04 +0000540 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500541 {
542 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000543 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500544 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000545 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
546 const ip4_header_t *ip0, *ip1;
547 const dpo_id_t *dpo0, *dpo1;
548
Dave Barachd7cb1b52016-12-09 09:52:16 -0500549 /* Prefetch next iteration. */
550 {
551 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000552
553 p2 = vlib_get_buffer (vm, from[2]);
554 p3 = vlib_get_buffer (vm, from[3]);
555
556 vlib_prefetch_buffer_header (p2, STORE);
557 vlib_prefetch_buffer_header (p3, STORE);
558
559 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
560 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500561 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000562
563 pi0 = to_next[0] = from[0];
564 pi1 = to_next[1] = from[1];
565
566 from += 2;
567 n_left_from -= 2;
568 to_next += 2;
569 n_left_to_next -= 2;
570
571 p0 = vlib_get_buffer (vm, pi0);
572 p1 = vlib_get_buffer (vm, pi1);
573
574 ip0 = vlib_buffer_get_current (p0);
575 ip1 = vlib_buffer_get_current (p1);
576 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
577 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
578
Dave Barachd7cb1b52016-12-09 09:52:16 -0500579 lb0 = load_balance_get (lbi0);
580 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000581
Dave Barachd7cb1b52016-12-09 09:52:16 -0500582 /*
583 * this node is for via FIBs we can re-use the hash value from the
584 * to node if present.
585 * We don't want to use the same hash value at each level in the recursion
586 * graph as that would lead to polarisation
587 */
588 hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
589 hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000590
Dave Barachd7cb1b52016-12-09 09:52:16 -0500591 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
592 {
593 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
594 {
595 hc0 = vnet_buffer (p0)->ip.flow_hash =
596 vnet_buffer (p0)->ip.flow_hash >> 1;
597 }
598 else
599 {
600 hc0 = vnet_buffer (p0)->ip.flow_hash =
601 ip4_compute_flow_hash (ip0, hc0);
602 }
603 }
604 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
605 {
606 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
607 {
608 hc1 = vnet_buffer (p1)->ip.flow_hash =
609 vnet_buffer (p1)->ip.flow_hash >> 1;
610 }
611 else
612 {
613 hc1 = vnet_buffer (p1)->ip.flow_hash =
614 ip4_compute_flow_hash (ip1, hc1);
615 }
616 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000617
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 dpo0 =
619 load_balance_get_bucket_i (lb0,
620 hc0 & (lb0->lb_n_buckets_minus_1));
621 dpo1 =
622 load_balance_get_bucket_i (lb1,
623 hc1 & (lb1->lb_n_buckets_minus_1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000624
625 next0 = dpo0->dpoi_next_node;
626 next1 = dpo1->dpoi_next_node;
627
628 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
629 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
630
631 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500632 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000633 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000635
636 vlib_validate_buffer_enqueue_x2 (vm, node, next,
637 to_next, n_left_to_next,
638 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000640
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 while (n_left_from > 0 && n_left_to_next > 0)
642 {
643 ip_lookup_next_t next0;
644 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500645 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100646 u32 pi0, lbi0, hc0;
647 const ip4_header_t *ip0;
648 const dpo_id_t *dpo0;
649
650 pi0 = from[0];
651 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000652 from += 1;
653 to_next += 1;
654 n_left_to_next -= 1;
655 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656
657 p0 = vlib_get_buffer (vm, pi0);
658
659 ip0 = vlib_buffer_get_current (p0);
660 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
661
Dave Barachd7cb1b52016-12-09 09:52:16 -0500662 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100663
Dave Barachd7cb1b52016-12-09 09:52:16 -0500664 hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
665 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
666 {
667 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
668 {
669 hc0 = vnet_buffer (p0)->ip.flow_hash =
670 vnet_buffer (p0)->ip.flow_hash >> 1;
671 }
672 else
673 {
674 hc0 = vnet_buffer (p0)->ip.flow_hash =
675 ip4_compute_flow_hash (ip0, hc0);
676 }
677 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000678
Dave Barachd7cb1b52016-12-09 09:52:16 -0500679 dpo0 =
680 load_balance_get_bucket_i (lb0,
681 hc0 & (lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100682
683 next0 = dpo0->dpoi_next_node;
684 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
685
Dave Barach75fc8542016-10-11 16:16:02 -0400686 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100688
Neale Ranns2be95c12016-11-19 13:50:04 +0000689 vlib_validate_buffer_enqueue_x1 (vm, node, next,
690 to_next, n_left_to_next,
691 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100692 }
693
694 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 }
696
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 return frame->n_vectors;
698}
699
Dave Barachd7cb1b52016-12-09 09:52:16 -0500700VLIB_REGISTER_NODE (ip4_load_balance_node) =
701{
702.function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
703 sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
704 format_ip4_lookup_trace,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100707
708/* get first interface address */
709ip4_address_t *
710ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500711 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100712{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500713 ip_lookup_main_t *lm = &im->lookup_main;
714 ip_interface_address_t *ia = 0;
715 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100716
Dave Barach75fc8542016-10-11 16:16:02 -0400717 foreach_ip_interface_address (lm, ia, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500718 1 /* honor unnumbered */ ,
719 (
720 {
721 ip4_address_t * a =
722 ip_interface_address_get_address (lm, ia);
723 result = a;
724 break;
725 }
726 ));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100727 if (result_ia)
728 *result_ia = result ? ia : 0;
729 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700730}
731
732static void
733ip4_add_interface_routes (u32 sw_if_index,
734 ip4_main_t * im, u32 fib_index,
735 ip_interface_address_t * a)
736{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737 ip_lookup_main_t *lm = &im->lookup_main;
738 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100739 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500740 .fp_len = a->address_length,
741 .fp_proto = FIB_PROTOCOL_IP4,
742 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100743 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744
745 a->neighbor_probe_adj_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100747 if (pfx.fp_len < 32)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500748 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100749 fib_node_index_t fei;
750
Dave Barachd7cb1b52016-12-09 09:52:16 -0500751 fei = fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), FIB_PROTOCOL_IP4, NULL, /* No next-hop address */
752 sw_if_index, ~0, // invalid FIB index
753 1, NULL, // no out-label stack
754 FIB_ROUTE_PATH_FLAG_NONE);
755 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
756 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100757
758 pfx.fp_len = 32;
759
760 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500761 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100762 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763 lm->classify_table_index_by_sw_if_index[sw_if_index];
764 if (classify_table_index != (u32) ~ 0)
765 {
766 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100767
Dave Barachd7cb1b52016-12-09 09:52:16 -0500768 dpo_set (&dpo,
769 DPO_CLASSIFY,
770 DPO_PROTO_IP4,
771 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100772
Dave Barachd7cb1b52016-12-09 09:52:16 -0500773 fib_table_entry_special_dpo_add (fib_index,
774 &pfx,
775 FIB_SOURCE_CLASSIFY,
776 FIB_ENTRY_FLAG_NONE, &dpo);
777 dpo_reset (&dpo);
778 }
779 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100780
Dave Barachd7cb1b52016-12-09 09:52:16 -0500781 fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), FIB_PROTOCOL_IP4, &pfx.fp_addr, sw_if_index, ~0, // invalid FIB index
782 1, NULL, // no out-label stack
783 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784}
785
786static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100787ip4_del_interface_routes (ip4_main_t * im,
788 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500789 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500791 fib_prefix_t pfx = {
792 .fp_len = address_length,
793 .fp_proto = FIB_PROTOCOL_IP4,
794 .fp_addr.ip4 = *address,
795 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700796
Dave Barachd7cb1b52016-12-09 09:52:16 -0500797 if (pfx.fp_len < 32)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100798 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500799 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100800 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801
Dave Barachd7cb1b52016-12-09 09:52:16 -0500802 pfx.fp_len = 32;
803 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804}
805
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100806void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500807ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100808{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100811 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
812
813 /*
814 * enable/disable only on the 1<->0 transition
815 */
816 if (is_enable)
817 {
818 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500819 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100820 }
821 else
822 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100824 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500825 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100826 }
Damjan Marion4d489932016-12-09 03:21:27 -0800827 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
828 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100829
Damjan Marion4d489932016-12-09 03:21:27 -0800830 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
831 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100832
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100833}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
Ed Warnickecb9cada2015-12-08 15:45:58 -0700835static clib_error_t *
836ip4_add_del_interface_address_internal (vlib_main_t * vm,
837 u32 sw_if_index,
838 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500839 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500841 vnet_main_t *vnm = vnet_get_main ();
842 ip4_main_t *im = &ip4_main;
843 ip_lookup_main_t *lm = &im->lookup_main;
844 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700845 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500846 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847
848 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
849 ip4_addr_fib_init (&ip4_af, address,
850 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
851 vec_add1 (addr_fib, ip4_af);
852
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100853 /* FIXME-LATER
854 * there is no support for adj-fib handling in the presence of overlapping
855 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
856 * most routers do.
857 */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500858 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100860 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500861 with an existing address. */
862 ip_interface_address_t *ia;
Dave Barach75fc8542016-10-11 16:16:02 -0400863 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500864 0 /* honor unnumbered */ ,
865 (
866 {
867 ip4_address_t * x =
868 ip_interface_address_get_address
869 (&im->lookup_main, ia);
870 if (ip4_destination_matches_route
871 (im, address, x, ia->address_length)
872 ||
873 ip4_destination_matches_route (im,
874 x,
875 address,
876 address_length))
877 return
878 clib_error_create
879 ("failed to add %U which conflicts with %U for interface %U",
880 format_ip4_address_and_length, address,
881 address_length,
882 format_ip4_address_and_length, x,
883 ia->address_length,
884 format_vnet_sw_if_index_name, vnm,
885 sw_if_index);}
886 ));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700887 }
888
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889 elts_before = pool_elts (lm->if_address_pool);
890
891 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500892 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893 if (error)
894 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400895
Dave Barachd7cb1b52016-12-09 09:52:16 -0500896 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100897
898 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500899 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100900 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500901 ip4_add_interface_routes (sw_if_index,
902 im, ip4_af.fib_index,
903 pool_elt_at_index
904 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700905
906 /* If pool did not grow/shrink: add duplicate address. */
907 if (elts_before != pool_elts (lm->if_address_pool))
908 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500909 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 vec_foreach (cb, im->add_del_interface_address_callbacks)
911 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500912 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700913 }
914
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916 vec_free (addr_fib);
917 return error;
918}
919
920clib_error_t *
921ip4_add_del_interface_address (vlib_main_t * vm, u32 sw_if_index,
922 ip4_address_t * address, u32 address_length,
923 u32 is_del)
924{
925 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500926 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700927}
928
Dave Barachd6534602016-06-14 18:38:02 -0400929/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500930/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100931VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
932{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500933 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100934 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -0800935 .end_node = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100936 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
937};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100938
Dave Barachd7cb1b52016-12-09 09:52:16 -0500939VNET_FEATURE_INIT (ip4_flow_classify, static) =
940{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100941 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700942 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100943 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700944};
945
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946VNET_FEATURE_INIT (ip4_inacl, static) =
947{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100948 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400949 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100950 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400951};
952
Dave Barachd7cb1b52016-12-09 09:52:16 -0500953VNET_FEATURE_INIT (ip4_source_check_1, static) =
954{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100955 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400956 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100957 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400958};
959
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960VNET_FEATURE_INIT (ip4_source_check_2, static) =
961{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100962 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400963 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100964 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400965};
966
Dave Barachd7cb1b52016-12-09 09:52:16 -0500967VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
968{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100969 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400970 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100971 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400972};
973
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974VNET_FEATURE_INIT (ip4_policer_classify, static) =
975{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100976 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700977 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100978 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700979};
980
Dave Barachd7cb1b52016-12-09 09:52:16 -0500981VNET_FEATURE_INIT (ip4_ipsec, static) =
982{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100983 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400984 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100985 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400986};
987
Dave Barachd7cb1b52016-12-09 09:52:16 -0500988VNET_FEATURE_INIT (ip4_vpath, static) =
989{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100990 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400991 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500992 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
993};
994
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
996{
John Lo37682e12016-11-30 12:51:39 -0500997 .arc_name = "ip4-unicast",
998 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100999 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001000};
1001
Dave Barachd7cb1b52016-12-09 09:52:16 -05001002VNET_FEATURE_INIT (ip4_lookup, static) =
1003{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001004 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -04001005 .node_name = "ip4-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001006 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001007};
1008
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009VNET_FEATURE_INIT (ip4_drop, static) =
1010{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001011 .arc_name = "ip4-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001012 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001013 .runs_before = 0, /* not before any other features */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001014};
1015
1016
Dave Barachd6534602016-06-14 18:38:02 -04001017/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001018VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1019{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001020 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001021 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Damjan Marion4d489932016-12-09 03:21:27 -08001022 .end_node = "ip4-lookup-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001023 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1024};
1025
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1027{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001028 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001029 .node_name = "vpath-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .runs_before = VNET_FEATURES ("ip4-lookup-multicast"),
Dave Barachd6534602016-06-14 18:38:02 -04001031};
1032
Dave Barachd7cb1b52016-12-09 09:52:16 -05001033VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1034{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001035 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001036 .node_name = "ip4-lookup-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001037 .runs_before = VNET_FEATURES ("ip4-drop"),
Dave Barachd6534602016-06-14 18:38:02 -04001038};
1039
Dave Barachd7cb1b52016-12-09 09:52:16 -05001040VNET_FEATURE_INIT (ip4_mc_drop, static) =
1041{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001042 .arc_name = "ip4-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001043 .node_name = "ip4-drop",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001044 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001045};
Dave Barach5331c722016-08-17 11:54:30 -04001046
1047/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001048VNET_FEATURE_ARC_INIT (ip4_output, static) =
1049{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001050 .arc_name = "ip4-output",
Neale Rannsf06aea52016-11-29 06:51:37 -08001051 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
Damjan Marion892e0762016-12-09 18:52:05 +01001052 .end_node = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001053 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1054};
Dave Barach5331c722016-08-17 11:54:30 -04001055
Dave Barachd7cb1b52016-12-09 09:52:16 -05001056VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1057{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001058 .arc_name = "ip4-output",
1059 .node_name = "ip4-source-and-port-range-check-tx",
Matus Fabian08a6f012016-11-15 06:08:51 -08001060 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1061};
1062
Dave Barachd7cb1b52016-12-09 09:52:16 -05001063VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1064{
Matus Fabian08a6f012016-11-15 06:08:51 -08001065 .arc_name = "ip4-output",
1066 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001067 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001068};
1069
1070/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001071VNET_FEATURE_INIT (ip4_interface_output, static) =
1072{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001073 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001074 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001075 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001076};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001077/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001078
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001080ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001082 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001084 /* Fill in lookup tables with default table (0). */
1085 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1086
Damjan Marion8b3191e2016-11-09 19:54:20 +01001087 vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1088 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089
Damjan Marion8b3191e2016-11-09 19:54:20 +01001090 vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1091 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001092
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 return /* no error */ 0;
1094}
1095
1096VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1097
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098/* Global IP4 main. */
1099ip4_main_t ip4_main;
1100
1101clib_error_t *
1102ip4_lookup_init (vlib_main_t * vm)
1103{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001104 ip4_main_t *im = &ip4_main;
1105 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106 uword i;
1107
Damjan Marion8b3191e2016-11-09 19:54:20 +01001108 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1109 return error;
1110
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1112 {
1113 u32 m;
1114
1115 if (i < 32)
1116 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001117 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118 m = ~0;
1119 im->fib_masks[i] = clib_host_to_net_u32 (m);
1120 }
1121
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1123
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001124 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001125 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001126
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129 pn = pg_get_node (ip4_lookup_node.index);
1130 pn->unformat_edit = unformat_pg_ip4_header;
1131 }
1132
1133 {
1134 ethernet_arp_header_t h;
1135
1136 memset (&h, 0, sizeof (h));
1137
1138 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139 memset (h.ip4_over_ethernet[1].ethernet, 0,
1140 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
1142#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1143#define _8(f,v) h.f = v;
1144 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1145 _16 (l3_type, ETHERNET_TYPE_IP4);
1146 _8 (n_l2_address_bytes, 6);
1147 _8 (n_l3_address_bytes, 4);
1148 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1149#undef _16
1150#undef _8
1151
Dave Barachd7cb1b52016-12-09 09:52:16 -05001152 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 /* data */ &h,
1154 sizeof (h),
1155 /* alloc chunk size */ 8,
1156 "ip4 arp");
1157 }
1158
Dave Barach203c6322016-06-26 10:29:03 -04001159 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160}
1161
1162VLIB_INIT_FUNCTION (ip4_lookup_init);
1163
Dave Barachd7cb1b52016-12-09 09:52:16 -05001164typedef struct
1165{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001167 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 u32 flow_hash;
1169 u32 fib_index;
1170
1171 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001172 u8 packet_data[64 - 1 * sizeof (u32)];
1173}
1174ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176u8 *
1177format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178{
1179 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1180 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001181 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001182 uword indent = format_get_indent (s);
1183 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001184 format_white_space, indent,
1185 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001186 return s;
1187}
1188
Dave Barachd7cb1b52016-12-09 09:52:16 -05001189static u8 *
1190format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001191{
1192 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1193 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001194 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195 uword indent = format_get_indent (s);
1196
John Loac8146c2016-09-27 17:44:02 -04001197 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001199 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001200 format_white_space, indent,
1201 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001202 return s;
1203}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204
Dave Barachd7cb1b52016-12-09 09:52:16 -05001205static u8 *
1206format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001207{
1208 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1209 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001210 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1211 vnet_main_t *vnm = vnet_get_main ();
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001212 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213
Vengada Govindanf1544482016-09-28 02:45:57 -07001214 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001215 t->fib_index, t->dpo_index, format_ip_adjacency,
1216 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001217 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001218 format_white_space, indent,
1219 format_ip_adjacency_packet_data,
1220 vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221 return s;
1222}
1223
1224/* Common trace function for all ip4-forward next nodes. */
1225void
1226ip4_forward_next_trace (vlib_main_t * vm,
1227 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001228 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001230 u32 *from, n_left;
1231 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001232
1233 n_left = frame->n_vectors;
1234 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001235
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236 while (n_left >= 4)
1237 {
1238 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001239 vlib_buffer_t *b0, *b1;
1240 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241
1242 /* Prefetch next iteration. */
1243 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1244 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1245
1246 bi0 = from[0];
1247 bi1 = from[1];
1248
1249 b0 = vlib_get_buffer (vm, bi0);
1250 b1 = vlib_get_buffer (vm, bi1);
1251
1252 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1253 {
1254 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001255 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001257 t0->fib_index =
1258 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1259 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1260 vec_elt (im->fib_index_by_sw_if_index,
1261 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001262
Damjan Marionf1213b82016-03-13 02:22:06 +01001263 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001264 vlib_buffer_get_current (b0),
1265 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266 }
1267 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1268 {
1269 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001270 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 t1->fib_index =
1273 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1274 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1275 vec_elt (im->fib_index_by_sw_if_index,
1276 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1277 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1278 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279 }
1280 from += 2;
1281 n_left -= 2;
1282 }
1283
1284 while (n_left >= 1)
1285 {
1286 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001287 vlib_buffer_t *b0;
1288 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289
1290 bi0 = from[0];
1291
1292 b0 = vlib_get_buffer (vm, bi0);
1293
1294 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1295 {
1296 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001297 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001299 t0->fib_index =
1300 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1301 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1302 vec_elt (im->fib_index_by_sw_if_index,
1303 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1304 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1305 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 }
1307 from += 1;
1308 n_left -= 1;
1309 }
1310}
1311
1312static uword
1313ip4_drop_or_punt (vlib_main_t * vm,
1314 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001315 vlib_frame_t * frame, ip4_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001317 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001318 uword n_packets = frame->n_vectors;
1319
Dave Barachd7cb1b52016-12-09 09:52:16 -05001320 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001321 /* stride */ 1,
1322 n_packets,
1323 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001324 ip4_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325
1326 if (node->flags & VLIB_NODE_FLAG_TRACE)
1327 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1328
1329 return n_packets;
1330}
1331
1332static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001333ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1334{
1335 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1336}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001337
1338static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001339ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1340{
1341 return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1342}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343
Dave Barachd7cb1b52016-12-09 09:52:16 -05001344VLIB_REGISTER_NODE (ip4_drop_node, static) =
1345{
1346 .function = ip4_drop,.name = "ip4-drop",.vector_size =
1347 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
1348 1,.next_nodes =
1349 {
1350 [0] = "error-drop",}
1351,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001352
Dave Barachd7cb1b52016-12-09 09:52:16 -05001353VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354
Dave Barachd7cb1b52016-12-09 09:52:16 -05001355VLIB_REGISTER_NODE (ip4_punt_node, static) =
1356{
1357 .function = ip4_punt,.name = "ip4-punt",.vector_size =
1358 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
1359 1,.next_nodes =
1360 {
1361 [0] = "error-punt",}
1362,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363
Dave Barachd7cb1b52016-12-09 09:52:16 -05001364VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001365
Ed Warnickecb9cada2015-12-08 15:45:58 -07001366/* Compute TCP/UDP/ICMP4 checksum in software. */
1367u16
1368ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1369 ip4_header_t * ip0)
1370{
1371 ip_csum_t sum0;
1372 u32 ip_header_length, payload_length_host_byte_order;
1373 u32 n_this_buffer, n_bytes_left;
1374 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001375 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001376
Ed Warnickecb9cada2015-12-08 15:45:58 -07001377 /* Initialize checksum with ip header. */
1378 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001379 payload_length_host_byte_order =
1380 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1381 sum0 =
1382 clib_host_to_net_u32 (payload_length_host_byte_order +
1383 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001384
1385 if (BITS (uword) == 32)
1386 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001387 sum0 =
1388 ip_csum_with_carry (sum0,
1389 clib_mem_unaligned (&ip0->src_address, u32));
1390 sum0 =
1391 ip_csum_with_carry (sum0,
1392 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393 }
1394 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001395 sum0 =
1396 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397
1398 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1399 data_this_buffer = (void *) ip0 + ip_header_length;
1400 if (n_this_buffer + ip_header_length > p0->current_length)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001401 n_this_buffer =
1402 p0->current_length >
1403 ip_header_length ? p0->current_length - ip_header_length : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404 while (1)
1405 {
1406 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1407 n_bytes_left -= n_this_buffer;
1408 if (n_bytes_left == 0)
1409 break;
1410
1411 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1412 p0 = vlib_get_buffer (vm, p0->next_buffer);
1413 data_this_buffer = vlib_buffer_get_current (p0);
1414 n_this_buffer = p0->current_length;
1415 }
1416
Dave Barachd7cb1b52016-12-09 09:52:16 -05001417 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001418
1419 return sum16;
1420}
1421
John Lo37682e12016-11-30 12:51:39 -05001422u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001423ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1424{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001425 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1426 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001427 u16 sum16;
1428
1429 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1430 || ip0->protocol == IP_PROTOCOL_UDP);
1431
1432 udp0 = (void *) (ip0 + 1);
1433 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1434 {
1435 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1436 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1437 return p0->flags;
1438 }
1439
1440 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1441
1442 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1443 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1444
1445 return p0->flags;
1446}
1447
1448static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001449ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001451 ip4_main_t *im = &ip4_main;
1452 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001453 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001454 u32 *from, *to_next, n_left_from, n_left_to_next;
1455 vlib_node_runtime_t *error_node =
1456 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001457
1458 from = vlib_frame_vector_args (frame);
1459 n_left_from = frame->n_vectors;
1460 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001461
Ed Warnickecb9cada2015-12-08 15:45:58 -07001462 if (node->flags & VLIB_NODE_FLAG_TRACE)
1463 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1464
1465 while (n_left_from > 0)
1466 {
1467 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1468
1469 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001470 {
1471 vlib_buffer_t *p0, *p1;
1472 ip4_header_t *ip0, *ip1;
1473 udp_header_t *udp0, *udp1;
1474 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1475 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1476 const dpo_id_t *dpo0, *dpo1;
1477 const load_balance_t *lb0, *lb1;
1478 u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1479 u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1480 i32 len_diff0, len_diff1;
1481 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1482 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1483 u8 enqueue_code;
Dave Barach75fc8542016-10-11 16:16:02 -04001484
Dave Barachd7cb1b52016-12-09 09:52:16 -05001485 pi0 = to_next[0] = from[0];
1486 pi1 = to_next[1] = from[1];
1487 from += 2;
1488 n_left_from -= 2;
1489 to_next += 2;
1490 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001491
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492 p0 = vlib_get_buffer (vm, pi0);
1493 p1 = vlib_get_buffer (vm, pi1);
1494
1495 ip0 = vlib_buffer_get_current (p0);
1496 ip1 = vlib_buffer_get_current (p1);
1497
Dave Barachd7cb1b52016-12-09 09:52:16 -05001498 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1499 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001500
Dave Barachd7cb1b52016-12-09 09:52:16 -05001501 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1502 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
Neale Rannscb630ff2016-12-14 13:31:29 +01001503 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1504 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1505
Dave Barachd7cb1b52016-12-09 09:52:16 -05001506 fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1507 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Neale Rannscb630ff2016-12-14 13:31:29 +01001508 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1509 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001510
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001511 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1512 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513
1514 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1515
Dave Barachd7cb1b52016-12-09 09:52:16 -05001516 leaf0 =
1517 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1518 leaf1 =
1519 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001520
John Lo3419d0b2016-06-02 09:28:37 -04001521 /* Treat IP frag packets as "experimental" protocol for now
1522 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001523 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1524 proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1526 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1527 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1528 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1529
1530 flags0 = p0->flags;
1531 flags1 = p1->flags;
1532
1533 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1534 good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1535
1536 udp0 = ip4_next_header (ip0);
1537 udp1 = ip4_next_header (ip1);
1538
1539 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1540 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1541 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1542
Dave Barachd7cb1b52016-12-09 09:52:16 -05001543 leaf0 =
1544 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1545 leaf1 =
1546 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001547
1548 /* Verify UDP length. */
1549 ip_len0 = clib_net_to_host_u16 (ip0->length);
1550 ip_len1 = clib_net_to_host_u16 (ip1->length);
1551 udp_len0 = clib_net_to_host_u16 (udp0->length);
1552 udp_len1 = clib_net_to_host_u16 (udp1->length);
1553
1554 len_diff0 = ip_len0 - udp_len0;
1555 len_diff1 = ip_len1 - udp_len1;
1556
1557 len_diff0 = is_udp0 ? len_diff0 : 0;
1558 len_diff1 = is_udp1 ? len_diff1 : 0;
1559
Dave Barachd7cb1b52016-12-09 09:52:16 -05001560 if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1561 & good_tcp_udp0 & good_tcp_udp1)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562 {
1563 if (is_tcp_udp0)
1564 {
1565 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001566 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001567 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1568 good_tcp_udp0 =
1569 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1570 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1571 }
1572 if (is_tcp_udp1)
1573 {
1574 if (is_tcp_udp1
Dave Barachd7cb1b52016-12-09 09:52:16 -05001575 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001576 flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1577 good_tcp_udp1 =
1578 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1579 good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1580 }
1581 }
1582
1583 good_tcp_udp0 &= len_diff0 >= 0;
1584 good_tcp_udp1 &= len_diff1 >= 0;
1585
Dave Barachd7cb1b52016-12-09 09:52:16 -05001586 leaf0 =
1587 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1588 leaf1 =
1589 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001590
1591 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1592
1593 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1594 error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1595
1596 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001597 error0 = (is_tcp_udp0 && !good_tcp_udp0
1598 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1599 error1 = (is_tcp_udp1 && !good_tcp_udp1
1600 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601
Dave Barachd7cb1b52016-12-09 09:52:16 -05001602 leaf0 =
1603 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1604 leaf1 =
1605 ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
1606 leaf0 =
1607 (leaf0 ==
1608 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1609 leaf1 =
1610 (leaf1 ==
1611 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612
Dave Barachd7cb1b52016-12-09 09:52:16 -05001613 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1614 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1615 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616
Dave Barachd7cb1b52016-12-09 09:52:16 -05001617 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1618 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1619 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620
Dave Barachd7cb1b52016-12-09 09:52:16 -05001621 lb0 = load_balance_get (lbi0);
1622 lb1 = load_balance_get (lbi1);
1623 dpo0 = load_balance_get_bucket_i (lb0, 0);
1624 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625
Dave Barach75fc8542016-10-11 16:16:02 -04001626 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001627 * Must have a route to source otherwise we drop the packet.
1628 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001629 *
1630 * The checks are:
1631 * - the source is a recieve => it's from us => bogus, do this
1632 * first since it sets a different error code.
1633 * - uRPF check for any route to source - accept if passes.
1634 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001635 */
Neale Ranns3ee44042016-10-03 13:05:48 +01001636 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001637 dpo0->dpoi_type == DPO_RECEIVE) ?
1638 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1639 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1640 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001641 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Neale Ranns3ee44042016-10-03 13:05:48 +01001643 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001644 dpo1->dpoi_type == DPO_RECEIVE) ?
1645 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1646 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1647 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001648 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001649 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001650
1651 next0 = lm->local_next_by_ip_protocol[proto0];
1652 next1 = lm->local_next_by_ip_protocol[proto1];
1653
Dave Barachd7cb1b52016-12-09 09:52:16 -05001654 next0 =
1655 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1656 next1 =
1657 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001658
1659 p0->error = error0 ? error_node->errors[error0] : 0;
1660 p1->error = error1 ? error_node->errors[error1] : 0;
1661
Dave Barachd7cb1b52016-12-09 09:52:16 -05001662 enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663
1664 if (PREDICT_FALSE (enqueue_code != 0))
1665 {
1666 switch (enqueue_code)
1667 {
1668 case 1:
1669 /* A B A */
1670 to_next[-2] = pi1;
1671 to_next -= 1;
1672 n_left_to_next += 1;
1673 vlib_set_next_frame_buffer (vm, node, next0, pi0);
1674 break;
1675
1676 case 2:
1677 /* A A B */
1678 to_next -= 1;
1679 n_left_to_next += 1;
1680 vlib_set_next_frame_buffer (vm, node, next1, pi1);
1681 break;
1682
1683 case 3:
1684 /* A B B or A B C */
1685 to_next -= 2;
1686 n_left_to_next += 2;
1687 vlib_set_next_frame_buffer (vm, node, next0, pi0);
1688 vlib_set_next_frame_buffer (vm, node, next1, pi1);
1689 if (next0 == next1)
1690 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001691 vlib_put_next_frame (vm, node, next_index,
1692 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001693 next_index = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001694 vlib_get_next_frame (vm, node, next_index, to_next,
1695 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001696 }
1697 break;
1698 }
1699 }
1700 }
1701
1702 while (n_left_from > 0 && n_left_to_next > 0)
1703 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001704 vlib_buffer_t *p0;
1705 ip4_header_t *ip0;
1706 udp_header_t *udp0;
1707 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001709 u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001710 i32 len_diff0;
1711 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001712 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001713 const dpo_id_t *dpo0;
1714
Ed Warnickecb9cada2015-12-08 15:45:58 -07001715 pi0 = to_next[0] = from[0];
1716 from += 1;
1717 n_left_from -= 1;
1718 to_next += 1;
1719 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001720
Ed Warnickecb9cada2015-12-08 15:45:58 -07001721 p0 = vlib_get_buffer (vm, pi0);
1722
1723 ip0 = vlib_buffer_get_current (p0);
1724
Dave Barachd7cb1b52016-12-09 09:52:16 -05001725 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001726
Dave Barach75fc8542016-10-11 16:16:02 -04001727 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001728 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
Neale Rannscb630ff2016-12-14 13:31:29 +01001729 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1730 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001731
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001732 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733
1734 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
1735
Dave Barachd7cb1b52016-12-09 09:52:16 -05001736 leaf0 =
1737 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001738
John Lo3419d0b2016-06-02 09:28:37 -04001739 /* Treat IP frag packets as "experimental" protocol for now
1740 until support of IP frag reassembly is implemented */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001741 proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1743 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1744
1745 flags0 = p0->flags;
1746
1747 good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1748
1749 udp0 = ip4_next_header (ip0);
1750
1751 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1752 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1753
Dave Barachd7cb1b52016-12-09 09:52:16 -05001754 leaf0 =
1755 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756
1757 /* Verify UDP length. */
1758 ip_len0 = clib_net_to_host_u16 (ip0->length);
1759 udp_len0 = clib_net_to_host_u16 (udp0->length);
1760
1761 len_diff0 = ip_len0 - udp_len0;
1762
1763 len_diff0 = is_udp0 ? len_diff0 : 0;
1764
Dave Barachd7cb1b52016-12-09 09:52:16 -05001765 if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766 {
1767 if (is_tcp_udp0)
1768 {
1769 if (is_tcp_udp0
Dave Barachd7cb1b52016-12-09 09:52:16 -05001770 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001771 flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1772 good_tcp_udp0 =
1773 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1774 good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1775 }
1776 }
1777
1778 good_tcp_udp0 &= len_diff0 >= 0;
1779
Dave Barachd7cb1b52016-12-09 09:52:16 -05001780 leaf0 =
1781 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782
1783 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1784
1785 error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1786
1787 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001788 error0 = (is_tcp_udp0 && !good_tcp_udp0
1789 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001790
Dave Barachd7cb1b52016-12-09 09:52:16 -05001791 leaf0 =
1792 ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1793 leaf0 =
1794 (leaf0 ==
1795 IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001797 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001798 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001799
Dave Barachd7cb1b52016-12-09 09:52:16 -05001800 lb0 = load_balance_get (lbi0);
1801 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001802
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001803 vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001804 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001805
Neale Ranns3ee44042016-10-03 13:05:48 +01001806 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001807 dpo0->dpoi_type == DPO_RECEIVE) ?
1808 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1809 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1810 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001811 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001812 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813
1814 next0 = lm->local_next_by_ip_protocol[proto0];
1815
Dave Barachd7cb1b52016-12-09 09:52:16 -05001816 next0 =
1817 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818
Dave Barachd7cb1b52016-12-09 09:52:16 -05001819 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001820
1821 if (PREDICT_FALSE (next0 != next_index))
1822 {
1823 n_left_to_next += 1;
1824 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1825
1826 next_index = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001827 vlib_get_next_frame (vm, node, next_index, to_next,
1828 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829 to_next[0] = pi0;
1830 to_next += 1;
1831 n_left_to_next -= 1;
1832 }
1833 }
Dave Barach75fc8542016-10-11 16:16:02 -04001834
Ed Warnickecb9cada2015-12-08 15:45:58 -07001835 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1836 }
1837
1838 return frame->n_vectors;
1839}
1840
Dave Barachd7cb1b52016-12-09 09:52:16 -05001841VLIB_REGISTER_NODE (ip4_local_node, static) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001843 .function = ip4_local,.name = "ip4-local",.vector_size =
1844 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
1845 IP_LOCAL_N_NEXT,.next_nodes =
1846 {
1847 [IP_LOCAL_NEXT_DROP] = "error-drop",
1848 [IP_LOCAL_NEXT_PUNT] = "error-punt",
1849 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1850 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",}
1851,};
1852
1853VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1854
1855void
1856ip4_register_protocol (u32 protocol, u32 node_index)
1857{
1858 vlib_main_t *vm = vlib_get_main ();
1859 ip4_main_t *im = &ip4_main;
1860 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861
1862 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001863 lm->local_next_by_ip_protocol[protocol] =
1864 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865}
1866
1867static clib_error_t *
1868show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001869 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001871 ip4_main_t *im = &ip4_main;
1872 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873 int i;
1874
1875 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001876 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001877 {
1878 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001879 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001880 }
1881 return 0;
1882}
1883
1884
1885
Billy McFall0683c9c2016-10-13 08:27:31 -04001886/*?
1887 * Display the set of protocols handled by the local IPv4 stack.
1888 *
1889 * @cliexpar
1890 * Example of how to display local protocol table:
1891 * @cliexstart{show ip local}
1892 * Protocols handled by ip4_local
1893 * 1
1894 * 17
1895 * 47
1896 * @cliexend
1897?*/
1898/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001899VLIB_CLI_COMMAND (show_ip_local, static) =
1900{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901 .path = "show ip local",
1902 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001903 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001904};
Billy McFall0683c9c2016-10-13 08:27:31 -04001905/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001906
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001907always_inline uword
1908ip4_arp_inline (vlib_main_t * vm,
1909 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001910 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001911{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001912 vnet_main_t *vnm = vnet_get_main ();
1913 ip4_main_t *im = &ip4_main;
1914 ip_lookup_main_t *lm = &im->lookup_main;
1915 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001916 uword n_left_from, n_left_to_next_drop, next_index;
1917 static f64 time_last_seed_change = -1e100;
1918 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001919 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001920 f64 time_now;
1921
1922 if (node->flags & VLIB_NODE_FLAG_TRACE)
1923 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1924
1925 time_now = vlib_time_now (vm);
1926 if (time_now - time_last_seed_change > 1e-3)
1927 {
1928 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001929 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1930 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001931 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1932 hash_seeds[i] = r[i];
1933
1934 /* Mark all hash keys as been no-seen before. */
1935 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1936 hash_bitmap[i] = 0;
1937
1938 time_last_seed_change = time_now;
1939 }
1940
1941 from = vlib_frame_vector_args (frame);
1942 n_left_from = frame->n_vectors;
1943 next_index = node->cached_next_index;
1944 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001945 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946
1947 while (n_left_from > 0)
1948 {
1949 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1950 to_next_drop, n_left_to_next_drop);
1951
1952 while (n_left_from > 0 && n_left_to_next_drop > 0)
1953 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001954 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001955 ip_adjacency_t *adj0;
1956 vlib_buffer_t *p0;
1957 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001959
1960 pi0 = from[0];
1961
1962 p0 = vlib_get_buffer (vm, pi0);
1963
1964 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1965 adj0 = ip_get_adjacency (lm, adj_index0);
1966 ip0 = vlib_buffer_get_current (p0);
1967
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 a0 = hash_seeds[0];
1969 b0 = hash_seeds[1];
1970 c0 = hash_seeds[2];
1971
1972 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1973 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1974
Dave Barachd7cb1b52016-12-09 09:52:16 -05001975 if (is_glean)
1976 {
Neale Ranns948e00f2016-10-20 13:39:34 +01001977 /*
1978 * this is the Glean case, so we are ARPing for the
1979 * packet's destination
1980 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981 a0 ^= ip0->dst_address.data_u32;
1982 }
1983 else
1984 {
1985 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
1986 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987 b0 ^= sw_if_index0;
1988
1989 hash_v3_finalize32 (a0, b0, c0);
1990
1991 c0 &= BITS (hash_bitmap) - 1;
1992 c0 = c0 / BITS (uword);
1993 m0 = (uword) 1 << (c0 % BITS (uword));
1994
1995 bm0 = hash_bitmap[c0];
1996 drop0 = (bm0 & m0) != 0;
1997
1998 /* Mark it as seen. */
1999 hash_bitmap[c0] = bm0 | m0;
2000
2001 from += 1;
2002 n_left_from -= 1;
2003 to_next_drop[0] = pi0;
2004 to_next_drop += 1;
2005 n_left_to_next_drop -= 1;
2006
Dave Barachd7cb1b52016-12-09 09:52:16 -05002007 p0->error =
2008 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2009 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002010
Neale Rannsb80c5362016-10-08 13:03:40 +01002011 /*
2012 * the adj has been updated to a rewrite but the node the DPO that got
2013 * us here hasn't - yet. no big deal. we'll drop while we wait.
2014 */
2015 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2016 continue;
2017
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 if (drop0)
2019 continue;
2020
Dave Barachd7cb1b52016-12-09 09:52:16 -05002021 /*
2022 * Can happen if the control-plane is programming tables
2023 * with traffic flowing; at least that's today's lame excuse.
2024 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002025 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN) ||
2026 (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002027 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002028 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002029 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002030 else
2031 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002032 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002033 u32 bi0 = 0;
2034 vlib_buffer_t *b0;
2035 ethernet_arp_header_t *h0;
2036 vnet_hw_interface_t *hw_if0;
2037
2038 h0 =
2039 vlib_packet_template_get_packet (vm,
2040 &im->ip4_arp_request_packet_template,
2041 &bi0);
2042
2043 /* Add rewrite/encap string for ARP packet. */
2044 vnet_rewrite_one_header (adj0[0], h0,
2045 sizeof (ethernet_header_t));
2046
2047 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2048
2049 /* Src ethernet address in ARP header. */
2050 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2051 hw_if0->hw_address,
2052 sizeof (h0->ip4_over_ethernet[0].ethernet));
2053
2054 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002055 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002056 /* The interface's source address is stashed in the Glean Adj */
2057 h0->ip4_over_ethernet[0].ip4 =
2058 adj0->sub_type.glean.receive_addr.ip4;
2059
2060 /* Copy in destination address we are requesting. This is the
2061 * glean case, so it's the packet's destination.*/
2062 h0->ip4_over_ethernet[1].ip4.data_u32 =
2063 ip0->dst_address.data_u32;
2064 }
2065 else
2066 {
2067 /* Src IP address in ARP header. */
2068 if (ip4_src_address_for_packet (lm, sw_if_index0,
2069 &h0->
2070 ip4_over_ethernet[0].ip4))
2071 {
2072 /* No source address available */
2073 p0->error =
2074 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2075 vlib_buffer_free (vm, &bi0, 1);
2076 continue;
2077 }
2078
2079 /* Copy in destination address we are requesting from the
2080 incomplete adj */
2081 h0->ip4_over_ethernet[1].ip4.data_u32 =
2082 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002083 }
2084
Dave Barachd7cb1b52016-12-09 09:52:16 -05002085 vlib_buffer_copy_trace_flag (vm, p0, bi0);
2086 b0 = vlib_get_buffer (vm, bi0);
2087 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2088
2089 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2090
2091 vlib_set_next_frame_buffer (vm, node,
2092 adj0->rewrite_header.next_index,
2093 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002094 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002095 }
2096
2097 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2098 }
2099
2100 return frame->n_vectors;
2101}
2102
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002103static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002104ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002105{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002106 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002107}
2108
2109static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05002110ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002111{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002112 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002113}
2114
Dave Barachd7cb1b52016-12-09 09:52:16 -05002115static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116 [IP4_ARP_ERROR_DROP] = "address overflow drops",
2117 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2118 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2119 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2120 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002121 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002122};
2123
Dave Barachd7cb1b52016-12-09 09:52:16 -05002124VLIB_REGISTER_NODE (ip4_arp_node) =
2125{
2126 .function = ip4_arp,.name = "ip4-arp",.vector_size =
2127 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2128 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2129 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2130 {
2131 [IP4_ARP_NEXT_DROP] = "error-drop",}
2132,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002133
Dave Barachd7cb1b52016-12-09 09:52:16 -05002134VLIB_REGISTER_NODE (ip4_glean_node) =
2135{
2136 .function = ip4_glean,.name = "ip4-glean",.vector_size =
2137 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2138 ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2139 ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2140 {
2141 [IP4_ARP_NEXT_DROP] = "error-drop",}
2142,};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002143
Ed Warnickecb9cada2015-12-08 15:45:58 -07002144#define foreach_notrace_ip4_arp_error \
2145_(DROP) \
2146_(REQUEST_SENT) \
2147_(REPLICATE_DROP) \
2148_(REPLICATE_FAIL)
2149
Dave Barachd7cb1b52016-12-09 09:52:16 -05002150clib_error_t *
2151arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002152{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002153 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002154
2155 /* don't trace ARP request packets */
2156#define _(a) \
2157 vnet_pcap_drop_trace_filter_add_del \
2158 (rt->errors[IP4_ARP_ERROR_##a], \
2159 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002160 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002161#undef _
2162 return 0;
2163}
2164
Dave Barachd7cb1b52016-12-09 09:52:16 -05002165VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002166
2167
2168/* Send an ARP request to see if given destination is reachable on given interface. */
2169clib_error_t *
2170ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2171{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002172 vnet_main_t *vnm = vnet_get_main ();
2173 ip4_main_t *im = &ip4_main;
2174 ethernet_arp_header_t *h;
2175 ip4_address_t *src;
2176 ip_interface_address_t *ia;
2177 ip_adjacency_t *adj;
2178 vnet_hw_interface_t *hi;
2179 vnet_sw_interface_t *si;
2180 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002181 u32 bi = 0;
2182
2183 si = vnet_get_sw_interface (vnm, sw_if_index);
2184
2185 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2186 {
2187 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002188 format_ip4_address, dst,
2189 format_vnet_sw_if_index_name, vnm,
2190 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002191 }
2192
Dave Barachd7cb1b52016-12-09 09:52:16 -05002193 src =
2194 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2195 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002196 {
2197 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002198 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05002199 (0, "no matching interface address for destination %U (interface %U)",
2200 format_ip4_address, dst,
2201 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002202 }
2203
2204 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2205
Dave Barachd7cb1b52016-12-09 09:52:16 -05002206 h =
2207 vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template,
2208 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209
2210 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2211
Dave Barachd7cb1b52016-12-09 09:52:16 -05002212 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2213 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214
2215 h->ip4_over_ethernet[0].ip4 = src[0];
2216 h->ip4_over_ethernet[1].ip4 = dst[0];
2217
2218 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002219 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2220 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002221
2222 /* Add encapsulation string for software interface (e.g. ethernet header). */
2223 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2224 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2225
2226 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002227 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2228 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002229 to_next[0] = bi;
2230 f->n_vectors = 1;
2231 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2232 }
2233
2234 return /* no error */ 0;
2235}
2236
Dave Barachd7cb1b52016-12-09 09:52:16 -05002237typedef enum
2238{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002239 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002240 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002241} ip4_rewrite_next_t;
2242
2243always_inline uword
2244ip4_rewrite_inline (vlib_main_t * vm,
2245 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002246 vlib_frame_t * frame, int is_midchain)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002247{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002248 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2249 u32 *from = vlib_frame_vector_args (frame);
2250 u32 n_left_from, n_left_to_next, *to_next, next_index;
2251 vlib_node_runtime_t *error_node =
2252 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002253
2254 n_left_from = frame->n_vectors;
2255 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002256 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04002257
Ed Warnickecb9cada2015-12-08 15:45:58 -07002258 while (n_left_from > 0)
2259 {
2260 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2261
2262 while (n_left_from >= 4 && n_left_to_next >= 2)
2263 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002264 ip_adjacency_t *adj0, *adj1;
2265 vlib_buffer_t *p0, *p1;
2266 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002267 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2268 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002269 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002270
Ed Warnickecb9cada2015-12-08 15:45:58 -07002271 /* Prefetch next iteration. */
2272 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002273 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274
2275 p2 = vlib_get_buffer (vm, from[2]);
2276 p3 = vlib_get_buffer (vm, from[3]);
2277
2278 vlib_prefetch_buffer_header (p2, STORE);
2279 vlib_prefetch_buffer_header (p3, STORE);
2280
2281 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2282 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2283 }
2284
2285 pi0 = to_next[0] = from[0];
2286 pi1 = to_next[1] = from[1];
2287
2288 from += 2;
2289 n_left_from -= 2;
2290 to_next += 2;
2291 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002292
Ed Warnickecb9cada2015-12-08 15:45:58 -07002293 p0 = vlib_get_buffer (vm, pi0);
2294 p1 = vlib_get_buffer (vm, pi1);
2295
Neale Rannsf06aea52016-11-29 06:51:37 -08002296 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2297 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298
Dave Barachd7cb1b52016-12-09 09:52:16 -05002299 /* We should never rewrite a pkt using the MISS adjacency */
2300 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301
2302 ip0 = vlib_buffer_get_current (p0);
2303 ip1 = vlib_buffer_get_current (p1);
2304
2305 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002306 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002307
2308 /* Decrement TTL & update checksum.
2309 Works either endian, so no need for byte swap. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002310 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002311 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002312 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
2314 /* Input node should have reject packets with ttl 0. */
2315 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002316
2317 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002318 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002319
2320 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002321 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002322 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002323
Dave Barachd7cb1b52016-12-09 09:52:16 -05002324 /*
2325 * If the ttl drops below 1 when forwarding, generate
2326 * an ICMP response.
2327 */
2328 if (PREDICT_FALSE (ttl0 <= 0))
2329 {
2330 error0 = IP4_ERROR_TIME_EXPIRED;
2331 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2332 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2333 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2334 0);
2335 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2336 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002337
2338 /* Verify checksum. */
2339 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2340 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002341 else
2342 {
2343 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2344 }
2345 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002346 {
2347 i32 ttl1 = ip1->ttl;
2348
2349 /* Input node should have reject packets with ttl 0. */
2350 ASSERT (ip1->ttl > 0);
2351
2352 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2353 checksum1 += checksum1 >= 0xffff;
2354
2355 ip1->checksum = checksum1;
2356 ttl1 -= 1;
2357 ip1->ttl = ttl1;
2358
Dave Barachd7cb1b52016-12-09 09:52:16 -05002359 /*
2360 * If the ttl drops below 1 when forwarding, generate
2361 * an ICMP response.
2362 */
2363 if (PREDICT_FALSE (ttl1 <= 0))
2364 {
2365 error1 = IP4_ERROR_TIME_EXPIRED;
2366 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2367 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2368 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2369 0);
2370 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2371 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002372
2373 /* Verify checksum. */
2374 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2375 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2376 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002377 else
2378 {
2379 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2380 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381
2382 /* Rewrite packet header and updates lengths. */
2383 adj0 = ip_get_adjacency (lm, adj_index0);
2384 adj1 = ip_get_adjacency (lm, adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002385
Dave Barachd7cb1b52016-12-09 09:52:16 -05002386 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 rw_len0 = adj0[0].rewrite_header.data_bytes;
2388 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002389 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2390 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002391
Dave Barachd7cb1b52016-12-09 09:52:16 -05002392 /* Check MTU of outgoing interface. */
2393 error0 =
2394 (vlib_buffer_length_in_chain (vm, p0) >
2395 adj0[0].
2396 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2397 error0);
2398 error1 =
2399 (vlib_buffer_length_in_chain (vm, p1) >
2400 adj1[0].
2401 rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2402 error1);
Chris Lukef2868fc2016-06-14 16:26:22 -04002403
Dave Barachd7cb1b52016-12-09 09:52:16 -05002404 /*
Neale Ranns044183f2017-01-24 01:34:25 -08002405 * pre-fetch the per-adjacency counters
Dave Barachd7cb1b52016-12-09 09:52:16 -05002406 */
Neale Ranns044183f2017-01-24 01:34:25 -08002407 vlib_prefetch_combined_counter (&adjacency_counters,
2408 cpu_index, adj_index0);
2409 vlib_prefetch_combined_counter (&adjacency_counters,
2410 cpu_index, adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002411
Dave Barachd7cb1b52016-12-09 09:52:16 -05002412 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2413 * to see the IP headerr */
2414 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2415 {
Damjan Marion892e0762016-12-09 18:52:05 +01002416 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002417 p0->current_data -= rw_len0;
2418 p0->current_length += rw_len0;
2419 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2420 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002421
Dave Barachd7cb1b52016-12-09 09:52:16 -05002422 vnet_feature_arc_start (lm->output_feature_arc_index,
2423 tx_sw_if_index0, &next0, p0);
2424 }
2425 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2426 {
Damjan Marion892e0762016-12-09 18:52:05 +01002427 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002428 p1->current_data -= rw_len1;
2429 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002430
Dave Barachd7cb1b52016-12-09 09:52:16 -05002431 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2432 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002433
Dave Barachd7cb1b52016-12-09 09:52:16 -05002434 vnet_feature_arc_start (lm->output_feature_arc_index,
2435 tx_sw_if_index1, &next1, p1);
2436 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437
2438 /* Guess we are only writing on simple Ethernet header. */
2439 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002440 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002441
Neale Ranns044183f2017-01-24 01:34:25 -08002442 /*
2443 * Bump the per-adjacency counters
2444 */
2445 vlib_increment_combined_counter
2446 (&adjacency_counters,
2447 cpu_index,
2448 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2449
2450 vlib_increment_combined_counter
2451 (&adjacency_counters,
2452 cpu_index,
2453 adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2454
Neale Ranns5e575b12016-10-03 09:40:25 +01002455 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002456 {
2457 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2458 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2459 }
Dave Barach75fc8542016-10-11 16:16:02 -04002460
Ed Warnickecb9cada2015-12-08 15:45:58 -07002461 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2462 to_next, n_left_to_next,
2463 pi0, pi1, next0, next1);
2464 }
2465
2466 while (n_left_from > 0 && n_left_to_next > 0)
2467 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002468 ip_adjacency_t *adj0;
2469 vlib_buffer_t *p0;
2470 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002472 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002473
Ed Warnickecb9cada2015-12-08 15:45:58 -07002474 pi0 = to_next[0] = from[0];
2475
2476 p0 = vlib_get_buffer (vm, pi0);
2477
Neale Rannsf06aea52016-11-29 06:51:37 -08002478 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002479
Dave Barachd7cb1b52016-12-09 09:52:16 -05002480 /* We should never rewrite a pkt using the MISS adjacency */
2481 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482
2483 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002484
Ed Warnickecb9cada2015-12-08 15:45:58 -07002485 ip0 = vlib_buffer_get_current (p0);
2486
2487 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002488 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002489
2490 /* Decrement TTL & update checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002491 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002492 {
2493 i32 ttl0 = ip0->ttl;
2494
2495 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2496
2497 checksum0 += checksum0 >= 0xffff;
2498
2499 ip0->checksum = checksum0;
2500
2501 ASSERT (ip0->ttl > 0);
2502
2503 ttl0 -= 1;
2504
2505 ip0->ttl = ttl0;
2506
2507 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2508
Dave Barachd7cb1b52016-12-09 09:52:16 -05002509 if (PREDICT_FALSE (ttl0 <= 0))
2510 {
2511 /*
2512 * If the ttl drops below 1 when forwarding, generate
2513 * an ICMP response.
2514 */
2515 error0 = IP4_ERROR_TIME_EXPIRED;
2516 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2517 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2518 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2519 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2520 0);
2521 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002522 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002523 else
2524 {
2525 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2526 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002527
Neale Ranns044183f2017-01-24 01:34:25 -08002528 vlib_prefetch_combined_counter (&adjacency_counters,
2529 cpu_index, adj_index0);
2530
Ed Warnickecb9cada2015-12-08 15:45:58 -07002531 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002532 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002533
Dave Barachd7cb1b52016-12-09 09:52:16 -05002534 /* Update packet buffer attributes/set output interface. */
2535 rw_len0 = adj0[0].rewrite_header.data_bytes;
2536 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002537
Neale Ranns044183f2017-01-24 01:34:25 -08002538 vlib_increment_combined_counter
2539 (&adjacency_counters,
2540 cpu_index,
2541 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002542
Dave Barachd7cb1b52016-12-09 09:52:16 -05002543 /* Check MTU of outgoing interface. */
2544 error0 = (vlib_buffer_length_in_chain (vm, p0)
2545 > adj0[0].rewrite_header.max_l3_packet_bytes
2546 ? IP4_ERROR_MTU_EXCEEDED : error0);
Chris Luke816f3e12016-06-14 16:24:47 -04002547
Ed Warnickecb9cada2015-12-08 15:45:58 -07002548 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002549
Dave Barachd7cb1b52016-12-09 09:52:16 -05002550 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2551 * to see the IP headerr */
2552 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2553 {
2554 p0->current_data -= rw_len0;
2555 p0->current_length += rw_len0;
2556 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002557
Dave Barachd7cb1b52016-12-09 09:52:16 -05002558 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2559 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002560
Neale Ranns5e575b12016-10-03 09:40:25 +01002561 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002562 {
2563 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
Neale Ranns5e575b12016-10-03 09:40:25 +01002564 }
2565
Dave Barachd7cb1b52016-12-09 09:52:16 -05002566 vnet_feature_arc_start (lm->output_feature_arc_index,
2567 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002568
Dave Barachd7cb1b52016-12-09 09:52:16 -05002569 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002570
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571 from += 1;
2572 n_left_from -= 1;
2573 to_next += 1;
2574 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002575
Ed Warnickecb9cada2015-12-08 15:45:58 -07002576 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2577 to_next, n_left_to_next,
2578 pi0, next0);
2579 }
Dave Barach75fc8542016-10-11 16:16:02 -04002580
Ed Warnickecb9cada2015-12-08 15:45:58 -07002581 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2582 }
2583
2584 /* Need to do trace after rewrites to pick up new packet data. */
2585 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002586 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002587
2588 return frame->n_vectors;
2589}
2590
Dave Barach132d51d2016-07-07 10:10:17 -04002591
Neale Rannsf06aea52016-11-29 06:51:37 -08002592/** @brief IPv4 rewrite node.
2593 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002594
2595 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2596 header checksum, fetch the ip adjacency, check the outbound mtu,
2597 apply the adjacency rewrite, and send pkts to the adjacency
2598 rewrite header's rewrite_next_index.
2599
2600 @param vm vlib_main_t corresponding to the current thread
2601 @param node vlib_node_runtime_t
2602 @param frame vlib_frame_t whose contents should be dispatched
2603
2604 @par Graph mechanics: buffer metadata, next index usage
2605
2606 @em Uses:
2607 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2608 - the rewrite adjacency index
2609 - <code>adj->lookup_next_index</code>
2610 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002611 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002612 - <code>adj->rewrite_header</code>
2613 - Rewrite string length, rewrite string, next_index
2614
2615 @em Sets:
2616 - <code>b->current_data, b->current_length</code>
2617 - Updated net of applying the rewrite string
2618
2619 <em>Next Indices:</em>
2620 - <code> adj->rewrite_header.next_index </code>
Dave Barach75fc8542016-10-11 16:16:02 -04002621 or @c error-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002622*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002623static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002624ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002625 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002626{
Neale Rannsf06aea52016-11-29 06:51:37 -08002627 return ip4_rewrite_inline (vm, node, frame, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002628}
2629
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002630static uword
2631ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002632 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002633{
Neale Rannsf06aea52016-11-29 06:51:37 -08002634 return ip4_rewrite_inline (vm, node, frame, 1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002635}
2636
Neale Rannsf06aea52016-11-29 06:51:37 -08002637
Dave Barachd7cb1b52016-12-09 09:52:16 -05002638VLIB_REGISTER_NODE (ip4_rewrite_node) =
2639{
2640 .function = ip4_rewrite,.name = "ip4-rewrite",.vector_size =
2641 sizeof (u32),.format_trace = format_ip4_rewrite_trace,.n_next_nodes =
2642 2,.next_nodes =
2643 {
2644 [IP4_REWRITE_NEXT_DROP] = "error-drop",
2645 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",}
2646,};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002647
Dave Barachd7cb1b52016-12-09 09:52:16 -05002648VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002649
Dave Barachd7cb1b52016-12-09 09:52:16 -05002650VLIB_REGISTER_NODE (ip4_midchain_node) =
2651{
2652.function = ip4_midchain,.name = "ip4-midchain",.vector_size =
2653 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.sibling_of =
2654 "ip4-rewrite",};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655
Dave Barachd7cb1b52016-12-09 09:52:16 -05002656VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Damjan Marion1c80e832016-05-11 23:07:18 +02002657
Ed Warnickecb9cada2015-12-08 15:45:58 -07002658static clib_error_t *
2659add_del_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002660 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002661{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002662 vnet_main_t *vnm = vnet_get_main ();
2663 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664 u32 sw_if_index, table_id;
2665
2666 sw_if_index = ~0;
2667
Dave Barachd7cb1b52016-12-09 09:52:16 -05002668 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669 {
2670 error = clib_error_return (0, "unknown interface `%U'",
2671 format_unformat_error, input);
2672 goto done;
2673 }
2674
2675 if (unformat (input, "%d", &table_id))
2676 ;
2677 else
2678 {
2679 error = clib_error_return (0, "expected table id `%U'",
2680 format_unformat_error, input);
2681 goto done;
2682 }
2683
2684 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002685 ip4_main_t *im = &ip4_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002686 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002687
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002688 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002689 table_id);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002690
2691 //
2692 // FIXME-LATER
2693 // changing an interface's table has consequences for any connecteds
2694 // and adj-fibs already installed.
2695 //
2696 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2697 im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698 }
2699
Dave Barachd7cb1b52016-12-09 09:52:16 -05002700done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002701 return error;
2702}
2703
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002704/*?
Billy McFall0683c9c2016-10-13 08:27:31 -04002705 * Place the indicated interface into the supplied IPv4 FIB table (also known
2706 * as a VRF). If the FIB table does not exist, this command creates it. To
2707 * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2708 * FIB table will only be displayed if a route has been added to the table, or
2709 * an IP Address is assigned to an interface in the table (which adds a route
Billy McFallebb9a6a2016-10-17 11:35:32 -04002710 * automatically).
Billy McFall0683c9c2016-10-13 08:27:31 -04002711 *
2712 * @note IP addresses added after setting the interface IP table end up in
2713 * the indicated FIB table. If the IP address is added prior to adding the
2714 * interface to the FIB table, it will NOT be part of the FIB table. Predictable
2715 * but potentially counter-intuitive results occur if you provision interface
2716 * addresses in multiple FIBs. Upon RX, packets will be processed in the last
2717 * IP table ID provisioned. It might be marginally useful to evade source RPF
2718 * drops to put an interface address into multiple FIBs.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002719 *
2720 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -04002721 * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2722 * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002723 ?*/
Billy McFall0683c9c2016-10-13 08:27:31 -04002724/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002725VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2726{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727 .path = "set interface ip table",
2728 .function = add_del_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04002729 .short_help = "set interface ip table <interface> <table-id>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002730};
Billy McFall0683c9c2016-10-13 08:27:31 -04002731/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732
2733
2734static uword
2735ip4_lookup_multicast (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002736 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002738 ip4_main_t *im = &ip4_main;
2739 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
2740 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002742 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07002743
2744 from = vlib_frame_vector_args (frame);
2745 n_left_from = frame->n_vectors;
2746 next = node->cached_next_index;
2747
2748 while (n_left_from > 0)
2749 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002750 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002751
2752 while (n_left_from >= 4 && n_left_to_next >= 2)
2753 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002754 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002755 u32 pi0, pi1, lb_index0, lb_index1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002756 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002757 ip4_header_t *ip0, *ip1;
2758 u32 fib_index0, fib_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002759 const dpo_id_t *dpo0, *dpo1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002760 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002761
2762 /* Prefetch next iteration. */
2763 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002764 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002765
2766 p2 = vlib_get_buffer (vm, from[2]);
2767 p3 = vlib_get_buffer (vm, from[3]);
2768
2769 vlib_prefetch_buffer_header (p2, LOAD);
2770 vlib_prefetch_buffer_header (p3, LOAD);
2771
2772 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
2773 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
2774 }
2775
2776 pi0 = to_next[0] = from[0];
2777 pi1 = to_next[1] = from[1];
2778
2779 p0 = vlib_get_buffer (vm, pi0);
2780 p1 = vlib_get_buffer (vm, pi1);
2781
2782 ip0 = vlib_buffer_get_current (p0);
2783 ip1 = vlib_buffer_get_current (p1);
2784
Dave Barachd7cb1b52016-12-09 09:52:16 -05002785 fib_index0 =
2786 vec_elt (im->fib_index_by_sw_if_index,
2787 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
2788 fib_index1 =
2789 vec_elt (im->fib_index_by_sw_if_index,
2790 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
2791 fib_index0 =
2792 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
2793 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
2794 fib_index1 =
2795 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
2796 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797
Dave Barachd7cb1b52016-12-09 09:52:16 -05002798 lb_index0 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0),
2799 &ip0->dst_address);
2800 lb_index1 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index1),
2801 &ip1->dst_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002802
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002803 lb0 = load_balance_get (lb_index0);
2804 lb1 = load_balance_get (lb_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002805
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002806 ASSERT (lb0->lb_n_buckets > 0);
2807 ASSERT (is_pow2 (lb0->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -05002808 ASSERT (lb1->lb_n_buckets > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002809 ASSERT (is_pow2 (lb1->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002810
Dave Barach75fc8542016-10-11 16:16:02 -04002811 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
Dave Barachd7cb1b52016-12-09 09:52:16 -05002812 (ip0, lb0->lb_hash_config);
Dave Barach75fc8542016-10-11 16:16:02 -04002813
2814 vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
Dave Barachd7cb1b52016-12-09 09:52:16 -05002815 (ip1, lb1->lb_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002816
Dave Barachd7cb1b52016-12-09 09:52:16 -05002817 dpo0 = load_balance_get_bucket_i (lb0,
2818 (vnet_buffer (p0)->ip.flow_hash &
2819 (lb0->lb_n_buckets_minus_1)));
2820 dpo1 = load_balance_get_bucket_i (lb1,
2821 (vnet_buffer (p1)->ip.flow_hash &
2822 (lb1->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002823
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002824 next0 = dpo0->dpoi_next_node;
2825 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
2826 next1 = dpo1->dpoi_next_node;
2827 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002828
Dave Barachd7cb1b52016-12-09 09:52:16 -05002829 if (1) /* $$$$$$ HACK FIXME */
2830 vlib_increment_combined_counter
2831 (cm, cpu_index, lb_index0, 1,
2832 vlib_buffer_length_in_chain (vm, p0));
2833 if (1) /* $$$$$$ HACK FIXME */
2834 vlib_increment_combined_counter
2835 (cm, cpu_index, lb_index1, 1,
2836 vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002837
2838 from += 2;
2839 to_next += 2;
2840 n_left_to_next -= 2;
2841 n_left_from -= 2;
2842
Dave Barachd7cb1b52016-12-09 09:52:16 -05002843 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002844 if (PREDICT_FALSE (wrong_next != 0))
2845 {
2846 switch (wrong_next)
2847 {
2848 case 1:
2849 /* A B A */
2850 to_next[-2] = pi1;
2851 to_next -= 1;
2852 n_left_to_next += 1;
2853 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2854 break;
2855
2856 case 2:
2857 /* A A B */
2858 to_next -= 1;
2859 n_left_to_next += 1;
2860 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2861 break;
2862
2863 case 3:
2864 /* A B C */
2865 to_next -= 2;
2866 n_left_to_next += 2;
2867 vlib_set_next_frame_buffer (vm, node, next0, pi0);
2868 vlib_set_next_frame_buffer (vm, node, next1, pi1);
2869 if (next0 == next1)
2870 {
2871 /* A B B */
2872 vlib_put_next_frame (vm, node, next, n_left_to_next);
2873 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874 vlib_get_next_frame (vm, node, next, to_next,
2875 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002876 }
2877 }
2878 }
2879 }
Dave Barach75fc8542016-10-11 16:16:02 -04002880
Ed Warnickecb9cada2015-12-08 15:45:58 -07002881 while (n_left_from > 0 && n_left_to_next > 0)
2882 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002883 vlib_buffer_t *p0;
2884 ip4_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002885 u32 pi0, lb_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002886 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002887 u32 fib_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002888 const dpo_id_t *dpo0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002889 const load_balance_t *lb0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002890
2891 pi0 = from[0];
2892 to_next[0] = pi0;
2893
2894 p0 = vlib_get_buffer (vm, pi0);
2895
2896 ip0 = vlib_buffer_get_current (p0);
2897
Dave Barach75fc8542016-10-11 16:16:02 -04002898 fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002899 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
2900 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
2901 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Dave Barach75fc8542016-10-11 16:16:02 -04002902
Dave Barachd7cb1b52016-12-09 09:52:16 -05002903 lb_index0 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0),
2904 &ip0->dst_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002905
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002906 lb0 = load_balance_get (lb_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002908 ASSERT (lb0->lb_n_buckets > 0);
2909 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002910
Dave Barach75fc8542016-10-11 16:16:02 -04002911 vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
Dave Barachd7cb1b52016-12-09 09:52:16 -05002912 (ip0, lb0->lb_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002913
Dave Barachd7cb1b52016-12-09 09:52:16 -05002914 dpo0 = load_balance_get_bucket_i (lb0,
2915 (vnet_buffer (p0)->ip.flow_hash &
2916 (lb0->lb_n_buckets_minus_1)));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002917
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002918 next0 = dpo0->dpoi_next_node;
2919 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002920
Dave Barachd7cb1b52016-12-09 09:52:16 -05002921 if (1) /* $$$$$$ HACK FIXME */
2922 vlib_increment_combined_counter
2923 (cm, cpu_index, lb_index0, 1,
2924 vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925
2926 from += 1;
2927 to_next += 1;
2928 n_left_to_next -= 1;
2929 n_left_from -= 1;
2930
2931 if (PREDICT_FALSE (next0 != next))
2932 {
2933 n_left_to_next += 1;
2934 vlib_put_next_frame (vm, node, next, n_left_to_next);
2935 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002936 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002937 to_next[0] = pi0;
2938 to_next += 1;
2939 n_left_to_next -= 1;
2940 }
2941 }
2942
2943 vlib_put_next_frame (vm, node, next, n_left_to_next);
2944 }
2945
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002946 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002947 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002948
Ed Warnickecb9cada2015-12-08 15:45:58 -07002949 return frame->n_vectors;
2950}
2951
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952VLIB_REGISTER_NODE (ip4_lookup_multicast_node, static) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002953{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002954.function = ip4_lookup_multicast,.name =
2955 "ip4-lookup-multicast",.vector_size = sizeof (u32),.sibling_of =
2956 "ip4-lookup",.format_trace = format_ip4_lookup_trace,.n_next_nodes = 0,};
2957
2958VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node,
2959 ip4_lookup_multicast);
2960
2961VLIB_REGISTER_NODE (ip4_multicast_node, static) =
2962{
2963 .function = ip4_drop,.name = "ip4-multicast",.vector_size =
2964 sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
2965 1,.next_nodes =
2966 {
2967 [0] = "error-drop",}
2968,};
2969
2970int
2971ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2972{
2973 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002974 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002975 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002976
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002977 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002978
2979 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2980 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
2981 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
2982 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2983 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002984
Ed Warnickecb9cada2015-12-08 15:45:58 -07002985 /* Handle default route. */
2986 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002987
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002988 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002989
Dave Barachd7cb1b52016-12-09 09:52:16 -05002990 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991}
Dave Barach75fc8542016-10-11 16:16:02 -04002992
Ed Warnickecb9cada2015-12-08 15:45:58 -07002993static clib_error_t *
2994test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002995 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002996{
Billy McFall309fe062016-10-14 07:37:33 -04002997 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002998 u32 table_id = 0;
2999 f64 count = 1;
3000 u32 n;
3001 int i;
3002 ip4_address_t ip4_base_address;
3003 u64 errors = 0;
3004
Dave Barachd7cb1b52016-12-09 09:52:16 -05003005 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3006 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07003007 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003008 {
3009 /* Make sure the entry exists. */
3010 fib = ip4_fib_get (table_id);
3011 if ((fib) && (fib->index != table_id))
3012 return clib_error_return (0, "<fib-index> %d does not exist",
3013 table_id);
3014 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003015 else if (unformat (input, "count %f", &count))
3016 ;
3017
3018 else if (unformat (input, "%U",
3019 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003020 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003022 return clib_error_return (0, "unknown input `%U'",
3023 format_unformat_error, input);
3024 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025
3026 n = count;
3027
3028 for (i = 0; i < n; i++)
3029 {
3030 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003031 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032
Dave Barach75fc8542016-10-11 16:16:02 -04003033 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05003034 clib_host_to_net_u32 (1 +
3035 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036 }
3037
Dave Barach75fc8542016-10-11 16:16:02 -04003038 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003039 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3040 else
3041 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3042
3043 return 0;
3044}
3045
Billy McFall0683c9c2016-10-13 08:27:31 -04003046/*?
3047 * Perform a lookup of an IPv4 Address (or range of addresses) in the
3048 * given FIB table to determine if there is a conflict with the
3049 * adjacency table. The fib-id can be determined by using the
3050 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
3051 * of 0 is used.
3052 *
3053 * @todo This command uses fib-id, other commands use table-id (not
3054 * just a name, they are different indexes). Would like to change this
3055 * to table-id for consistency.
3056 *
3057 * @cliexpar
3058 * Example of how to run the test lookup command:
3059 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3060 * No errors in 2 lookups
3061 * @cliexend
3062?*/
3063/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003064VLIB_CLI_COMMAND (lookup_test_command, static) =
3065{
3066 .path = "test lookup",
3067 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3068 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003069};
Billy McFall0683c9c2016-10-13 08:27:31 -04003070/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003071
Dave Barachd7cb1b52016-12-09 09:52:16 -05003072int
3073vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003074{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003075 ip4_main_t *im4 = &ip4_main;
3076 ip4_fib_t *fib;
3077 uword *p = hash_get (im4->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003078
3079 if (p == 0)
3080 return VNET_API_ERROR_NO_SUCH_FIB;
3081
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003082 fib = ip4_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003083
3084 fib->flow_hash_config = flow_hash_config;
3085 return 0;
3086}
Dave Barach75fc8542016-10-11 16:16:02 -04003087
Ed Warnickecb9cada2015-12-08 15:45:58 -07003088static clib_error_t *
3089set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003090 unformat_input_t * input,
3091 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092{
3093 int matched = 0;
3094 u32 table_id = 0;
3095 u32 flow_hash_config = 0;
3096 int rv;
3097
Dave Barachd7cb1b52016-12-09 09:52:16 -05003098 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3099 {
3100 if (unformat (input, "table %d", &table_id))
3101 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003102#define _(a,v) \
3103 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003104 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003105#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003106 else
3107 break;
3108 }
Dave Barach75fc8542016-10-11 16:16:02 -04003109
Ed Warnickecb9cada2015-12-08 15:45:58 -07003110 if (matched == 0)
3111 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003112 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003113
Ed Warnickecb9cada2015-12-08 15:45:58 -07003114 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3115 switch (rv)
3116 {
3117 case 0:
3118 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003119
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120 case VNET_API_ERROR_NO_SUCH_FIB:
3121 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003122
Ed Warnickecb9cada2015-12-08 15:45:58 -07003123 default:
3124 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3125 break;
3126 }
Dave Barach75fc8542016-10-11 16:16:02 -04003127
Ed Warnickecb9cada2015-12-08 15:45:58 -07003128 return 0;
3129}
Dave Barach75fc8542016-10-11 16:16:02 -04003130
Billy McFall0683c9c2016-10-13 08:27:31 -04003131/*?
3132 * Configure the set of IPv4 fields used by the flow hash.
3133 *
3134 * @cliexpar
3135 * Example of how to set the flow hash on a given table:
3136 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3137 * Example of display the configured flow hash:
3138 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003139 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3140 * 0.0.0.0/0
3141 * unicast-ip4-chain
3142 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3143 * [0] [@0]: dpo-drop ip6
3144 * 0.0.0.0/32
3145 * unicast-ip4-chain
3146 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3147 * [0] [@0]: dpo-drop ip6
3148 * 224.0.0.0/8
3149 * unicast-ip4-chain
3150 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3151 * [0] [@0]: dpo-drop ip6
3152 * 6.0.1.2/32
3153 * unicast-ip4-chain
3154 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3155 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3156 * 7.0.0.1/32
3157 * unicast-ip4-chain
3158 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3159 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3160 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3161 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3162 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3163 * 240.0.0.0/8
3164 * unicast-ip4-chain
3165 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3166 * [0] [@0]: dpo-drop ip6
3167 * 255.255.255.255/32
3168 * unicast-ip4-chain
3169 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3170 * [0] [@0]: dpo-drop ip6
3171 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3172 * 0.0.0.0/0
3173 * unicast-ip4-chain
3174 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3175 * [0] [@0]: dpo-drop ip6
3176 * 0.0.0.0/32
3177 * unicast-ip4-chain
3178 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3179 * [0] [@0]: dpo-drop ip6
3180 * 172.16.1.0/24
3181 * unicast-ip4-chain
3182 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3183 * [0] [@4]: ipv4-glean: af_packet0
3184 * 172.16.1.1/32
3185 * unicast-ip4-chain
3186 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3187 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3188 * 172.16.1.2/32
3189 * unicast-ip4-chain
3190 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3191 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3192 * 172.16.2.0/24
3193 * unicast-ip4-chain
3194 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3195 * [0] [@4]: ipv4-glean: af_packet1
3196 * 172.16.2.1/32
3197 * unicast-ip4-chain
3198 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3199 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3200 * 224.0.0.0/8
3201 * unicast-ip4-chain
3202 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3203 * [0] [@0]: dpo-drop ip6
3204 * 240.0.0.0/8
3205 * unicast-ip4-chain
3206 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3207 * [0] [@0]: dpo-drop ip6
3208 * 255.255.255.255/32
3209 * unicast-ip4-chain
3210 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3211 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003212 * @cliexend
3213?*/
3214/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003215VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3216{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003217 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003218 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003219 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003220 .function = set_ip_flow_hash_command_fn,
3221};
Billy McFall0683c9c2016-10-13 08:27:31 -04003222/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003223
Dave Barachd7cb1b52016-12-09 09:52:16 -05003224int
3225vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3226 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003227{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003228 vnet_main_t *vnm = vnet_get_main ();
3229 vnet_interface_main_t *im = &vnm->interface_main;
3230 ip4_main_t *ipm = &ip4_main;
3231 ip_lookup_main_t *lm = &ipm->lookup_main;
3232 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003233 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003234
3235 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3236 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3237
3238 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3239 return VNET_API_ERROR_NO_SUCH_ENTRY;
3240
3241 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003242 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003243
Neale Rannsdf089a82016-10-02 16:39:06 +01003244 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3245
3246 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003247 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003248 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003249 .fp_len = 32,
3250 .fp_proto = FIB_PROTOCOL_IP4,
3251 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003252 };
3253 u32 fib_index;
3254
Dave Barachd7cb1b52016-12-09 09:52:16 -05003255 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3256 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003257
3258
Dave Barachd7cb1b52016-12-09 09:52:16 -05003259 if (table_index != (u32) ~ 0)
3260 {
3261 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003262
Dave Barachd7cb1b52016-12-09 09:52:16 -05003263 dpo_set (&dpo,
3264 DPO_CLASSIFY,
3265 DPO_PROTO_IP4,
3266 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003267
Dave Barachd7cb1b52016-12-09 09:52:16 -05003268 fib_table_entry_special_dpo_add (fib_index,
3269 &pfx,
3270 FIB_SOURCE_CLASSIFY,
3271 FIB_ENTRY_FLAG_NONE, &dpo);
3272 dpo_reset (&dpo);
3273 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003274 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003275 {
3276 fib_table_entry_special_remove (fib_index,
3277 &pfx, FIB_SOURCE_CLASSIFY);
3278 }
3279 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003280
Ed Warnickecb9cada2015-12-08 15:45:58 -07003281 return 0;
3282}
3283
3284static clib_error_t *
3285set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003286 unformat_input_t * input,
3287 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003288{
3289 u32 table_index = ~0;
3290 int table_index_set = 0;
3291 u32 sw_if_index = ~0;
3292 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003293
Dave Barachd7cb1b52016-12-09 09:52:16 -05003294 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3295 {
3296 if (unformat (input, "table-index %d", &table_index))
3297 table_index_set = 1;
3298 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3299 vnet_get_main (), &sw_if_index))
3300 ;
3301 else
3302 break;
3303 }
Dave Barach75fc8542016-10-11 16:16:02 -04003304
Ed Warnickecb9cada2015-12-08 15:45:58 -07003305 if (table_index_set == 0)
3306 return clib_error_return (0, "classify table-index must be specified");
3307
3308 if (sw_if_index == ~0)
3309 return clib_error_return (0, "interface / subif must be specified");
3310
3311 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3312
3313 switch (rv)
3314 {
3315 case 0:
3316 break;
3317
3318 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3319 return clib_error_return (0, "No such interface");
3320
3321 case VNET_API_ERROR_NO_SUCH_ENTRY:
3322 return clib_error_return (0, "No such classifier table");
3323 }
3324 return 0;
3325}
3326
Billy McFall0683c9c2016-10-13 08:27:31 -04003327/*?
3328 * Assign a classification table to an interface. The classification
3329 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3330 * commands. Once the table is create, use this command to filter packets
3331 * on an interface.
3332 *
3333 * @cliexpar
3334 * Example of how to assign a classification table to an interface:
3335 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3336?*/
3337/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003338VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3339{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003340 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003341 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003342 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003343 .function = set_ip_classify_command_fn,
3344};
Billy McFall0683c9c2016-10-13 08:27:31 -04003345/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003346
3347/*
3348 * fd.io coding-style-patch-verification: ON
3349 *
3350 * Local Variables:
3351 * eval: (c-set-style "gnu")
3352 * End:
3353 */