Line data Source code
1 : /*
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_source_check.c: IP v4 check source address (unicast RPF check)
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 : #ifndef __URPF_DP_H__
41 : #define __URPF_DP_H__
42 :
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>
47 :
48 : #include <urpf/urpf.h>
49 :
50 : /**
51 : * @file
52 : * @brief Unicast Reverse Path forwarding.
53 : *
54 : * This file contains the interface unicast source check.
55 : */
56 : typedef struct
57 : {
58 : index_t urpf;
59 : } urpf_trace_t;
60 :
61 : static u8 *
62 1426 : format_urpf_trace (u8 * s, va_list * va)
63 : {
64 1426 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
65 1426 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
66 1426 : urpf_trace_t *t = va_arg (*va, urpf_trace_t *);
67 :
68 1426 : s = format (s, "uRPF:%d", t->urpf);
69 :
70 1426 : return s;
71 : }
72 :
73 : #define foreach_urpf_error \
74 : _(DROP, "uRPF Drop") \
75 :
76 : typedef enum urpf_error_t_
77 : {
78 : #define _(a,b) URPF_ERROR_##a,
79 : foreach_urpf_error
80 : #undef _
81 : URPF_N_ERROR,
82 : } urpf_error_t;
83 :
84 : typedef enum
85 : {
86 : URPF_NEXT_DROP,
87 : URPF_N_NEXT,
88 : } urpf_next_t;
89 :
90 : static_always_inline uword
91 26 : urpf_inline (vlib_main_t * vm,
92 : vlib_node_runtime_t * node,
93 : vlib_frame_t * frame,
94 : ip_address_family_t af, vlib_dir_t dir, urpf_mode_t mode)
95 : {
96 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
97 : u16 nexts[VLIB_FRAME_SIZE], *next;
98 : u32 n_left, *from;
99 :
100 26 : from = vlib_frame_vector_args (frame);
101 26 : n_left = frame->n_vectors;
102 26 : b = bufs;
103 26 : next = nexts;
104 :
105 26 : vlib_get_buffers (vm, from, bufs, n_left);
106 :
107 806 : while (n_left >= 4)
108 : {
109 : u32 pass0, lb_index0, pass1, lb_index1;
110 : const load_balance_t *lb0, *lb1;
111 : u32 fib_index0, fib_index1;
112 : const u8 *h0, *h1;
113 :
114 : /* Prefetch next iteration. */
115 : {
116 780 : vlib_prefetch_buffer_header (b[2], LOAD);
117 780 : vlib_prefetch_buffer_header (b[3], LOAD);
118 780 : vlib_prefetch_buffer_data (b[2], LOAD);
119 780 : vlib_prefetch_buffer_data (b[3], LOAD);
120 : }
121 :
122 780 : h0 = (u8 *) vlib_buffer_get_current (b[0]);
123 780 : h1 = (u8 *) vlib_buffer_get_current (b[1]);
124 :
125 780 : if (VLIB_TX == dir)
126 : {
127 420 : h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
128 420 : h1 += vnet_buffer (b[1])->ip.save_rewrite_length;
129 : }
130 :
131 780 : fib_index0 =
132 780 : urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index;
133 780 : fib_index1 =
134 780 : urpf_cfgs[af][dir][vnet_buffer (b[1])->sw_if_index[dir]].fib_index;
135 :
136 780 : if (AF_IP4 == af)
137 : {
138 : const ip4_header_t *ip0, *ip1;
139 :
140 390 : ip0 = (ip4_header_t *) h0;
141 390 : ip1 = (ip4_header_t *) h1;
142 :
143 390 : ip4_fib_forwarding_lookup_x2 (fib_index0,
144 : fib_index1,
145 : &ip0->src_address,
146 : &ip1->src_address,
147 : &lb_index0, &lb_index1);
148 : /* Pass multicast. */
149 780 : pass0 = (ip4_address_is_multicast (&ip0->src_address) ||
150 390 : ip4_address_is_global_broadcast (&ip0->src_address));
151 780 : pass1 = (ip4_address_is_multicast (&ip1->src_address) ||
152 390 : ip4_address_is_global_broadcast (&ip1->src_address));
153 : }
154 : else
155 : {
156 : const ip6_header_t *ip0, *ip1;
157 :
158 390 : ip0 = (ip6_header_t *) h0;
159 390 : ip1 = (ip6_header_t *) h1;
160 :
161 390 : lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
162 : &ip0->src_address);
163 390 : lb_index1 = ip6_fib_table_fwding_lookup (fib_index1,
164 : &ip1->src_address);
165 390 : pass0 = ip6_address_is_multicast (&ip0->src_address);
166 390 : pass1 = ip6_address_is_multicast (&ip1->src_address);
167 : }
168 :
169 780 : lb0 = load_balance_get (lb_index0);
170 780 : lb1 = load_balance_get (lb_index1);
171 :
172 780 : if (URPF_MODE_STRICT == mode)
173 : {
174 : /* for RX the check is: would this source adddress be forwarded
175 : * out of the interface on which it was recieved, if yes allow.
176 : * For TX it's; would this source address be forwarded out of the
177 : * interface through which it is being sent, if yes drop.
178 : */
179 : int res0, res1;
180 :
181 420 : res0 = fib_urpf_check (lb0->lb_urpf,
182 420 : vnet_buffer (b[0])->sw_if_index[dir]);
183 420 : res1 = fib_urpf_check (lb1->lb_urpf,
184 420 : vnet_buffer (b[1])->sw_if_index[dir]);
185 :
186 420 : if (VLIB_RX == dir)
187 : {
188 180 : pass0 |= res0;
189 180 : pass1 |= res1;
190 : }
191 : else
192 : {
193 240 : pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf);
194 240 : pass1 |= !res1 && fib_urpf_check_size (lb1->lb_urpf);
195 :
196 : /* allow locally generated */
197 240 : pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
198 240 : pass1 |= b[1]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
199 : }
200 : }
201 : else
202 : {
203 360 : pass0 |= fib_urpf_check_size (lb0->lb_urpf);
204 360 : pass1 |= fib_urpf_check_size (lb1->lb_urpf);
205 : }
206 :
207 780 : if (PREDICT_TRUE (pass0))
208 420 : vnet_feature_next_u16 (&next[0], b[0]);
209 : else
210 : {
211 360 : next[0] = URPF_NEXT_DROP;
212 360 : b[0]->error = node->errors[URPF_ERROR_DROP];
213 : }
214 780 : if (PREDICT_TRUE (pass1))
215 420 : vnet_feature_next_u16 (&next[1], b[1]);
216 : else
217 : {
218 360 : next[1] = URPF_NEXT_DROP;
219 360 : b[1]->error = node->errors[URPF_ERROR_DROP];
220 : }
221 :
222 780 : if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
223 : {
224 : urpf_trace_t *t;
225 :
226 780 : t = vlib_add_trace (vm, node, b[0], sizeof (*t));
227 780 : t->urpf = lb0->lb_urpf;
228 : }
229 780 : if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
230 : {
231 : urpf_trace_t *t;
232 :
233 780 : t = vlib_add_trace (vm, node, b[1], sizeof (*t));
234 780 : t->urpf = lb1->lb_urpf;
235 : }
236 :
237 780 : b += 2;
238 780 : next += 2;
239 780 : n_left -= 2;
240 : }
241 :
242 104 : while (n_left)
243 : {
244 : u32 pass0, lb_index0, fib_index0;
245 : const load_balance_t *lb0;
246 : const u8 *h0;
247 :
248 78 : h0 = (u8 *) vlib_buffer_get_current (b[0]);
249 :
250 78 : if (VLIB_TX == dir)
251 42 : h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
252 :
253 78 : fib_index0 =
254 78 : urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index;
255 :
256 78 : if (AF_IP4 == af)
257 : {
258 : const ip4_header_t *ip0;
259 :
260 39 : ip0 = (ip4_header_t *) h0;
261 :
262 39 : lb_index0 = ip4_fib_forwarding_lookup (fib_index0,
263 : &ip0->src_address);
264 :
265 : /* Pass multicast. */
266 78 : pass0 = (ip4_address_is_multicast (&ip0->src_address) ||
267 39 : ip4_address_is_global_broadcast (&ip0->src_address));
268 : }
269 : else
270 : {
271 : const ip6_header_t *ip0;
272 :
273 39 : ip0 = (ip6_header_t *) h0;
274 :
275 39 : lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
276 : &ip0->src_address);
277 39 : pass0 = ip6_address_is_multicast (&ip0->src_address);
278 : }
279 :
280 78 : lb0 = load_balance_get (lb_index0);
281 :
282 78 : if (URPF_MODE_STRICT == mode)
283 : {
284 : int res0;
285 :
286 42 : res0 = fib_urpf_check (lb0->lb_urpf,
287 42 : vnet_buffer (b[0])->sw_if_index[dir]);
288 42 : if (VLIB_RX == dir)
289 18 : pass0 |= res0;
290 : else
291 : {
292 24 : pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf);
293 24 : pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
294 : }
295 : }
296 : else
297 36 : pass0 |= fib_urpf_check_size (lb0->lb_urpf);
298 :
299 78 : if (PREDICT_TRUE (pass0))
300 42 : vnet_feature_next_u16 (&next[0], b[0]);
301 : else
302 : {
303 36 : next[0] = URPF_NEXT_DROP;
304 36 : b[0]->error = node->errors[URPF_ERROR_DROP];
305 : }
306 :
307 78 : if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
308 : {
309 : urpf_trace_t *t;
310 :
311 78 : t = vlib_add_trace (vm, node, b[0], sizeof (*t));
312 78 : t->urpf = lb0->lb_urpf;
313 : }
314 78 : b++;
315 78 : next++;
316 78 : n_left--;
317 : }
318 :
319 26 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
320 :
321 26 : return frame->n_vectors;
322 : }
323 :
324 : #endif
325 :
326 : /*
327 : * fd.io coding-style-patch-verification: ON
328 : *
329 : * Local Variables:
330 : * eval: (c-set-style "gnu")
331 : * End:
332 : */
|