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>
44 } ip4_source_check_trace_t;
46 static u8 * format_ip4_source_check_trace (u8 * s, va_list * va)
48 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
49 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
50 ip4_source_check_trace_t * t = va_arg (*va, ip4_source_check_trace_t *);
54 t->packet_data, sizeof (t->packet_data));
60 IP4_SOURCE_CHECK_NEXT_DROP,
61 IP4_SOURCE_CHECK_N_NEXT,
62 } ip4_source_check_next_t;
65 IP4_SOURCE_CHECK_REACHABLE_VIA_RX,
66 IP4_SOURCE_CHECK_REACHABLE_VIA_ANY,
67 } ip4_source_check_type_t;
71 u32 no_default_route : 1;
75 } ip4_source_check_config_t;
78 ip4_source_check_inline (vlib_main_t * vm,
79 vlib_node_runtime_t * node,
81 ip4_source_check_type_t source_check_type)
83 ip4_main_t * im = &ip4_main;
84 ip_lookup_main_t * lm = &im->lookup_main;
85 ip_config_main_t * cm = &lm->rx_config_mains[VNET_UNICAST];
86 u32 n_left_from, * from, * to_next;
88 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
90 from = vlib_frame_vector_args (frame);
91 n_left_from = frame->n_vectors;
92 next_index = node->cached_next_index;
94 if (node->flags & VLIB_NODE_FLAG_TRACE)
95 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
97 sizeof (ip4_source_check_trace_t));
99 while (n_left_from > 0)
103 vlib_get_next_frame (vm, node, next_index,
104 to_next, n_left_to_next);
106 while (n_left_from >= 4 && n_left_to_next >= 2)
108 vlib_buffer_t * p0, * p1;
109 ip4_header_t * ip0, * ip1;
110 ip4_fib_mtrie_t * mtrie0, * mtrie1;
111 ip4_fib_mtrie_leaf_t leaf0, leaf1;
112 ip4_source_check_config_t * c0, * c1;
113 ip_adjacency_t * adj0, * adj1;
114 u32 pi0, next0, pass0, adj_index0;
115 u32 pi1, next1, pass1, adj_index1;
117 /* Prefetch next iteration. */
119 vlib_buffer_t * p2, * p3;
121 p2 = vlib_get_buffer (vm, from[2]);
122 p3 = vlib_get_buffer (vm, from[3]);
124 vlib_prefetch_buffer_header (p2, LOAD);
125 vlib_prefetch_buffer_header (p3, LOAD);
127 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
128 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
131 pi0 = to_next[0] = from[0];
132 pi1 = to_next[1] = from[1];
138 p0 = vlib_get_buffer (vm, pi0);
139 p1 = vlib_get_buffer (vm, pi1);
141 ip0 = vlib_buffer_get_current (p0);
142 ip1 = vlib_buffer_get_current (p1);
144 c0 = vnet_get_config_data (&cm->config_main,
145 &vnet_buffer (p0)->ip.current_config_index,
148 c1 = vnet_get_config_data (&cm->config_main,
149 &vnet_buffer (p1)->ip.current_config_index,
153 mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
154 mtrie1 = &vec_elt_at_index (im->fibs, c1->fib_index)->mtrie;
156 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
158 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
159 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
161 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
162 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
164 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
165 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
167 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
168 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
170 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
171 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
173 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, c0->fib_index,
175 c0->no_default_route));
176 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, c1->fib_index,
178 c1->no_default_route));
180 adj0 = ip_get_adjacency (lm, adj_index0);
181 adj1 = ip_get_adjacency (lm, adj_index1);
183 /* Pass multicast. */
184 pass0 = ip4_address_is_multicast (&ip0->src_address) || ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
185 pass1 = ip4_address_is_multicast (&ip1->src_address) || ip1->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
187 pass0 |= (adj0->lookup_next_index == IP_LOOKUP_NEXT_REWRITE
188 && (source_check_type == IP4_SOURCE_CHECK_REACHABLE_VIA_ANY
189 || vnet_buffer (p0)->sw_if_index[VLIB_RX] == adj0->rewrite_header.sw_if_index));
190 pass1 |= (adj1->lookup_next_index == IP_LOOKUP_NEXT_REWRITE
191 && (source_check_type == IP4_SOURCE_CHECK_REACHABLE_VIA_ANY
192 || vnet_buffer (p1)->sw_if_index[VLIB_RX] == adj1->rewrite_header.sw_if_index));
194 next0 = (pass0 ? next0 : IP4_SOURCE_CHECK_NEXT_DROP);
195 next1 = (pass1 ? next1 : IP4_SOURCE_CHECK_NEXT_DROP);
197 p0->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
198 p1->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
200 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
201 to_next, n_left_to_next,
202 pi0, pi1, next0, next1);
205 while (n_left_from > 0 && n_left_to_next > 0)
209 ip4_fib_mtrie_t * mtrie0;
210 ip4_fib_mtrie_leaf_t leaf0;
211 ip4_source_check_config_t * c0;
212 ip_adjacency_t * adj0;
213 u32 pi0, next0, pass0, adj_index0;
222 p0 = vlib_get_buffer (vm, pi0);
223 ip0 = vlib_buffer_get_current (p0);
225 c0 = vnet_get_config_data (&cm->config_main,
226 &vnet_buffer (p0)->ip.current_config_index,
230 mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
232 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
234 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
236 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
238 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
240 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
242 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
244 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, c0->fib_index,
246 c0->no_default_route));
247 adj0 = ip_get_adjacency (lm, adj_index0);
249 /* Pass multicast. */
250 pass0 = ip4_address_is_multicast (&ip0->src_address) || ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
252 pass0 |= (adj0->lookup_next_index == IP_LOOKUP_NEXT_REWRITE
253 && (source_check_type == IP4_SOURCE_CHECK_REACHABLE_VIA_ANY
254 || vnet_buffer (p0)->sw_if_index[VLIB_RX] == adj0->rewrite_header.sw_if_index));
256 next0 = (pass0 ? next0 : IP4_SOURCE_CHECK_NEXT_DROP);
257 p0->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
259 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
260 to_next, n_left_to_next,
264 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
267 return frame->n_vectors;
271 ip4_source_check_reachable_via_any (vlib_main_t * vm,
272 vlib_node_runtime_t * node,
273 vlib_frame_t * frame)
275 return ip4_source_check_inline (vm, node, frame, IP4_SOURCE_CHECK_REACHABLE_VIA_ANY);
279 ip4_source_check_reachable_via_rx (vlib_main_t * vm,
280 vlib_node_runtime_t * node,
281 vlib_frame_t * frame)
283 return ip4_source_check_inline (vm, node, frame, IP4_SOURCE_CHECK_REACHABLE_VIA_RX);
286 VLIB_REGISTER_NODE (ip4_check_source_reachable_via_any) = {
287 .function = ip4_source_check_reachable_via_any,
288 .name = "ip4-source-check-via-any",
289 .vector_size = sizeof (u32),
291 .n_next_nodes = IP4_SOURCE_CHECK_N_NEXT,
293 [IP4_SOURCE_CHECK_NEXT_DROP] = "error-drop",
296 .format_buffer = format_ip4_header,
297 .format_trace = format_ip4_source_check_trace,
300 VLIB_REGISTER_NODE (ip4_check_source_reachable_via_rx) = {
301 .function = ip4_source_check_reachable_via_rx,
302 .name = "ip4-source-check-via-rx",
303 .vector_size = sizeof (u32),
305 .n_next_nodes = IP4_SOURCE_CHECK_N_NEXT,
307 [IP4_SOURCE_CHECK_NEXT_DROP] = "error-drop",
310 .format_buffer = format_ip4_header,
311 .format_trace = format_ip4_source_check_trace,
314 static clib_error_t *
315 set_ip_source_check (vlib_main_t * vm,
316 unformat_input_t * input,
317 vlib_cli_command_t * cmd)
319 vnet_main_t * vnm = vnet_get_main();
320 ip4_main_t * im = &ip4_main;
321 ip_lookup_main_t * lm = &im->lookup_main;
322 ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
323 clib_error_t * error = 0;
324 u32 sw_if_index, is_del, ci;
325 ip4_source_check_config_t config;
326 ip4_rx_feature_type_t type;
330 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
332 error = clib_error_return (0, "unknown interface `%U'",
333 format_unformat_error, input);
338 config.no_default_route = 0;
339 config.fib_index = im->fib_index_by_sw_if_index[sw_if_index];
340 type = IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_RX;
341 if (unformat (input, "del"))
344 ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
346 ? vnet_config_del_feature
347 : vnet_config_add_feature)
348 (vm, &rx_cm->config_main,
353 rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
359 VLIB_CLI_COMMAND (set_interface_ip_source_check_command, static) = {
360 .path = "set interface ip source-check",
361 .function = set_ip_source_check,
362 .short_help = "Set IP4/IP6 interface unicast source check",
365 /* Dummy init function to get us linked in. */
366 clib_error_t * ip4_source_check_init (vlib_main_t * vm)
369 VLIB_INIT_FUNCTION (ip4_source_check_init);