Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 : #include <vnet/mfib/mfib_itf.h>
17 : #include <vnet/mfib/mfib_entry.h>
18 : #include <vnet/dpo/replicate_dpo.h>
19 : #include <vnet/mfib/ip4_mfib.h>
20 : #include <vnet/mfib/ip6_mfib.h>
21 : #include <vnet/mfib/mfib_signal.h>
22 : #include <vnet/fib/ip4_fib.h>
23 : #include <vnet/fib/ip6_fib.h>
24 :
25 : #include <vnet/ip/ip4.h>
26 : #include <vnet/vnet.h>
27 :
28 : typedef struct mfib_forward_lookup_trace_t_ {
29 : u32 entry_index;
30 : u32 fib_index;
31 : } mfib_forward_lookup_trace_t;
32 :
33 : static u8 *
34 2964 : format_mfib_forward_lookup_trace (u8 * s, va_list * args)
35 : {
36 2964 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37 2964 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38 2964 : mfib_forward_lookup_trace_t * t = va_arg (*args, mfib_forward_lookup_trace_t *);
39 :
40 2964 : s = format (s, "fib %d entry %d", t->fib_index, t->entry_index);
41 2964 : return s;
42 : }
43 :
44 : /* Common trace function for all ip4-forward next nodes. */
45 : static void
46 1712 : mfib_forward_lookup_trace (vlib_main_t * vm,
47 : vlib_node_runtime_t * node,
48 : vlib_frame_t * frame)
49 : {
50 : u32 * from, n_left;
51 1712 : ip4_main_t * im = &ip4_main;
52 :
53 1712 : n_left = frame->n_vectors;
54 1712 : from = vlib_frame_vector_args (frame);
55 :
56 3117 : while (n_left >= 4)
57 : {
58 : mfib_forward_lookup_trace_t * t0, * t1;
59 : vlib_buffer_t * b0, * b1;
60 : u32 bi0, bi1;
61 :
62 : /* Prefetch next iteration. */
63 1405 : vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
64 1405 : vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
65 :
66 1405 : bi0 = from[0];
67 1405 : bi1 = from[1];
68 :
69 1405 : b0 = vlib_get_buffer (vm, bi0);
70 1405 : b1 = vlib_get_buffer (vm, bi1);
71 :
72 1405 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
73 : {
74 1405 : t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
75 1405 : t0->entry_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
76 1405 : t0->fib_index = vec_elt (im->mfib_index_by_sw_if_index,
77 : vnet_buffer(b1)->sw_if_index[VLIB_RX]);
78 : }
79 1405 : if (b1->flags & VLIB_BUFFER_IS_TRACED)
80 : {
81 1405 : t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
82 1405 : t1->entry_index = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
83 1405 : t1->fib_index = vec_elt (im->mfib_index_by_sw_if_index,
84 : vnet_buffer(b1)->sw_if_index[VLIB_RX]);
85 : }
86 1405 : from += 2;
87 1405 : n_left -= 2;
88 : }
89 :
90 3490 : while (n_left >= 1)
91 : {
92 : mfib_forward_lookup_trace_t * t0;
93 : vlib_buffer_t * b0;
94 : u32 bi0;
95 :
96 1778 : bi0 = from[0];
97 :
98 1778 : b0 = vlib_get_buffer (vm, bi0);
99 :
100 1778 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
101 : {
102 1778 : t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
103 1778 : t0->entry_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
104 1778 : t0->fib_index = vec_elt (im->mfib_index_by_sw_if_index,
105 : vnet_buffer(b0)->sw_if_index[VLIB_RX]);
106 : }
107 1778 : from += 1;
108 1778 : n_left -= 1;
109 : }
110 1712 : }
111 :
112 : typedef enum mfib_forward_lookup_next_t_ {
113 : MFIB_FORWARD_LOOKUP_NEXT_RPF,
114 : MFIB_FORWARD_LOOKUP_N_NEXT,
115 : } mfib_forward_lookup_next_t;
116 :
117 : static uword
118 2190 : mfib_forward_lookup (vlib_main_t * vm,
119 : vlib_node_runtime_t * node,
120 : vlib_frame_t * frame,
121 : int is_v4)
122 : {
123 : u32 n_left_from, n_left_to_next, * from, * to_next;
124 :
125 2190 : from = vlib_frame_vector_args (frame);
126 2190 : n_left_from = frame->n_vectors;
127 :
128 4380 : while (n_left_from > 0)
129 : {
130 2190 : vlib_get_next_frame (vm, node, MFIB_FORWARD_LOOKUP_NEXT_RPF,
131 : to_next, n_left_to_next);
132 :
133 7355 : while (n_left_from > 0 && n_left_to_next > 0)
134 : {
135 : fib_node_index_t mfei0;
136 : vlib_buffer_t * p0;
137 : u32 fib_index0;
138 : u32 pi0;
139 :
140 5165 : pi0 = from[0];
141 5165 : to_next[0] = pi0;
142 5165 : from += 1;
143 5165 : to_next += 1;
144 5165 : n_left_to_next -= 1;
145 5165 : n_left_from -= 1;
146 :
147 5165 : p0 = vlib_get_buffer (vm, pi0);
148 :
149 5165 : if (is_v4)
150 : {
151 : ip4_header_t * ip0;
152 :
153 2090 : ip_lookup_set_buffer_fib_index (
154 : ip4_main.fib_index_by_sw_if_index, p0);
155 2090 : fib_index0 = vec_elt (ip4_main.mfib_index_by_sw_if_index,
156 : vnet_buffer (p0)->sw_if_index[VLIB_RX]);
157 2090 : ip0 = vlib_buffer_get_current (p0);
158 2090 : mfei0 = ip4_mfib_table_lookup (ip4_mfib_get (fib_index0),
159 2090 : &ip0->src_address,
160 2090 : &ip0->dst_address, 64);
161 : }
162 : else
163 : {
164 : ip6_header_t *ip0;
165 :
166 3075 : ip_lookup_set_buffer_fib_index (
167 : ip6_main.fib_index_by_sw_if_index, p0);
168 3075 : fib_index0 = vec_elt (ip6_main.mfib_index_by_sw_if_index,
169 : vnet_buffer (p0)->sw_if_index[VLIB_RX]);
170 3075 : ip0 = vlib_buffer_get_current (p0);
171 3075 : mfei0 = ip6_mfib_table_fwd_lookup (ip6_mfib_get (fib_index0),
172 3075 : &ip0->src_address,
173 3075 : &ip0->dst_address);
174 : }
175 :
176 5165 : vnet_buffer (p0)->ip.adj_index[VLIB_TX] = mfei0;
177 : }
178 :
179 2190 : vlib_put_next_frame (vm, node, MFIB_FORWARD_LOOKUP_NEXT_RPF,
180 : n_left_to_next);
181 : }
182 :
183 2190 : if (node->flags & VLIB_NODE_FLAG_TRACE)
184 1712 : mfib_forward_lookup_trace(vm, node, frame);
185 :
186 2190 : return frame->n_vectors;
187 : }
188 :
189 2334 : VLIB_NODE_FN (ip4_mfib_forward_lookup_node) (vlib_main_t * vm,
190 : vlib_node_runtime_t * node,
191 : vlib_frame_t * frame)
192 : {
193 34 : return (mfib_forward_lookup (vm, node, frame, 1));
194 : }
195 :
196 183788 : VLIB_REGISTER_NODE (ip4_mfib_forward_lookup_node) = {
197 : .name = "ip4-mfib-forward-lookup",
198 : .vector_size = sizeof (u32),
199 :
200 : .format_trace = format_mfib_forward_lookup_trace,
201 :
202 : .n_next_nodes = MFIB_FORWARD_LOOKUP_N_NEXT,
203 : .next_nodes = {
204 : [MFIB_FORWARD_LOOKUP_NEXT_RPF] = "ip4-mfib-forward-rpf",
205 : },
206 : };
207 :
208 4456 : VLIB_NODE_FN (ip6_mfib_forward_lookup_node) (vlib_main_t * vm,
209 : vlib_node_runtime_t * node,
210 : vlib_frame_t * frame)
211 : {
212 2156 : return (mfib_forward_lookup (vm, node, frame, 0));
213 : }
214 :
215 183788 : VLIB_REGISTER_NODE (ip6_mfib_forward_lookup_node) = {
216 : .name = "ip6-mfib-forward-lookup",
217 : .vector_size = sizeof (u32),
218 :
219 : .format_trace = format_mfib_forward_lookup_trace,
220 :
221 : .n_next_nodes = MFIB_FORWARD_LOOKUP_N_NEXT,
222 : .next_nodes = {
223 : [MFIB_FORWARD_LOOKUP_NEXT_RPF] = "ip6-mfib-forward-rpf",
224 : },
225 : };
226 :
227 :
228 : typedef struct mfib_forward_rpf_trace_t_ {
229 : u32 entry_index;
230 : u32 sw_if_index;
231 : mfib_itf_flags_t itf_flags;
232 : } mfib_forward_rpf_trace_t;
233 :
234 : typedef enum mfib_forward_rpf_next_t_ {
235 : MFIB_FORWARD_RPF_NEXT_DROP,
236 : MFIB_FORWARD_RPF_N_NEXT,
237 : } mfib_forward_rpf_next_t;
238 :
239 : static u8 *
240 3952 : format_mfib_forward_rpf_trace (u8 * s, va_list * args)
241 : {
242 3952 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
243 3952 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
244 3952 : mfib_forward_rpf_trace_t * t = va_arg (*args, mfib_forward_rpf_trace_t *);
245 :
246 3952 : s = format (s, "entry %d", t->entry_index);
247 3952 : s = format (s, " itf %d", t->sw_if_index);
248 3952 : s = format (s, " flags %U", format_mfib_itf_flags, t->itf_flags);
249 :
250 3952 : return s;
251 : }
252 :
253 : static int
254 364 : mfib_forward_connected_check (vlib_buffer_t * b0,
255 : u32 sw_if_index,
256 : int is_v4)
257 : {
258 : /*
259 : * Lookup the source of the IP packet in the
260 : * FIB. return true if the entry is attached.
261 : */
262 : index_t lbi0;
263 :
264 364 : if (is_v4)
265 : {
266 : load_balance_t *lb0;
267 : ip4_header_t *ip0;
268 :
269 364 : ip0 = vlib_buffer_get_current(b0);
270 :
271 364 : lbi0 = ip4_fib_forwarding_lookup(
272 : ip4_fib_table_get_index_for_sw_if_index(
273 : sw_if_index),
274 364 : &ip0->src_address);
275 364 : lb0 = load_balance_get(lbi0);
276 :
277 364 : return (FIB_ENTRY_FLAG_ATTACHED &
278 364 : lb0->lb_fib_entry_flags);
279 : }
280 : else
281 : {
282 0 : ASSERT(0);
283 : }
284 0 : return (0);
285 : }
286 :
287 : static void
288 637 : mfib_forward_itf_signal (vlib_main_t *vm,
289 : const mfib_entry_t *mfe,
290 : mfib_itf_t *mfi,
291 : vlib_buffer_t *b0)
292 : {
293 : mfib_itf_flags_t old_flags;
294 :
295 637 : old_flags = clib_atomic_fetch_or(&mfi->mfi_flags,
296 : MFIB_ITF_FLAG_SIGNAL_PRESENT);
297 :
298 637 : if (!(old_flags & MFIB_ITF_FLAG_SIGNAL_PRESENT))
299 : {
300 : /*
301 : * we were the lucky ones to set the signal present flag
302 : */
303 7 : if (!(old_flags & MFIB_ITF_FLAG_DONT_PRESERVE))
304 : {
305 : /*
306 : * preserve a copy of the packet for the control
307 : * plane to examine.
308 : * Only allow one preserved packet at at time, since
309 : * when the signal present flag is cleared so is the
310 : * preserved packet.
311 : */
312 7 : mfib_signal_push(mfe, mfi, b0);
313 : }
314 : else
315 : {
316 : /*
317 : * The control plane just wants the signal, not the packet as well
318 : */
319 0 : mfib_signal_push(mfe, mfi, NULL);
320 : }
321 : }
322 : /*
323 : * else
324 : * there is already a signal present on this interface that the
325 : * control plane has not yet acknowledged
326 : */
327 637 : }
328 :
329 : always_inline uword
330 2209 : mfib_forward_rpf (vlib_main_t * vm,
331 : vlib_node_runtime_t * node,
332 : vlib_frame_t * frame,
333 : int is_v4)
334 : {
335 : u32 n_left_from, n_left_to_next, * from, * to_next;
336 : mfib_forward_rpf_next_t next;
337 : vlib_node_runtime_t *error_node;
338 :
339 2209 : if (is_v4)
340 45 : error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
341 : else
342 2164 : error_node = vlib_node_get_runtime (vm, ip6_input_node.index);
343 2209 : from = vlib_frame_vector_args (frame);
344 2209 : n_left_from = frame->n_vectors;
345 2209 : next = MFIB_FORWARD_RPF_NEXT_DROP;
346 :
347 4418 : while (n_left_from > 0)
348 : {
349 2209 : vlib_get_next_frame (vm, node, next,
350 : to_next, n_left_to_next);
351 :
352 9055 : while (n_left_from > 0 && n_left_to_next > 0)
353 : {
354 : fib_node_index_t mfei0;
355 : const mfib_entry_t *mfe0;
356 : mfib_itf_t *mfi0;
357 : vlib_buffer_t * b0;
358 : u32 pi0, next0;
359 : mfib_itf_flags_t iflags0;
360 : mfib_entry_flags_t eflags0;
361 : u8 error0;
362 :
363 6846 : pi0 = from[0];
364 6846 : to_next[0] = pi0;
365 6846 : from += 1;
366 6846 : to_next += 1;
367 6846 : n_left_to_next -= 1;
368 6846 : n_left_from -= 1;
369 :
370 6846 : error0 = IP4_ERROR_NONE;
371 6846 : b0 = vlib_get_buffer (vm, pi0);
372 6846 : mfei0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
373 6846 : mfe0 = mfib_entry_get(mfei0);
374 6846 : mfi0 = mfib_entry_get_itf(mfe0,
375 6846 : vnet_buffer(b0)->sw_if_index[VLIB_RX]);
376 :
377 : /*
378 : * throughout this function we are 'PREDICT' optimising
379 : * for the case of throughput traffic that is not replicated
380 : * to the host stack nor sets local flags
381 : */
382 :
383 : /*
384 : * If the mfib entry has a configured RPF-ID check that
385 : * in preference to an interface based RPF
386 : */
387 6846 : if (MFIB_RPF_ID_NONE != mfe0->mfe_rpf_id)
388 : {
389 1423 : iflags0 = (mfe0->mfe_rpf_id == vnet_buffer(b0)->ip.rpf_id ?
390 1423 : MFIB_ITF_FLAG_ACCEPT :
391 : MFIB_ITF_FLAG_NONE);
392 : }
393 : else
394 : {
395 5423 : if (PREDICT_TRUE(NULL != mfi0))
396 : {
397 4974 : iflags0 = mfi0->mfi_flags;
398 : }
399 : else
400 : {
401 449 : iflags0 = MFIB_ITF_FLAG_NONE;
402 : }
403 : }
404 6846 : eflags0 = mfe0->mfe_flags;
405 :
406 6846 : if (PREDICT_FALSE(eflags0 & MFIB_ENTRY_FLAG_CONNECTED))
407 : {
408 : /*
409 : * lookup the source in the unicast FIB - check it
410 : * matches a connected.
411 : */
412 364 : if (mfib_forward_connected_check(
413 : b0,
414 364 : vnet_buffer(b0)->sw_if_index[VLIB_RX],
415 : is_v4))
416 : {
417 364 : mfib_forward_itf_signal(vm, mfe0, mfi0, b0);
418 : }
419 : }
420 6846 : if (PREDICT_FALSE((eflags0 & MFIB_ENTRY_FLAG_SIGNAL) ^
421 : (iflags0 & MFIB_ITF_FLAG_NEGATE_SIGNAL)))
422 : {
423 : /*
424 : * Entry signal XOR interface negate-signal
425 : */
426 273 : if (NULL != mfi0)
427 : {
428 273 : mfib_forward_itf_signal(vm, mfe0, mfi0, b0);
429 : }
430 : }
431 :
432 6846 : if (PREDICT_TRUE((iflags0 & MFIB_ITF_FLAG_ACCEPT) ||
433 : (eflags0 & MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF)))
434 : {
435 : /*
436 : * This interface is accepting packets for the matching entry
437 : */
438 5801 : next0 = mfe0->mfe_rep.dpoi_next_node;
439 :
440 5801 : vnet_buffer(b0)->ip.adj_index[VLIB_TX] =
441 5801 : mfe0->mfe_rep.dpoi_index;
442 : }
443 : else
444 : {
445 1045 : next0 = MFIB_FORWARD_RPF_NEXT_DROP;
446 1045 : error0 =
447 : (is_v4 ? IP4_ERROR_RPF_FAILURE : IP6_ERROR_RPF_FAILURE);
448 : }
449 :
450 6846 : b0->error = error0 ? error_node->errors[error0] : 0;
451 :
452 6846 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
453 : {
454 : mfib_forward_rpf_trace_t *t0;
455 :
456 6269 : t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
457 6269 : t0->entry_index = mfei0;
458 6269 : t0->itf_flags = iflags0;
459 6269 : if (NULL == mfi0)
460 : {
461 1872 : t0->sw_if_index = ~0;
462 : }
463 : else
464 : {
465 4397 : t0->sw_if_index = mfi0->mfi_sw_if_index;
466 : }
467 : }
468 6846 : vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next,
469 : n_left_to_next, pi0, next0);
470 : }
471 :
472 2209 : vlib_put_next_frame (vm, node, next, n_left_to_next);
473 : }
474 :
475 2209 : return frame->n_vectors;
476 : }
477 :
478 2345 : VLIB_NODE_FN (ip4_mfib_forward_rpf_node) (vlib_main_t * vm,
479 : vlib_node_runtime_t * node,
480 : vlib_frame_t * frame)
481 : {
482 45 : return (mfib_forward_rpf(vm, node, frame, 1));
483 : }
484 :
485 :
486 183788 : VLIB_REGISTER_NODE (ip4_mfib_forward_rpf_node) = {
487 : .name = "ip4-mfib-forward-rpf",
488 : .vector_size = sizeof (u32),
489 :
490 : .format_trace = format_mfib_forward_rpf_trace,
491 :
492 : .n_next_nodes = MFIB_FORWARD_RPF_N_NEXT,
493 : .next_nodes = {
494 : [MFIB_FORWARD_RPF_NEXT_DROP] = "ip4-drop",
495 : },
496 : };
497 :
498 4464 : VLIB_NODE_FN (ip6_mfib_forward_rpf_node) (vlib_main_t * vm,
499 : vlib_node_runtime_t * node,
500 : vlib_frame_t * frame)
501 : {
502 2164 : return (mfib_forward_rpf(vm, node, frame, 0));
503 : }
504 :
505 :
506 183788 : VLIB_REGISTER_NODE (ip6_mfib_forward_rpf_node) = {
507 : .name = "ip6-mfib-forward-rpf",
508 : .vector_size = sizeof (u32),
509 :
510 : .format_trace = format_mfib_forward_rpf_trace,
511 :
512 : .n_next_nodes = MFIB_FORWARD_RPF_N_NEXT,
513 : .next_nodes = {
514 : [MFIB_FORWARD_RPF_NEXT_DROP] = "ip6-drop",
515 : },
516 : };
517 :
|