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.
43 #include <vnet/fib/ip4_fib.h>
44 #include <vnet/fib/ip6_fib.h>
45 #include <vnet/fib/fib_urpf_list.h>
46 #include <vnet/dpo/load_balance.h>
48 #include <urpf/urpf.h>
52 * @brief Unicast Reverse Path forwarding.
54 * This file contains the interface unicast source check.
62 format_urpf_trace (u8 * s, va_list * va)
64 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
65 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
66 urpf_trace_t *t = va_arg (*va, urpf_trace_t *);
68 s = format (s, "uRPF:%d", t->urpf);
73 #define foreach_urpf_error \
74 _(DROP, "uRPF Drop") \
76 typedef enum urpf_error_t_
78 #define _(a,b) URPF_ERROR_##a,
90 static_always_inline uword
91 urpf_inline (vlib_main_t * vm,
92 vlib_node_runtime_t * node,
94 ip_address_family_t af, vlib_dir_t dir, urpf_mode_t mode)
96 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
97 u16 nexts[VLIB_FRAME_SIZE], *next;
100 from = vlib_frame_vector_args (frame);
101 n_left = frame->n_vectors;
105 vlib_get_buffers (vm, from, bufs, n_left);
109 u32 pass0, lb_index0, pass1, lb_index1;
110 const load_balance_t *lb0, *lb1;
111 u32 fib_index0, fib_index1;
114 /* Prefetch next iteration. */
116 vlib_prefetch_buffer_header (b[2], LOAD);
117 vlib_prefetch_buffer_header (b[3], LOAD);
118 vlib_prefetch_buffer_data (b[2], LOAD);
119 vlib_prefetch_buffer_data (b[3], LOAD);
122 h0 = (u8 *) vlib_buffer_get_current (b[0]);
123 h1 = (u8 *) vlib_buffer_get_current (b[1]);
127 h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
128 h1 += vnet_buffer (b[1])->ip.save_rewrite_length;
133 const ip4_header_t *ip0, *ip1;
135 ip0 = (ip4_header_t *) h0;
136 ip1 = (ip4_header_t *) h1;
138 fib_index0 = ip4_main.fib_index_by_sw_if_index
139 [vnet_buffer (b[0])->sw_if_index[dir]];
140 fib_index1 = ip4_main.fib_index_by_sw_if_index
141 [vnet_buffer (b[1])->sw_if_index[dir]];
143 ip4_fib_forwarding_lookup_x2 (fib_index0,
147 &lb_index0, &lb_index1);
148 /* Pass multicast. */
149 pass0 = (ip4_address_is_multicast (&ip0->src_address) ||
150 ip4_address_is_global_broadcast (&ip0->src_address));
151 pass1 = (ip4_address_is_multicast (&ip1->src_address) ||
152 ip4_address_is_global_broadcast (&ip1->src_address));
156 const ip6_header_t *ip0, *ip1;
158 fib_index0 = ip6_main.fib_index_by_sw_if_index
159 [vnet_buffer (b[0])->sw_if_index[dir]];
160 fib_index1 = ip6_main.fib_index_by_sw_if_index
161 [vnet_buffer (b[1])->sw_if_index[dir]];
163 ip0 = (ip6_header_t *) h0;
164 ip1 = (ip6_header_t *) h1;
166 lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
168 lb_index1 = ip6_fib_table_fwding_lookup (fib_index1,
170 pass0 = ip6_address_is_multicast (&ip0->src_address);
171 pass1 = ip6_address_is_multicast (&ip1->src_address);
174 lb0 = load_balance_get (lb_index0);
175 lb1 = load_balance_get (lb_index1);
177 if (URPF_MODE_STRICT == mode)
179 /* for RX the check is: would this source adddress be forwarded
180 * out of the interface on which it was recieved, if yes allow.
181 * For TX it's; would this source address be forwarded out of the
182 * interface through which it is being sent, if yes drop.
186 res0 = fib_urpf_check (lb0->lb_urpf,
187 vnet_buffer (b[0])->sw_if_index[dir]);
188 res1 = fib_urpf_check (lb1->lb_urpf,
189 vnet_buffer (b[1])->sw_if_index[dir]);
198 pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf);
199 pass1 |= !res1 && fib_urpf_check_size (lb1->lb_urpf);
201 /* allow locally generated */
202 pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
203 pass1 |= b[1]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
208 pass0 |= fib_urpf_check_size (lb0->lb_urpf);
209 pass1 |= fib_urpf_check_size (lb1->lb_urpf);
212 if (PREDICT_TRUE (pass0))
213 vnet_feature_next_u16 (&next[0], b[0]);
216 next[0] = URPF_NEXT_DROP;
217 b[0]->error = node->errors[URPF_ERROR_DROP];
219 if (PREDICT_TRUE (pass1))
220 vnet_feature_next_u16 (&next[1], b[1]);
223 next[1] = URPF_NEXT_DROP;
224 b[1]->error = node->errors[URPF_ERROR_DROP];
227 if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
231 t = vlib_add_trace (vm, node, b[0], sizeof (*t));
232 t->urpf = lb0->lb_urpf;
234 if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
238 t = vlib_add_trace (vm, node, b[1], sizeof (*t));
239 t->urpf = lb1->lb_urpf;
249 u32 pass0, lb_index0, fib_index0;
250 const load_balance_t *lb0;
253 h0 = (u8 *) vlib_buffer_get_current (b[0]);
256 h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
260 const ip4_header_t *ip0;
262 fib_index0 = ip4_main.fib_index_by_sw_if_index
263 [vnet_buffer (b[0])->sw_if_index[dir]];
264 ip0 = (ip4_header_t *) h0;
266 lb_index0 = ip4_fib_forwarding_lookup (fib_index0,
269 /* Pass multicast. */
270 pass0 = (ip4_address_is_multicast (&ip0->src_address) ||
271 ip4_address_is_global_broadcast (&ip0->src_address));
275 const ip6_header_t *ip0;
277 ip0 = (ip6_header_t *) h0;
278 fib_index0 = ip6_main.fib_index_by_sw_if_index
279 [vnet_buffer (b[0])->sw_if_index[dir]];
281 lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
283 pass0 = ip6_address_is_multicast (&ip0->src_address);
286 lb0 = load_balance_get (lb_index0);
288 if (URPF_MODE_STRICT == mode)
292 res0 = fib_urpf_check (lb0->lb_urpf,
293 vnet_buffer (b[0])->sw_if_index[dir]);
298 pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf);
299 pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
303 pass0 |= fib_urpf_check_size (lb0->lb_urpf);
305 if (PREDICT_TRUE (pass0))
306 vnet_feature_next_u16 (&next[0], b[0]);
309 next[0] = URPF_NEXT_DROP;
310 b[0]->error = node->errors[URPF_ERROR_DROP];
313 if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
317 t = vlib_add_trace (vm, node, b[0], sizeof (*t));
318 t->urpf = lb0->lb_urpf;
325 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
327 return frame->n_vectors;
333 * fd.io coding-style-patch-verification: ON
336 * eval: (c-set-style "gnu")