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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 * ip/ip4_source_check.c: IP v4 check source address (unicast RPF check)
18 * Copyright (c) 2008 Eliot Dresselhaus
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:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
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.
40 #include <vnet/ip/ip.h>
41 #include <vnet/fib/ip4_fib.h>
42 #include <vnet/dpo/load_balance.h>
46 } ip4_source_check_trace_t;
48 static u8 * format_ip4_source_check_trace (u8 * s, va_list * va)
50 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
51 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
52 ip4_source_check_trace_t * t = va_arg (*va, ip4_source_check_trace_t *);
56 t->packet_data, sizeof (t->packet_data));
62 IP4_SOURCE_CHECK_NEXT_DROP,
63 IP4_SOURCE_CHECK_N_NEXT,
64 } ip4_source_check_next_t;
67 IP4_SOURCE_CHECK_REACHABLE_VIA_RX,
68 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY,
69 } ip4_source_check_type_t;
73 u32 no_default_route : 1;
77 } ip4_source_check_config_t;
80 ip4_source_check_inline (vlib_main_t * vm,
81 vlib_node_runtime_t * node,
83 ip4_source_check_type_t source_check_type)
85 ip4_main_t * im = &ip4_main;
86 ip_lookup_main_t * lm = &im->lookup_main;
87 ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
88 u32 n_left_from, * from, * to_next;
90 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
92 from = vlib_frame_vector_args (frame);
93 n_left_from = frame->n_vectors;
94 next_index = node->cached_next_index;
96 if (node->flags & VLIB_NODE_FLAG_TRACE)
97 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
99 sizeof (ip4_source_check_trace_t));
101 while (n_left_from > 0)
105 vlib_get_next_frame (vm, node, next_index,
106 to_next, n_left_to_next);
108 while (n_left_from >= 4 && n_left_to_next >= 2)
110 vlib_buffer_t * p0, * p1;
111 ip4_header_t * ip0, * ip1;
112 ip4_fib_mtrie_t * mtrie0, * mtrie1;
113 ip4_fib_mtrie_leaf_t leaf0, leaf1;
114 ip4_source_check_config_t * c0, * c1;
115 const load_balance_t * lb0, * lb1;
116 u32 pi0, next0, pass0, lb_index0;
117 u32 pi1, next1, pass1, lb_index1;
118 const ip_adjacency_t *adj0, *adj1;
119 const dpo_id_t *dpo0, *dpo1;
122 /* Prefetch next iteration. */
124 vlib_buffer_t * p2, * p3;
126 p2 = vlib_get_buffer (vm, from[2]);
127 p3 = vlib_get_buffer (vm, from[3]);
129 vlib_prefetch_buffer_header (p2, LOAD);
130 vlib_prefetch_buffer_header (p3, LOAD);
132 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
133 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
136 pi0 = to_next[0] = from[0];
137 pi1 = to_next[1] = from[1];
143 p0 = vlib_get_buffer (vm, pi0);
144 p1 = vlib_get_buffer (vm, pi1);
146 ip0 = vlib_buffer_get_current (p0);
147 ip1 = vlib_buffer_get_current (p1);
149 c0 = vnet_get_config_data (&cm->config_main,
150 &p0->current_config_index,
153 c1 = vnet_get_config_data (&cm->config_main,
154 &p1->current_config_index,
158 mtrie0 = &ip4_fib_get (c0->fib_index)->mtrie;
159 mtrie1 = &ip4_fib_get (c1->fib_index)->mtrie;
161 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
163 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
164 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
166 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
167 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
169 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
170 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
172 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
173 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
175 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
176 lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
178 lb0 = load_balance_get(lb_index0);
179 lb1 = load_balance_get(lb_index1);
181 /* Pass multicast. */
182 pass0 = ip4_address_is_multicast (&ip0->src_address) || ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
183 pass1 = ip4_address_is_multicast (&ip1->src_address) || ip1->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
185 if (PREDICT_TRUE(1 == lb0->lb_n_buckets))
187 dpo0 = load_balance_get_bucket_i(lb0, 0);
188 if (PREDICT_TRUE(dpo0->dpoi_type == DPO_ADJACENCY))
190 pass0 |= (source_check_type ==
191 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
192 adj0 = adj_get(dpo0->dpoi_index);
193 pass0 |= (vnet_buffer (p0)->sw_if_index[VLIB_RX] ==
194 adj0->rewrite_header.sw_if_index);
199 for (ii0 = 0; ii0 < lb0->lb_n_buckets && !pass0; ii0++)
201 dpo0 = load_balance_get_bucket_i(lb0, ii0);
202 if (PREDICT_TRUE(dpo0->dpoi_type == DPO_ADJACENCY))
204 pass0 |= (source_check_type ==
205 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
206 adj0 = adj_get(dpo0->dpoi_index);
207 pass0 |= (vnet_buffer (p0)->sw_if_index[VLIB_RX] ==
208 adj0->rewrite_header.sw_if_index);
212 if (PREDICT_TRUE(1 == lb1->lb_n_buckets))
214 dpo1 = load_balance_get_bucket_i(lb1, 0);
215 if (PREDICT_TRUE(dpo1->dpoi_type == DPO_ADJACENCY))
217 pass1 |= (source_check_type ==
218 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
219 adj1 = adj_get(dpo1->dpoi_index);
220 pass1 |= (vnet_buffer (p1)->sw_if_index[VLIB_RX] ==
221 adj1->rewrite_header.sw_if_index);
226 for (ii1 = 0; ii1 < lb1->lb_n_buckets && !pass1; ii1++)
228 dpo1 = load_balance_get_bucket_i(lb1, ii1);
229 if (PREDICT_TRUE(dpo1->dpoi_type == DPO_ADJACENCY))
231 pass1 |= (source_check_type ==
232 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
233 adj1 = adj_get(dpo1->dpoi_index);
234 pass1 |= (vnet_buffer (p1)->sw_if_index[VLIB_RX] ==
235 adj1->rewrite_header.sw_if_index);
240 next0 = (pass0 ? next0 : IP4_SOURCE_CHECK_NEXT_DROP);
241 next1 = (pass1 ? next1 : IP4_SOURCE_CHECK_NEXT_DROP);
243 p0->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
244 p1->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
246 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
247 to_next, n_left_to_next,
248 pi0, pi1, next0, next1);
251 while (n_left_from > 0 && n_left_to_next > 0)
255 ip4_fib_mtrie_t * mtrie0;
256 ip4_fib_mtrie_leaf_t leaf0;
257 ip4_source_check_config_t * c0;
258 ip_adjacency_t * adj0;
259 u32 pi0, next0, pass0, lb_index0;
260 const load_balance_t * lb0;
261 const dpo_id_t *dpo0;
271 p0 = vlib_get_buffer (vm, pi0);
272 ip0 = vlib_buffer_get_current (p0);
274 c0 = vnet_get_config_data (&cm->config_main,
275 &p0->current_config_index,
279 mtrie0 = &ip4_fib_get (c0->fib_index)->mtrie;
281 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
283 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
285 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
287 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
289 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
291 lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
293 lb0 = load_balance_get(lb_index0);
295 /* Pass multicast. */
296 pass0 = ip4_address_is_multicast (&ip0->src_address) || ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
298 if (PREDICT_TRUE(1 == lb0->lb_n_buckets))
300 dpo0 = load_balance_get_bucket_i(lb0, 0);
301 if (PREDICT_TRUE(dpo0->dpoi_type == DPO_ADJACENCY))
303 pass0 |= (source_check_type ==
304 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
305 adj0 = adj_get(dpo0->dpoi_index);
306 pass0 |= (vnet_buffer (p0)->sw_if_index[VLIB_RX] ==
307 adj0->rewrite_header.sw_if_index);
312 for (ii0 = 0; ii0 < lb0->lb_n_buckets && !pass0; ii0++)
314 dpo0 = load_balance_get_bucket_i(lb0, ii0);
315 if (PREDICT_TRUE(dpo0->dpoi_type == DPO_ADJACENCY))
317 pass0 |= (source_check_type ==
318 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
319 adj0 = adj_get(dpo0->dpoi_index);
320 pass0 |= (vnet_buffer (p0)->sw_if_index[VLIB_RX] ==
321 adj0->rewrite_header.sw_if_index);
326 next0 = (pass0 ? next0 : IP4_SOURCE_CHECK_NEXT_DROP);
327 p0->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
329 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
330 to_next, n_left_to_next,
334 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
337 return frame->n_vectors;
341 ip4_source_check_reachable_via_any (vlib_main_t * vm,
342 vlib_node_runtime_t * node,
343 vlib_frame_t * frame)
345 return ip4_source_check_inline (vm, node, frame, IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
349 ip4_source_check_reachable_via_rx (vlib_main_t * vm,
350 vlib_node_runtime_t * node,
351 vlib_frame_t * frame)
353 return ip4_source_check_inline (vm, node, frame, IP4_SOURCE_CHECK_REACHABLE_VIA_RX);
356 VLIB_REGISTER_NODE (ip4_check_source_reachable_via_any) = {
357 .function = ip4_source_check_reachable_via_any,
358 .name = "ip4-source-check-via-any",
359 .vector_size = sizeof (u32),
361 .n_next_nodes = IP4_SOURCE_CHECK_N_NEXT,
363 [IP4_SOURCE_CHECK_NEXT_DROP] = "error-drop",
366 .format_buffer = format_ip4_header,
367 .format_trace = format_ip4_source_check_trace,
370 VLIB_NODE_FUNCTION_MULTIARCH (ip4_check_source_reachable_via_any,
371 ip4_source_check_reachable_via_any)
373 VLIB_REGISTER_NODE (ip4_check_source_reachable_via_rx) = {
374 .function = ip4_source_check_reachable_via_rx,
375 .name = "ip4-source-check-via-rx",
376 .vector_size = sizeof (u32),
378 .n_next_nodes = IP4_SOURCE_CHECK_N_NEXT,
380 [IP4_SOURCE_CHECK_NEXT_DROP] = "error-drop",
383 .format_buffer = format_ip4_header,
384 .format_trace = format_ip4_source_check_trace,
387 VLIB_NODE_FUNCTION_MULTIARCH (ip4_check_source_reachable_via_rx,
388 ip4_source_check_reachable_via_rx)
390 static clib_error_t *
391 set_ip_source_check (vlib_main_t * vm,
392 unformat_input_t * input,
393 vlib_cli_command_t * cmd)
395 vnet_main_t * vnm = vnet_get_main();
396 ip4_main_t * im = &ip4_main;
397 ip_lookup_main_t * lm = &im->lookup_main;
398 ip_config_main_t * rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
399 clib_error_t * error = 0;
400 u32 sw_if_index, is_del, ci;
401 ip4_source_check_config_t config;
406 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
408 error = clib_error_return (0, "unknown interface `%U'",
409 format_unformat_error, input);
414 config.no_default_route = 0;
415 config.fib_index = im->fib_index_by_sw_if_index[sw_if_index];
416 feature_index = im->ip4_unicast_rx_feature_source_reachable_via_rx;
417 if (unformat (input, "del"))
420 ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
422 ? vnet_config_del_feature
423 : vnet_config_add_feature)
424 (vm, &rx_cm->config_main,
429 rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
435 VLIB_CLI_COMMAND (set_interface_ip_source_check_command, static) = {
436 .path = "set interface ip source-check",
437 .function = set_ip_source_check,
438 .short_help = "Set IP4/IP6 interface unicast source check",
441 /* Dummy init function to get us linked in. */
442 clib_error_t * ip4_source_check_init (vlib_main_t * vm)
445 VLIB_INIT_FUNCTION (ip4_source_check_init);