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:
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 #include <vnet/ip/ip.h>
17 #include <vnet/dpo/lookup_dpo.h>
18 #include <vnet/dpo/load_balance.h>
19 #include <vnet/mpls/mpls.h>
20 #include <vnet/fib/fib_table.h>
21 #include <vnet/fib/ip4_fib.h>
22 #include <vnet/fib/ip6_fib.h>
23 #include <vnet/fib/mpls_fib.h>
25 static const char *const lookup_input_names[] = LOOKUP_INPUTS;
28 * @brief Enumeration of the lookup subtypes
30 typedef enum lookup_sub_type_t_
34 LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE,
36 #define LOOKUP_SUB_TYPE_NUM (LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE+1)
38 #define FOR_EACH_LOOKUP_SUB_TYPE(_st) \
39 for (_st = LOOKUP_SUB_TYPE_IP4_SRC; _st < LOOKUP_SUB_TYPE_NUM; _st++)
42 * @brief pool of all MPLS Label DPOs
44 lookup_dpo_t *lookup_dpo_pool;
47 * @brief An array of registered DPO type values for the sub-types
49 static dpo_type_t lookup_dpo_sub_types[LOOKUP_SUB_TYPE_NUM];
52 lookup_dpo_alloc (void)
56 pool_get_aligned(lookup_dpo_pool, lkd, CLIB_CACHE_LINE_BYTES);
62 lookup_dpo_get_index (lookup_dpo_t *lkd)
64 return (lkd - lookup_dpo_pool);
68 lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
71 lookup_table_t table_config,
77 lkd = lookup_dpo_alloc();
78 lkd->lkd_fib_index = fib_index;
79 lkd->lkd_proto = proto;
80 lkd->lkd_input = input;
81 lkd->lkd_table = table_config;
84 * use the input type to select the lookup sub-type
90 case LOOKUP_INPUT_SRC_ADDR:
91 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC];
93 case LOOKUP_INPUT_DST_ADDR:
96 case LOOKUP_TABLE_FROM_INPUT_INTERFACE:
97 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE];
99 case LOOKUP_TABLE_FROM_CONFIG:
100 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST];
111 dpo_set(dpo, type, proto, lookup_dpo_get_index(lkd));
116 lookup_dpo_add_or_lock_w_fib_index (fib_node_index_t fib_index,
118 lookup_input_t input,
119 lookup_table_t table_config,
122 if (LOOKUP_TABLE_FROM_CONFIG == table_config)
124 fib_table_lock(fib_index, dpo_proto_to_fib(proto));
126 lookup_dpo_add_or_lock_i(fib_index, proto, input, table_config, dpo);
130 lookup_dpo_add_or_lock_w_table_id (u32 table_id,
132 lookup_input_t input,
133 lookup_table_t table_config,
136 fib_node_index_t fib_index = FIB_NODE_INDEX_INVALID;
138 if (LOOKUP_TABLE_FROM_CONFIG == table_config)
141 fib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
145 ASSERT(FIB_NODE_INDEX_INVALID != fib_index);
146 lookup_dpo_add_or_lock_i(fib_index, proto, input, table_config, dpo);
150 format_lookup_dpo (u8 *s, va_list *args)
152 index_t index = va_arg (*args, index_t);
155 lkd = lookup_dpo_get(index);
157 if (LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table)
159 s = format(s, "%s lookup in interface's %U table",
160 lookup_input_names[lkd->lkd_input],
161 format_dpo_proto, lkd->lkd_proto);
165 s = format(s, "%s lookup in %U",
166 lookup_input_names[lkd->lkd_input],
167 format_fib_table_name, lkd->lkd_fib_index,
168 dpo_proto_to_fib(lkd->lkd_proto));
174 lookup_dpo_lock (dpo_id_t *dpo)
178 lkd = lookup_dpo_get(dpo->dpoi_index);
184 lookup_dpo_unlock (dpo_id_t *dpo)
188 lkd = lookup_dpo_get(dpo->dpoi_index);
192 if (0 == lkd->lkd_locks)
194 if (LOOKUP_TABLE_FROM_CONFIG == lkd->lkd_table)
196 fib_table_unlock(lkd->lkd_fib_index,
197 dpo_proto_to_fib(lkd->lkd_proto));
199 pool_put(lookup_dpo_pool, lkd);
204 ip4_src_fib_lookup_one (u32 src_fib_index0,
205 const ip4_address_t * addr0,
206 u32 * src_adj_index0)
208 ip4_fib_mtrie_leaf_t leaf0, leaf1;
209 ip4_fib_mtrie_t * mtrie0;
211 mtrie0 = &ip4_fib_get (src_fib_index0)->mtrie;
213 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
214 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0);
215 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1);
216 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
217 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
219 /* Handle default route. */
220 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
221 src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
225 ip4_src_fib_lookup_two (u32 src_fib_index0,
227 const ip4_address_t * addr0,
228 const ip4_address_t * addr1,
229 u32 * src_adj_index0,
230 u32 * src_adj_index1)
232 ip4_fib_mtrie_leaf_t leaf0, leaf1;
233 ip4_fib_mtrie_t * mtrie0, * mtrie1;
235 mtrie0 = &ip4_fib_get (src_fib_index0)->mtrie;
236 mtrie1 = &ip4_fib_get (src_fib_index1)->mtrie;
238 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
240 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0);
241 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 0);
243 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1);
244 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 1);
246 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
247 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 2);
249 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
250 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 3);
252 /* Handle default route. */
253 leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
254 leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
255 src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
256 src_adj_index1[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
260 * @brief Lookup trace data
262 typedef struct lookup_trace_t_
266 mpls_unicast_header_t hdr;
268 fib_node_index_t fib_index;
274 lookup_dpo_ip4_inline (vlib_main_t * vm,
275 vlib_node_runtime_t * node,
276 vlib_frame_t * from_frame,
278 int table_from_interface)
280 u32 n_left_from, next_index, * from, * to_next;
281 u32 cpu_index = os_get_cpu_number();
282 vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
284 from = vlib_frame_vector_args (from_frame);
285 n_left_from = from_frame->n_vectors;
287 next_index = node->cached_next_index;
289 while (n_left_from > 0)
293 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
295 while (n_left_from >= 4 && n_left_to_next > 2)
297 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
298 flow_hash_config_t flow_hash_config0;
299 const ip4_address_t *input_addr0;
300 const load_balance_t *lb0;
301 const lookup_dpo_t * lkd0;
302 const ip4_header_t * ip0;
303 const dpo_id_t *dpo0;
305 u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
306 flow_hash_config_t flow_hash_config1;
307 const ip4_address_t *input_addr1;
308 const load_balance_t *lb1;
309 const lookup_dpo_t * lkd1;
310 const ip4_header_t * ip1;
311 const dpo_id_t *dpo1;
314 /* Prefetch next iteration. */
316 vlib_buffer_t * p2, * p3;
318 p2 = vlib_get_buffer (vm, from[2]);
319 p3 = vlib_get_buffer (vm, from[3]);
321 vlib_prefetch_buffer_header (p2, LOAD);
322 vlib_prefetch_buffer_header (p3, LOAD);
324 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
325 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
337 b0 = vlib_get_buffer (vm, bi0);
338 ip0 = vlib_buffer_get_current (b0);
339 b1 = vlib_get_buffer (vm, bi1);
340 ip1 = vlib_buffer_get_current (b1);
342 /* dst lookup was done by ip4 lookup */
343 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
344 lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
345 lkd0 = lookup_dpo_get(lkdi0);
346 lkd1 = lookup_dpo_get(lkdi1);
349 * choose between a lookup using the fib index in the DPO
350 * or getting the FIB index from the interface.
352 if (table_from_interface)
355 ip4_fib_table_get_index_for_sw_if_index(
356 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
358 ip4_fib_table_get_index_for_sw_if_index(
359 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
363 fib_index0 = lkd0->lkd_fib_index;
364 fib_index1 = lkd1->lkd_fib_index;
368 * choose between a source or destination address lookup in the table
372 input_addr0 = &ip0->src_address;
373 input_addr1 = &ip1->src_address;
377 input_addr0 = &ip0->dst_address;
378 input_addr1 = &ip1->dst_address;
382 ip4_src_fib_lookup_one (fib_index0, input_addr0, &lbi0);
383 ip4_src_fib_lookup_one (fib_index1, input_addr1, &lbi1);
384 lb0 = load_balance_get(lbi0);
385 lb1 = load_balance_get(lbi1);
387 /* Use flow hash to compute multipath adjacency. */
388 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
389 hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
391 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
393 flow_hash_config0 = lb0->lb_hash_config;
394 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
395 ip4_compute_flow_hash (ip0, flow_hash_config0);
398 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
400 flow_hash_config1 = lb1->lb_hash_config;
401 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
402 ip4_compute_flow_hash (ip1, flow_hash_config1);
405 dpo0 = load_balance_get_bucket_i(lb0,
407 (lb0->lb_n_buckets_minus_1)));
408 dpo1 = load_balance_get_bucket_i(lb1,
410 (lb1->lb_n_buckets_minus_1)));
412 next0 = dpo0->dpoi_next_node;
413 next1 = dpo1->dpoi_next_node;
414 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
415 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
417 vlib_increment_combined_counter
418 (cm, cpu_index, lbi0, 1,
419 vlib_buffer_length_in_chain (vm, b0));
420 vlib_increment_combined_counter
421 (cm, cpu_index, lbi1, 1,
422 vlib_buffer_length_in_chain (vm, b1));
424 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
426 lookup_trace_t *tr = vlib_add_trace (vm, node,
428 tr->fib_index = fib_index0;
430 tr->addr.ip4 = *input_addr0;
432 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
434 lookup_trace_t *tr = vlib_add_trace (vm, node,
436 tr->fib_index = fib_index1;
438 tr->addr.ip4 = *input_addr1;
441 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
442 to_next, n_left_to_next,
443 bi0, bi1, next0, next1);
446 while (n_left_from > 0 && n_left_to_next > 0)
448 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
449 flow_hash_config_t flow_hash_config0;
450 const ip4_address_t *input_addr;
451 const load_balance_t *lb0;
452 const lookup_dpo_t * lkd0;
453 const ip4_header_t * ip0;
454 const dpo_id_t *dpo0;
464 b0 = vlib_get_buffer (vm, bi0);
465 ip0 = vlib_buffer_get_current (b0);
467 /* dst lookup was done by ip4 lookup */
468 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
469 lkd0 = lookup_dpo_get(lkdi0);
472 * choose between a lookup using the fib index in the DPO
473 * or getting the FIB index from the interface.
475 if (table_from_interface)
478 ip4_fib_table_get_index_for_sw_if_index(
479 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
483 fib_index0 = lkd0->lkd_fib_index;
487 * choose between a source or destination address lookup in the table
491 input_addr = &ip0->src_address;
495 input_addr = &ip0->dst_address;
499 ip4_src_fib_lookup_one (fib_index0, input_addr, &lbi0);
500 lb0 = load_balance_get(lbi0);
502 /* Use flow hash to compute multipath adjacency. */
503 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
505 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
507 flow_hash_config0 = lb0->lb_hash_config;
508 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
509 ip4_compute_flow_hash (ip0, flow_hash_config0);
512 dpo0 = load_balance_get_bucket_i(lb0,
514 (lb0->lb_n_buckets_minus_1)));
516 next0 = dpo0->dpoi_next_node;
517 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
519 vlib_increment_combined_counter
520 (cm, cpu_index, lbi0, 1,
521 vlib_buffer_length_in_chain (vm, b0));
523 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
525 lookup_trace_t *tr = vlib_add_trace (vm, node,
527 tr->fib_index = fib_index0;
529 tr->addr.ip4 = *input_addr;
532 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
533 n_left_to_next, bi0, next0);
535 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
537 return from_frame->n_vectors;
541 format_lookup_trace (u8 * s, va_list * args)
543 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
544 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
545 lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
546 uword indent = format_get_indent (s);
547 s = format (s, "%U fib-index:%d addr:%U load-balance:%d",
548 format_white_space, indent,
550 format_ip46_address, &t->addr, IP46_TYPE_ANY,
556 lookup_ip4_dst (vlib_main_t * vm,
557 vlib_node_runtime_t * node,
558 vlib_frame_t * from_frame)
560 return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 0));
563 VLIB_REGISTER_NODE (lookup_ip4_dst_node) = {
564 .function = lookup_ip4_dst,
565 .name = "lookup-ip4-dst",
566 .vector_size = sizeof (u32),
567 .sibling_of = "ip4-lookup",
568 .format_trace = format_lookup_trace,
570 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_node, lookup_ip4_dst)
573 lookup_ip4_dst_itf (vlib_main_t * vm,
574 vlib_node_runtime_t * node,
575 vlib_frame_t * from_frame)
577 return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 1));
580 VLIB_REGISTER_NODE (lookup_ip4_dst_itf_node) = {
581 .function = lookup_ip4_dst_itf,
582 .name = "lookup-ip4-dst-itf",
583 .vector_size = sizeof (u32),
584 .sibling_of = "ip4-lookup",
585 .format_trace = format_lookup_trace,
587 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_itf_node, lookup_ip4_dst_itf)
590 lookup_ip4_src (vlib_main_t * vm,
591 vlib_node_runtime_t * node,
592 vlib_frame_t * from_frame)
594 return (lookup_dpo_ip4_inline(vm, node, from_frame, 1, 0));
597 VLIB_REGISTER_NODE (lookup_ip4_src_node) = {
598 .function = lookup_ip4_src,
599 .name = "lookup-ip4-src",
600 .vector_size = sizeof (u32),
601 .format_trace = format_lookup_trace,
602 .sibling_of = "ip4-lookup",
604 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_src_node, lookup_ip4_src)
607 lookup_dpo_ip6_inline (vlib_main_t * vm,
608 vlib_node_runtime_t * node,
609 vlib_frame_t * from_frame,
611 int table_from_interface)
613 vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
614 u32 n_left_from, next_index, * from, * to_next;
615 u32 cpu_index = os_get_cpu_number();
617 from = vlib_frame_vector_args (from_frame);
618 n_left_from = from_frame->n_vectors;
620 next_index = node->cached_next_index;
622 while (n_left_from > 0)
626 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
628 while (n_left_from >= 4 && n_left_to_next > 2)
630 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
631 flow_hash_config_t flow_hash_config0;
632 const ip6_address_t *input_addr0;
633 const load_balance_t *lb0;
634 const lookup_dpo_t * lkd0;
635 const ip6_header_t * ip0;
636 const dpo_id_t *dpo0;
638 u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
639 flow_hash_config_t flow_hash_config1;
640 const ip6_address_t *input_addr1;
641 const load_balance_t *lb1;
642 const lookup_dpo_t * lkd1;
643 const ip6_header_t * ip1;
644 const dpo_id_t *dpo1;
647 /* Prefetch next iteration. */
649 vlib_buffer_t * p2, * p3;
651 p2 = vlib_get_buffer (vm, from[2]);
652 p3 = vlib_get_buffer (vm, from[3]);
654 vlib_prefetch_buffer_header (p2, LOAD);
655 vlib_prefetch_buffer_header (p3, LOAD);
657 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
658 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
670 b0 = vlib_get_buffer (vm, bi0);
671 ip0 = vlib_buffer_get_current (b0);
672 b1 = vlib_get_buffer (vm, bi1);
673 ip1 = vlib_buffer_get_current (b1);
675 /* dst lookup was done by ip6 lookup */
676 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
677 lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
678 lkd0 = lookup_dpo_get(lkdi0);
679 lkd1 = lookup_dpo_get(lkdi1);
682 * choose between a lookup using the fib index in the DPO
683 * or getting the FIB index from the interface.
685 if (table_from_interface)
688 ip6_fib_table_get_index_for_sw_if_index(
689 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
691 ip6_fib_table_get_index_for_sw_if_index(
692 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
696 fib_index0 = lkd0->lkd_fib_index;
697 fib_index1 = lkd1->lkd_fib_index;
701 * choose between a source or destination address lookup in the table
705 input_addr0 = &ip0->src_address;
706 input_addr1 = &ip1->src_address;
710 input_addr0 = &ip0->dst_address;
711 input_addr1 = &ip1->dst_address;
715 lbi0 = ip6_fib_table_fwding_lookup(&ip6_main,
718 lbi1 = ip6_fib_table_fwding_lookup(&ip6_main,
721 lb0 = load_balance_get(lbi0);
722 lb1 = load_balance_get(lbi1);
724 /* Use flow hash to compute multipath adjacency. */
725 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
726 hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
728 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
730 flow_hash_config0 = lb0->lb_hash_config;
731 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
732 ip6_compute_flow_hash (ip0, flow_hash_config0);
735 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
737 flow_hash_config1 = lb1->lb_hash_config;
738 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
739 ip6_compute_flow_hash (ip1, flow_hash_config1);
742 dpo0 = load_balance_get_bucket_i(lb0,
744 (lb0->lb_n_buckets_minus_1)));
745 dpo1 = load_balance_get_bucket_i(lb1,
747 (lb1->lb_n_buckets_minus_1)));
749 next0 = dpo0->dpoi_next_node;
750 next1 = dpo1->dpoi_next_node;
751 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
752 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
754 vlib_increment_combined_counter
755 (cm, cpu_index, lbi0, 1,
756 vlib_buffer_length_in_chain (vm, b0));
757 vlib_increment_combined_counter
758 (cm, cpu_index, lbi1, 1,
759 vlib_buffer_length_in_chain (vm, b1));
761 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
763 lookup_trace_t *tr = vlib_add_trace (vm, node,
765 tr->fib_index = fib_index0;
767 tr->addr.ip6 = *input_addr0;
769 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
771 lookup_trace_t *tr = vlib_add_trace (vm, node,
773 tr->fib_index = fib_index1;
775 tr->addr.ip6 = *input_addr1;
777 vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
778 n_left_to_next, bi0, bi1,
781 while (n_left_from > 0 && n_left_to_next > 0)
783 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
784 flow_hash_config_t flow_hash_config0;
785 const ip6_address_t *input_addr0;
786 const load_balance_t *lb0;
787 const lookup_dpo_t * lkd0;
788 const ip6_header_t * ip0;
789 const dpo_id_t *dpo0;
799 b0 = vlib_get_buffer (vm, bi0);
800 ip0 = vlib_buffer_get_current (b0);
802 /* dst lookup was done by ip6 lookup */
803 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
804 lkd0 = lookup_dpo_get(lkdi0);
807 * choose between a lookup using the fib index in the DPO
808 * or getting the FIB index from the interface.
810 if (table_from_interface)
813 ip6_fib_table_get_index_for_sw_if_index(
814 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
818 fib_index0 = lkd0->lkd_fib_index;
822 * choose between a source or destination address lookup in the table
826 input_addr0 = &ip0->src_address;
830 input_addr0 = &ip0->dst_address;
834 lbi0 = ip6_fib_table_fwding_lookup(&ip6_main,
837 lb0 = load_balance_get(lbi0);
839 /* Use flow hash to compute multipath adjacency. */
840 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
842 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
844 flow_hash_config0 = lb0->lb_hash_config;
845 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
846 ip6_compute_flow_hash (ip0, flow_hash_config0);
849 dpo0 = load_balance_get_bucket_i(lb0,
851 (lb0->lb_n_buckets_minus_1)));
853 next0 = dpo0->dpoi_next_node;
854 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
856 vlib_increment_combined_counter
857 (cm, cpu_index, lbi0, 1,
858 vlib_buffer_length_in_chain (vm, b0));
860 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
862 lookup_trace_t *tr = vlib_add_trace (vm, node,
864 tr->fib_index = fib_index0;
866 tr->addr.ip6 = *input_addr0;
868 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
869 n_left_to_next, bi0, next0);
871 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
873 return from_frame->n_vectors;
877 lookup_ip6_dst (vlib_main_t * vm,
878 vlib_node_runtime_t * node,
879 vlib_frame_t * from_frame)
881 return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 0));
884 VLIB_REGISTER_NODE (lookup_ip6_dst_node) = {
885 .function = lookup_ip6_dst,
886 .name = "lookup-ip6-dst",
887 .vector_size = sizeof (u32),
888 .format_trace = format_lookup_trace,
889 .sibling_of = "ip6-lookup",
891 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_node, lookup_ip6_dst)
894 lookup_ip6_dst_itf (vlib_main_t * vm,
895 vlib_node_runtime_t * node,
896 vlib_frame_t * from_frame)
898 return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 1));
901 VLIB_REGISTER_NODE (lookup_ip6_dst_itf_node) = {
902 .function = lookup_ip6_dst_itf,
903 .name = "lookup-ip6-dst-itf",
904 .vector_size = sizeof (u32),
905 .format_trace = format_lookup_trace,
906 .sibling_of = "ip6-lookup",
908 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_itf_node, lookup_ip6_dst_itf)
911 lookup_ip6_src (vlib_main_t * vm,
912 vlib_node_runtime_t * node,
913 vlib_frame_t * from_frame)
915 return (lookup_dpo_ip6_inline(vm, node, from_frame, 1, 0));
918 VLIB_REGISTER_NODE (lookup_ip6_src_node) = {
919 .function = lookup_ip6_src,
920 .name = "lookup-ip6-src",
921 .vector_size = sizeof (u32),
922 .format_trace = format_lookup_trace,
923 .sibling_of = "ip6-lookup",
925 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_src_node, lookup_ip6_src)
928 lookup_dpo_mpls_inline (vlib_main_t * vm,
929 vlib_node_runtime_t * node,
930 vlib_frame_t * from_frame,
931 int table_from_interface)
933 u32 n_left_from, next_index, * from, * to_next;
934 u32 cpu_index = os_get_cpu_number();
935 vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
937 from = vlib_frame_vector_args (from_frame);
938 n_left_from = from_frame->n_vectors;
940 next_index = node->cached_next_index;
942 while (n_left_from > 0)
946 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
948 /* while (n_left_from >= 4 && n_left_to_next >= 2) */
951 while (n_left_from > 0 && n_left_to_next > 0)
953 u32 bi0, lkdi0, lbi0, fib_index0, next0;
954 const mpls_unicast_header_t * hdr0;
955 const load_balance_t *lb0;
956 const lookup_dpo_t * lkd0;
957 const dpo_id_t *dpo0;
967 b0 = vlib_get_buffer (vm, bi0);
968 hdr0 = vlib_buffer_get_current (b0);
970 /* dst lookup was done by mpls lookup */
971 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
972 lkd0 = lookup_dpo_get(lkdi0);
975 * choose between a lookup using the fib index in the DPO
976 * or getting the FIB index from the interface.
978 if (table_from_interface)
981 mpls_fib_table_get_index_for_sw_if_index(
982 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
986 fib_index0 = lkd0->lkd_fib_index;
990 lbi0 = mpls_fib_table_forwarding_lookup (fib_index0, hdr0);
991 lb0 = load_balance_get(lbi0);
992 dpo0 = load_balance_get_bucket_i(lb0, 0);
994 next0 = dpo0->dpoi_next_node;
995 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
997 vlib_increment_combined_counter
998 (cm, cpu_index, lbi0, 1,
999 vlib_buffer_length_in_chain (vm, b0));
1001 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1003 lookup_trace_t *tr = vlib_add_trace (vm, node,
1005 tr->fib_index = fib_index0;
1010 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
1011 n_left_to_next, bi0, next0);
1013 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1015 return from_frame->n_vectors;
1019 format_lookup_mpls_trace (u8 * s, va_list * args)
1021 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1022 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1023 lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
1024 uword indent = format_get_indent (s);
1025 mpls_unicast_header_t hdr;
1027 hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
1029 s = format (s, "%U fib-index:%d hdr:%U load-balance:%d",
1030 format_white_space, indent,
1032 format_mpls_header, hdr,
1038 lookup_mpls_dst (vlib_main_t * vm,
1039 vlib_node_runtime_t * node,
1040 vlib_frame_t * from_frame)
1042 return (lookup_dpo_mpls_inline(vm, node, from_frame, 0));
1045 VLIB_REGISTER_NODE (lookup_mpls_dst_node) = {
1046 .function = lookup_mpls_dst,
1047 .name = "lookup-mpls-dst",
1048 .vector_size = sizeof (u32),
1049 .sibling_of = "mpls-lookup",
1050 .format_trace = format_lookup_mpls_trace,
1053 VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_node, lookup_mpls_dst)
1056 lookup_mpls_dst_itf (vlib_main_t * vm,
1057 vlib_node_runtime_t * node,
1058 vlib_frame_t * from_frame)
1060 return (lookup_dpo_mpls_inline(vm, node, from_frame, 1));
1063 VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = {
1064 .function = lookup_mpls_dst_itf,
1065 .name = "lookup-mpls-dst-itf",
1066 .vector_size = sizeof (u32),
1067 .sibling_of = "mpls-lookup",
1068 .format_trace = format_lookup_mpls_trace,
1071 VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_itf_node, lookup_mpls_dst_itf)
1074 lookup_dpo_mem_show (void)
1076 fib_show_memory_usage("Lookup",
1077 pool_elts(lookup_dpo_pool),
1078 pool_len(lookup_dpo_pool),
1079 sizeof(lookup_dpo_t));
1082 const static dpo_vft_t lkd_vft = {
1083 .dv_lock = lookup_dpo_lock,
1084 .dv_unlock = lookup_dpo_unlock,
1085 .dv_format = format_lookup_dpo,
1087 const static dpo_vft_t lkd_vft_w_mem_show = {
1088 .dv_lock = lookup_dpo_lock,
1089 .dv_unlock = lookup_dpo_unlock,
1090 .dv_format = format_lookup_dpo,
1091 .dv_mem_show = lookup_dpo_mem_show,
1094 const static char* const lookup_src_ip4_nodes[] =
1099 const static char* const lookup_src_ip6_nodes[] =
1104 const static char* const * const lookup_src_nodes[DPO_PROTO_NUM] =
1106 [DPO_PROTO_IP4] = lookup_src_ip4_nodes,
1107 [DPO_PROTO_IP6] = lookup_src_ip6_nodes,
1108 [DPO_PROTO_MPLS] = NULL,
1111 const static char* const lookup_dst_ip4_nodes[] =
1116 const static char* const lookup_dst_ip6_nodes[] =
1121 const static char* const lookup_dst_mpls_nodes[] =
1126 const static char* const * const lookup_dst_nodes[DPO_PROTO_NUM] =
1128 [DPO_PROTO_IP4] = lookup_dst_ip4_nodes,
1129 [DPO_PROTO_IP6] = lookup_dst_ip6_nodes,
1130 [DPO_PROTO_MPLS] = lookup_dst_mpls_nodes,
1133 const static char* const lookup_dst_from_interface_ip4_nodes[] =
1135 "lookup-ip4-dst-itf",
1138 const static char* const lookup_dst_from_interface_ip6_nodes[] =
1140 "lookup-ip6-dst-itf",
1143 const static char* const lookup_dst_from_interface_mpls_nodes[] =
1145 "lookup-mpls-dst-itf",
1148 const static char* const * const lookup_dst_from_interface_nodes[DPO_PROTO_NUM] =
1150 [DPO_PROTO_IP4] = lookup_dst_from_interface_ip4_nodes,
1151 [DPO_PROTO_IP6] = lookup_dst_from_interface_ip6_nodes,
1152 [DPO_PROTO_MPLS] = lookup_dst_from_interface_mpls_nodes,
1157 lookup_dpo_module_init (void)
1159 dpo_register(DPO_LOOKUP, &lkd_vft_w_mem_show, NULL);
1162 * There are various sorts of lookup; src or dst addr v4 /v6 etc.
1163 * there isn't an object type for each (there is only the lookup_dpo_t),
1164 * but, for performance reasons, there is a data plane function, and hence
1165 * VLIB node for each. VLIB graph node construction is based on DPO types
1166 * so we create sub-types.
1168 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC] =
1169 dpo_register_new_type(&lkd_vft, lookup_src_nodes);
1170 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST] =
1171 dpo_register_new_type(&lkd_vft, lookup_dst_nodes);
1172 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE] =
1173 dpo_register_new_type(&lkd_vft, lookup_dst_from_interface_nodes);