Reorganize source tree to use single autotools instance
[vpp.git] / src / vnet / dpo / lookup_dpo.c
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/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>
24
25 static const char *const lookup_input_names[] = LOOKUP_INPUTS;
26
27 /**
28  * @brief Enumeration of the lookup subtypes
29  */
30 typedef enum lookup_sub_type_t_
31 {
32     LOOKUP_SUB_TYPE_SRC,
33     LOOKUP_SUB_TYPE_DST,
34     LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE,
35 } lookup_sub_type_t;
36 #define LOOKUP_SUB_TYPE_NUM (LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE+1)
37
38 #define FOR_EACH_LOOKUP_SUB_TYPE(_st)                                   \
39     for (_st = LOOKUP_SUB_TYPE_IP4_SRC; _st < LOOKUP_SUB_TYPE_NUM; _st++)
40
41 /**
42  * @brief pool of all MPLS Label DPOs
43  */
44 lookup_dpo_t *lookup_dpo_pool;
45
46 /**
47  * @brief An array of registered DPO type values for the sub-types
48  */
49 static dpo_type_t lookup_dpo_sub_types[LOOKUP_SUB_TYPE_NUM];
50
51 static lookup_dpo_t *
52 lookup_dpo_alloc (void)
53 {
54     lookup_dpo_t *lkd;
55
56     pool_get_aligned(lookup_dpo_pool, lkd, CLIB_CACHE_LINE_BYTES);
57
58     return (lkd);
59 }
60
61 static index_t
62 lookup_dpo_get_index (lookup_dpo_t *lkd)
63 {
64     return (lkd - lookup_dpo_pool);
65 }
66
67 static void
68 lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
69                           dpo_proto_t proto,
70                           lookup_input_t input,
71                           lookup_table_t table_config,
72                           dpo_id_t *dpo)
73 {
74     lookup_dpo_t *lkd;
75     dpo_type_t type;
76
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;
82
83     /*
84      * use the input type to select the lookup sub-type
85      */
86     type = 0;
87
88     switch (input)
89     {
90     case LOOKUP_INPUT_SRC_ADDR:
91         type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC];
92         break;
93     case LOOKUP_INPUT_DST_ADDR:
94         switch (table_config)
95         {
96         case LOOKUP_TABLE_FROM_INPUT_INTERFACE:
97             type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE];
98             break;
99         case LOOKUP_TABLE_FROM_CONFIG:
100             type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST];
101             break;
102         }
103     }
104
105     if (0 == type)
106     {
107         dpo_reset(dpo);
108     }
109     else
110     {
111         dpo_set(dpo, type, proto, lookup_dpo_get_index(lkd));
112     }
113 }
114
115 void
116 lookup_dpo_add_or_lock_w_fib_index (fib_node_index_t fib_index,
117                                     dpo_proto_t proto,
118                                     lookup_input_t input,
119                                     lookup_table_t table_config,
120                                     dpo_id_t *dpo)
121 {
122     if (LOOKUP_TABLE_FROM_CONFIG == table_config)
123     {
124         fib_table_lock(fib_index, dpo_proto_to_fib(proto));
125     }
126     lookup_dpo_add_or_lock_i(fib_index, proto, input, table_config, dpo);
127 }
128
129 void
130 lookup_dpo_add_or_lock_w_table_id (u32 table_id,
131                                    dpo_proto_t proto,
132                                    lookup_input_t input,
133                                    lookup_table_t table_config,
134                                    dpo_id_t *dpo)
135 {
136     fib_node_index_t fib_index = FIB_NODE_INDEX_INVALID;
137
138     if (LOOKUP_TABLE_FROM_CONFIG == table_config)
139     {
140         fib_index =
141             fib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
142                                               table_id);
143     }
144
145     ASSERT(FIB_NODE_INDEX_INVALID != fib_index);
146     lookup_dpo_add_or_lock_i(fib_index, proto, input, table_config, dpo);    
147 }
148
149 u8*
150 format_lookup_dpo (u8 *s, va_list *args)
151 {
152     index_t index = va_arg (*args, index_t);
153     lookup_dpo_t *lkd;
154
155     lkd = lookup_dpo_get(index);
156
157     if (LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table)
158     {
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);
162     }
163     else
164     {
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));
169     }
170     return (s);
171 }
172
173 static void
174 lookup_dpo_lock (dpo_id_t *dpo)
175 {
176     lookup_dpo_t *lkd;
177
178     lkd = lookup_dpo_get(dpo->dpoi_index);
179
180     lkd->lkd_locks++;
181 }
182
183 static void
184 lookup_dpo_unlock (dpo_id_t *dpo)
185 {
186     lookup_dpo_t *lkd;
187
188     lkd = lookup_dpo_get(dpo->dpoi_index);
189
190     lkd->lkd_locks--;
191
192     if (0 == lkd->lkd_locks)
193     {
194         if (LOOKUP_TABLE_FROM_CONFIG == lkd->lkd_table)
195         {
196             fib_table_unlock(lkd->lkd_fib_index,
197                              dpo_proto_to_fib(lkd->lkd_proto));
198         }
199         pool_put(lookup_dpo_pool, lkd);
200     }
201 }
202
203 always_inline void
204 ip4_src_fib_lookup_one (u32 src_fib_index0,
205                         const ip4_address_t * addr0,
206                         u32 * src_adj_index0)
207 {
208     ip4_fib_mtrie_leaf_t leaf0, leaf1;
209     ip4_fib_mtrie_t * mtrie0;
210
211     mtrie0 = &ip4_fib_get (src_fib_index0)->mtrie;
212
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);
218
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);
222 }
223
224 always_inline void
225 ip4_src_fib_lookup_two (u32 src_fib_index0,
226                         u32 src_fib_index1,
227                         const ip4_address_t * addr0,
228                         const ip4_address_t * addr1,
229                         u32 * src_adj_index0,
230                         u32 * src_adj_index1)
231 {
232     ip4_fib_mtrie_leaf_t leaf0, leaf1;
233     ip4_fib_mtrie_t * mtrie0, * mtrie1;
234
235     mtrie0 = &ip4_fib_get (src_fib_index0)->mtrie;
236     mtrie1 = &ip4_fib_get (src_fib_index1)->mtrie;
237
238     leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
239
240     leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0);
241     leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 0);
242
243     leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1);
244     leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 1);
245
246     leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
247     leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 2);
248
249     leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
250     leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 3);
251
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);
257 }
258
259 /**
260  * @brief Lookup trace  data
261  */
262 typedef struct lookup_trace_t_
263 {
264     union {
265         ip46_address_t addr;
266         mpls_unicast_header_t hdr;
267     };
268     fib_node_index_t fib_index;
269     index_t lbi;
270 } lookup_trace_t;
271
272
273 always_inline uword
274 lookup_dpo_ip4_inline (vlib_main_t * vm,
275                        vlib_node_runtime_t * node,
276                        vlib_frame_t * from_frame,
277                        int input_src_addr,
278                        int table_from_interface)
279 {
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;
283
284     from = vlib_frame_vector_args (from_frame);
285     n_left_from = from_frame->n_vectors;
286
287     next_index = node->cached_next_index;
288
289     while (n_left_from > 0)
290     {
291         u32 n_left_to_next;
292
293         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
294
295         while (n_left_from >= 4 && n_left_to_next > 2)
296         {
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;
304             vlib_buffer_t * b0;
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;
312             vlib_buffer_t * b1;
313
314             /* Prefetch next iteration. */
315             {
316                 vlib_buffer_t * p2, * p3;
317
318                 p2 = vlib_get_buffer (vm, from[2]);
319                 p3 = vlib_get_buffer (vm, from[3]);
320
321                 vlib_prefetch_buffer_header (p2, LOAD);
322                 vlib_prefetch_buffer_header (p3, LOAD);
323
324                 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
325                 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
326             }
327
328             bi0 = from[0];
329             to_next[0] = bi0;
330             bi1 = from[1];
331             to_next[1] = bi1;
332             from += 2;
333             to_next += 2;
334             n_left_from -= 2;
335             n_left_to_next -= 2;
336
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);
341
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);
347
348             /*
349              * choose between a lookup using the fib index in the DPO
350              * or getting the FIB index from the interface.
351              */
352             if (table_from_interface)
353             {
354                 fib_index0 =
355                     ip4_fib_table_get_index_for_sw_if_index(
356                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
357                 fib_index1 =
358                     ip4_fib_table_get_index_for_sw_if_index(
359                         vnet_buffer(b1)->sw_if_index[VLIB_RX]);
360             }
361             else
362             {
363                 fib_index0 = lkd0->lkd_fib_index;
364                 fib_index1 = lkd1->lkd_fib_index;
365             }
366
367             /*
368              * choose between a source or destination address lookup in the table
369              */
370             if (input_src_addr)
371             {
372                 input_addr0 = &ip0->src_address;
373                 input_addr1 = &ip1->src_address;
374             }
375             else
376             {
377                 input_addr0 = &ip0->dst_address;
378                 input_addr1 = &ip1->dst_address;
379             }
380
381             /* do lookup */
382             ip4_src_fib_lookup_two (fib_index0, fib_index1,
383                                     input_addr0, input_addr1,
384                                     &lbi0, &lbi1);
385             lb0 = load_balance_get(lbi0);
386             lb1 = load_balance_get(lbi1);
387
388             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
389             vnet_buffer(b1)->sw_if_index[VLIB_TX] = fib_index1;
390
391             /* Use flow hash to compute multipath adjacency. */
392             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
393             hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
394
395             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
396             {
397                 flow_hash_config0 = lb0->lb_hash_config;
398                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
399                     ip4_compute_flow_hash (ip0, flow_hash_config0);
400             }
401
402             if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
403             {
404                 flow_hash_config1 = lb1->lb_hash_config;
405                 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
406                     ip4_compute_flow_hash (ip1, flow_hash_config1);
407             }
408
409             dpo0 = load_balance_get_bucket_i(lb0,
410                                              (hash_c0 &
411                                               (lb0->lb_n_buckets_minus_1)));
412             dpo1 = load_balance_get_bucket_i(lb1,
413                                              (hash_c1 &
414                                               (lb1->lb_n_buckets_minus_1)));
415
416             next0 = dpo0->dpoi_next_node;
417             next1 = dpo1->dpoi_next_node;
418             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
419             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
420
421             vlib_increment_combined_counter
422                 (cm, cpu_index, lbi0, 1,
423                  vlib_buffer_length_in_chain (vm, b0));
424             vlib_increment_combined_counter
425                 (cm, cpu_index, lbi1, 1,
426                  vlib_buffer_length_in_chain (vm, b1));
427
428             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
429             {
430                 lookup_trace_t *tr = vlib_add_trace (vm, node,
431                                                      b0, sizeof (*tr));
432                 tr->fib_index = fib_index0;
433                 tr->lbi = lbi0;
434                 tr->addr.ip4 = *input_addr0;
435             }
436             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
437             {
438                 lookup_trace_t *tr = vlib_add_trace (vm, node,
439                                                      b1, sizeof (*tr));
440                 tr->fib_index = fib_index1;
441                 tr->lbi = lbi1;
442                 tr->addr.ip4 = *input_addr1;
443             }
444
445             vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
446                                              to_next, n_left_to_next,
447                                              bi0, bi1, next0, next1);
448         }
449
450         while (n_left_from > 0 && n_left_to_next > 0)
451         {
452             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
453             flow_hash_config_t flow_hash_config0;
454             const ip4_address_t *input_addr;
455             const load_balance_t *lb0;
456             const lookup_dpo_t * lkd0;
457             const ip4_header_t * ip0;
458             const dpo_id_t *dpo0;
459             vlib_buffer_t * b0;
460
461             bi0 = from[0];
462             to_next[0] = bi0;
463             from += 1;
464             to_next += 1;
465             n_left_from -= 1;
466             n_left_to_next -= 1;
467
468             b0 = vlib_get_buffer (vm, bi0);
469             ip0 = vlib_buffer_get_current (b0);
470
471             /* dst lookup was done by ip4 lookup */
472             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
473             lkd0 = lookup_dpo_get(lkdi0);
474
475             /*
476              * choose between a lookup using the fib index in the DPO
477              * or getting the FIB index from the interface.
478              */
479             if (table_from_interface)
480             {
481                 fib_index0 =
482                     ip4_fib_table_get_index_for_sw_if_index(
483                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
484             }
485             else
486             {
487                 fib_index0 = lkd0->lkd_fib_index;
488             }
489
490             /*
491              * choose between a source or destination address lookup in the table
492              */
493             if (input_src_addr)
494             {
495                 input_addr = &ip0->src_address;
496             }
497             else
498             {
499                 input_addr = &ip0->dst_address;
500             }
501
502             /* do lookup */
503             ip4_src_fib_lookup_one (fib_index0, input_addr, &lbi0);
504             lb0 = load_balance_get(lbi0);
505
506             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
507
508             /* Use flow hash to compute multipath adjacency. */
509             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
510
511             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
512             {
513                 flow_hash_config0 = lb0->lb_hash_config;
514                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
515                     ip4_compute_flow_hash (ip0, flow_hash_config0);
516             }
517
518             dpo0 = load_balance_get_bucket_i(lb0,
519                                              (hash_c0 &
520                                               (lb0->lb_n_buckets_minus_1)));
521
522             next0 = dpo0->dpoi_next_node;
523             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
524
525             vlib_increment_combined_counter
526                 (cm, cpu_index, lbi0, 1,
527                  vlib_buffer_length_in_chain (vm, b0));
528
529             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
530             {
531                 lookup_trace_t *tr = vlib_add_trace (vm, node,
532                                                      b0, sizeof (*tr));
533                 tr->fib_index = fib_index0;
534                 tr->lbi = lbi0;
535                 tr->addr.ip4 = *input_addr;
536             }
537
538             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
539                                             n_left_to_next, bi0, next0);
540         }
541         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
542     }
543     return from_frame->n_vectors;
544 }
545
546 static u8 *
547 format_lookup_trace (u8 * s, va_list * args)
548 {
549     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
550     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
551     lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
552     uword indent = format_get_indent (s);
553     s = format (s, "%U fib-index:%d addr:%U load-balance:%d",
554                 format_white_space, indent,
555                 t->fib_index,
556                 format_ip46_address, &t->addr, IP46_TYPE_ANY,
557                 t->lbi);
558     return s;
559 }
560
561 always_inline uword
562 lookup_ip4_dst (vlib_main_t * vm,
563                 vlib_node_runtime_t * node,
564                 vlib_frame_t * from_frame)
565 {
566     return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 0));
567 }
568
569 VLIB_REGISTER_NODE (lookup_ip4_dst_node) = {
570     .function = lookup_ip4_dst,
571     .name = "lookup-ip4-dst",
572     .vector_size = sizeof (u32),
573     .sibling_of = "ip4-lookup",
574     .format_trace = format_lookup_trace,
575 };
576 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_node, lookup_ip4_dst)
577
578 always_inline uword
579 lookup_ip4_dst_itf (vlib_main_t * vm,
580                     vlib_node_runtime_t * node,
581                     vlib_frame_t * from_frame)
582 {
583     return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 1));
584 }
585
586 VLIB_REGISTER_NODE (lookup_ip4_dst_itf_node) = {
587     .function = lookup_ip4_dst_itf,
588     .name = "lookup-ip4-dst-itf",
589     .vector_size = sizeof (u32),
590     .sibling_of = "ip4-lookup",
591     .format_trace = format_lookup_trace,
592 };
593 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_itf_node, lookup_ip4_dst_itf)
594
595 always_inline uword
596 lookup_ip4_src (vlib_main_t * vm,
597                 vlib_node_runtime_t * node,
598                 vlib_frame_t * from_frame)
599 {
600     return (lookup_dpo_ip4_inline(vm, node, from_frame, 1, 0));
601 }
602
603 VLIB_REGISTER_NODE (lookup_ip4_src_node) = {
604     .function = lookup_ip4_src,
605     .name = "lookup-ip4-src",
606     .vector_size = sizeof (u32),
607     .format_trace = format_lookup_trace,
608     .sibling_of = "ip4-lookup",
609 };
610 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_src_node, lookup_ip4_src)
611
612 always_inline uword
613 lookup_dpo_ip6_inline (vlib_main_t * vm,
614                        vlib_node_runtime_t * node,
615                        vlib_frame_t * from_frame,
616                        int input_src_addr,
617                        int table_from_interface)
618 {
619     vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
620     u32 n_left_from, next_index, * from, * to_next;
621     u32 cpu_index = os_get_cpu_number();
622
623     from = vlib_frame_vector_args (from_frame);
624     n_left_from = from_frame->n_vectors;
625
626     next_index = node->cached_next_index;
627
628     while (n_left_from > 0)
629     {
630         u32 n_left_to_next;
631
632         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
633
634         while (n_left_from >= 4 && n_left_to_next > 2)
635         {
636             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
637             flow_hash_config_t flow_hash_config0;
638             const ip6_address_t *input_addr0;
639             const load_balance_t *lb0;
640             const lookup_dpo_t * lkd0;
641             const ip6_header_t * ip0;
642             const dpo_id_t *dpo0;
643             vlib_buffer_t * b0;
644             u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
645             flow_hash_config_t flow_hash_config1;
646             const ip6_address_t *input_addr1;
647             const load_balance_t *lb1;
648             const lookup_dpo_t * lkd1;
649             const ip6_header_t * ip1;
650             const dpo_id_t *dpo1;
651             vlib_buffer_t * b1;
652
653             /* Prefetch next iteration. */
654             {
655                 vlib_buffer_t * p2, * p3;
656
657                 p2 = vlib_get_buffer (vm, from[2]);
658                 p3 = vlib_get_buffer (vm, from[3]);
659
660                 vlib_prefetch_buffer_header (p2, LOAD);
661                 vlib_prefetch_buffer_header (p3, LOAD);
662
663                 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
664                 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
665             }
666
667             bi0 = from[0];
668             to_next[0] = bi0;
669             bi1 = from[1];
670             to_next[1] = bi1;
671             from += 2;
672             to_next += 2;
673             n_left_from -= 2;
674             n_left_to_next -= 2;
675
676             b0 = vlib_get_buffer (vm, bi0);
677             ip0 = vlib_buffer_get_current (b0);
678             b1 = vlib_get_buffer (vm, bi1);
679             ip1 = vlib_buffer_get_current (b1);
680
681             /* dst lookup was done by ip6 lookup */
682             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
683             lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
684             lkd0 = lookup_dpo_get(lkdi0);
685             lkd1 = lookup_dpo_get(lkdi1);
686
687             /*
688              * choose between a lookup using the fib index in the DPO
689              * or getting the FIB index from the interface.
690              */
691             if (table_from_interface)
692             {
693                 fib_index0 =
694                     ip6_fib_table_get_index_for_sw_if_index(
695                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
696                 fib_index1 =
697                     ip6_fib_table_get_index_for_sw_if_index(
698                         vnet_buffer(b1)->sw_if_index[VLIB_RX]);
699             }
700             else
701             {
702                 fib_index0 = lkd0->lkd_fib_index;
703                 fib_index1 = lkd1->lkd_fib_index;
704             }
705
706             /*
707              * choose between a source or destination address lookup in the table
708              */
709             if (input_src_addr)
710             {
711                 input_addr0 = &ip0->src_address;
712                 input_addr1 = &ip1->src_address;
713             }
714             else
715             {
716                 input_addr0 = &ip0->dst_address;
717                 input_addr1 = &ip1->dst_address;
718             }
719
720             /* do src lookup */
721             lbi0 = ip6_fib_table_fwding_lookup(&ip6_main,
722                                                fib_index0,
723                                                input_addr0);
724             lbi1 = ip6_fib_table_fwding_lookup(&ip6_main,
725                                                fib_index1,
726                                                input_addr1);
727             lb0 = load_balance_get(lbi0);
728             lb1 = load_balance_get(lbi1);
729
730             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
731             vnet_buffer(b1)->sw_if_index[VLIB_TX] = fib_index1;
732
733             /* Use flow hash to compute multipath adjacency. */
734             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
735             hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
736
737             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
738             {
739                 flow_hash_config0 = lb0->lb_hash_config;
740                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
741                     ip6_compute_flow_hash (ip0, flow_hash_config0);
742             }
743
744             if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
745             {
746                 flow_hash_config1 = lb1->lb_hash_config;
747                 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
748                     ip6_compute_flow_hash (ip1, flow_hash_config1);
749             }
750
751             dpo0 = load_balance_get_bucket_i(lb0,
752                                              (hash_c0 &
753                                               (lb0->lb_n_buckets_minus_1)));
754             dpo1 = load_balance_get_bucket_i(lb1,
755                                              (hash_c1 &
756                                               (lb1->lb_n_buckets_minus_1)));
757
758             next0 = dpo0->dpoi_next_node;
759             next1 = dpo1->dpoi_next_node;
760             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
761             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
762
763             vlib_increment_combined_counter
764                 (cm, cpu_index, lbi0, 1,
765                  vlib_buffer_length_in_chain (vm, b0));
766             vlib_increment_combined_counter
767                 (cm, cpu_index, lbi1, 1,
768                  vlib_buffer_length_in_chain (vm, b1));
769
770             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
771             {
772                 lookup_trace_t *tr = vlib_add_trace (vm, node,
773                                                      b0, sizeof (*tr));
774                 tr->fib_index = fib_index0;
775                 tr->lbi = lbi0;
776                 tr->addr.ip6 = *input_addr0;
777             }
778             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
779             {
780                 lookup_trace_t *tr = vlib_add_trace (vm, node,
781                                                      b1, sizeof (*tr));
782                 tr->fib_index = fib_index1;
783                 tr->lbi = lbi1;
784                 tr->addr.ip6 = *input_addr1;
785             }
786             vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
787                                             n_left_to_next, bi0, bi1,
788                                             next0, next1);
789         }
790         while (n_left_from > 0 && n_left_to_next > 0)
791         {
792             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
793             flow_hash_config_t flow_hash_config0;
794             const ip6_address_t *input_addr0;
795             const load_balance_t *lb0;
796             const lookup_dpo_t * lkd0;
797             const ip6_header_t * ip0;
798             const dpo_id_t *dpo0;
799             vlib_buffer_t * b0;
800
801             bi0 = from[0];
802             to_next[0] = bi0;
803             from += 1;
804             to_next += 1;
805             n_left_from -= 1;
806             n_left_to_next -= 1;
807
808             b0 = vlib_get_buffer (vm, bi0);
809             ip0 = vlib_buffer_get_current (b0);
810
811             /* dst lookup was done by ip6 lookup */
812             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
813             lkd0 = lookup_dpo_get(lkdi0);
814
815             /*
816              * choose between a lookup using the fib index in the DPO
817              * or getting the FIB index from the interface.
818              */
819             if (table_from_interface)
820             {
821                 fib_index0 =
822                     ip6_fib_table_get_index_for_sw_if_index(
823                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
824             }
825             else
826             {
827                 fib_index0 = lkd0->lkd_fib_index;
828             }
829
830             /*
831              * choose between a source or destination address lookup in the table
832              */
833             if (input_src_addr)
834             {
835                 input_addr0 = &ip0->src_address;
836             }
837             else
838             {
839                 input_addr0 = &ip0->dst_address;
840             }
841
842             /* do src lookup */
843             lbi0 = ip6_fib_table_fwding_lookup(&ip6_main,
844                                                fib_index0,
845                                                input_addr0);
846             lb0 = load_balance_get(lbi0);
847
848             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
849
850             /* Use flow hash to compute multipath adjacency. */
851             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
852
853             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
854             {
855                 flow_hash_config0 = lb0->lb_hash_config;
856                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
857                     ip6_compute_flow_hash (ip0, flow_hash_config0);
858             }
859
860             dpo0 = load_balance_get_bucket_i(lb0,
861                                              (hash_c0 &
862                                               (lb0->lb_n_buckets_minus_1)));
863
864             next0 = dpo0->dpoi_next_node;
865             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
866
867             vlib_increment_combined_counter
868                 (cm, cpu_index, lbi0, 1,
869                  vlib_buffer_length_in_chain (vm, b0));
870
871             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
872             {
873                 lookup_trace_t *tr = vlib_add_trace (vm, node,
874                                                      b0, sizeof (*tr));
875                 tr->fib_index = fib_index0;
876                 tr->lbi = lbi0;
877                 tr->addr.ip6 = *input_addr0;
878             }
879             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
880                                             n_left_to_next, bi0, next0);
881         }
882         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
883     }
884     return from_frame->n_vectors;
885 }
886
887 always_inline uword
888 lookup_ip6_dst (vlib_main_t * vm,
889                 vlib_node_runtime_t * node,
890                 vlib_frame_t * from_frame)
891 {
892     return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 0));
893 }
894
895 VLIB_REGISTER_NODE (lookup_ip6_dst_node) = {
896     .function = lookup_ip6_dst,
897     .name = "lookup-ip6-dst",
898     .vector_size = sizeof (u32),
899     .format_trace = format_lookup_trace,
900     .sibling_of = "ip6-lookup",
901 };
902 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_node, lookup_ip6_dst)
903
904 always_inline uword
905 lookup_ip6_dst_itf (vlib_main_t * vm,
906                     vlib_node_runtime_t * node,
907                     vlib_frame_t * from_frame)
908 {
909     return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 1));
910 }
911
912 VLIB_REGISTER_NODE (lookup_ip6_dst_itf_node) = {
913     .function = lookup_ip6_dst_itf,
914     .name = "lookup-ip6-dst-itf",
915     .vector_size = sizeof (u32),
916     .format_trace = format_lookup_trace,
917     .sibling_of = "ip6-lookup",
918 };
919 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_itf_node, lookup_ip6_dst_itf)
920
921 always_inline uword
922 lookup_ip6_src (vlib_main_t * vm,
923                 vlib_node_runtime_t * node,
924                 vlib_frame_t * from_frame)
925 {
926     return (lookup_dpo_ip6_inline(vm, node, from_frame, 1, 0));
927 }
928
929 VLIB_REGISTER_NODE (lookup_ip6_src_node) = {
930     .function = lookup_ip6_src,
931     .name = "lookup-ip6-src",
932     .vector_size = sizeof (u32),
933     .format_trace = format_lookup_trace,
934     .sibling_of = "ip6-lookup",
935 };
936 VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_src_node, lookup_ip6_src)
937
938 always_inline uword
939 lookup_dpo_mpls_inline (vlib_main_t * vm,
940                        vlib_node_runtime_t * node,
941                        vlib_frame_t * from_frame,
942                        int table_from_interface)
943 {
944     u32 n_left_from, next_index, * from, * to_next;
945     u32 cpu_index = os_get_cpu_number();
946     vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
947
948     from = vlib_frame_vector_args (from_frame);
949     n_left_from = from_frame->n_vectors;
950
951     next_index = node->cached_next_index;
952
953     while (n_left_from > 0)
954     {
955         u32 n_left_to_next;
956
957         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
958
959         /* while (n_left_from >= 4 && n_left_to_next >= 2) */
960         /*   } */
961
962         while (n_left_from > 0 && n_left_to_next > 0)
963         {
964             u32 bi0, lkdi0, lbi0, fib_index0,  next0;
965             const mpls_unicast_header_t * hdr0;
966             const load_balance_t *lb0;
967             const lookup_dpo_t * lkd0;
968             const dpo_id_t *dpo0;
969             vlib_buffer_t * b0;
970
971             bi0 = from[0];
972             to_next[0] = bi0;
973             from += 1;
974             to_next += 1;
975             n_left_from -= 1;
976             n_left_to_next -= 1;
977
978             b0 = vlib_get_buffer (vm, bi0);
979             hdr0 = vlib_buffer_get_current (b0);
980
981             /* dst lookup was done by mpls lookup */
982             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
983             lkd0 = lookup_dpo_get(lkdi0);
984
985             /*
986              * choose between a lookup using the fib index in the DPO
987              * or getting the FIB index from the interface.
988              */
989             if (table_from_interface)
990             {
991                 fib_index0 = 
992                     mpls_fib_table_get_index_for_sw_if_index(
993                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
994             }
995             else
996             {
997                 fib_index0 = lkd0->lkd_fib_index;
998             }
999
1000             /* do lookup */
1001             lbi0 = mpls_fib_table_forwarding_lookup (fib_index0, hdr0);
1002             lb0  = load_balance_get(lbi0);
1003             dpo0 = load_balance_get_bucket_i(lb0, 0);
1004
1005             next0 = dpo0->dpoi_next_node;
1006             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
1007
1008             vlib_increment_combined_counter
1009                 (cm, cpu_index, lbi0, 1,
1010                  vlib_buffer_length_in_chain (vm, b0));
1011
1012             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
1013             {
1014                 lookup_trace_t *tr = vlib_add_trace (vm, node, 
1015                                                      b0, sizeof (*tr));
1016                 tr->fib_index = fib_index0;
1017                 tr->lbi = lbi0;
1018                 tr->hdr = *hdr0;
1019             }
1020
1021            vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
1022                                             n_left_to_next, bi0, next0);
1023         }
1024         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1025     }
1026     return from_frame->n_vectors;
1027 }
1028
1029 static u8 *
1030 format_lookup_mpls_trace (u8 * s, va_list * args)
1031 {
1032     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1033     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1034     lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
1035     uword indent = format_get_indent (s);
1036     mpls_unicast_header_t hdr;
1037
1038     hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
1039
1040     s = format (s, "%U fib-index:%d hdr:%U load-balance:%d",
1041                 format_white_space, indent,
1042                 t->fib_index,
1043                 format_mpls_header, hdr,
1044                 t->lbi);
1045     return s;
1046 }
1047
1048 always_inline uword
1049 lookup_mpls_dst (vlib_main_t * vm,
1050                 vlib_node_runtime_t * node,
1051                 vlib_frame_t * from_frame)
1052 {
1053     return (lookup_dpo_mpls_inline(vm, node, from_frame, 0));
1054 }
1055
1056 VLIB_REGISTER_NODE (lookup_mpls_dst_node) = {
1057     .function = lookup_mpls_dst,
1058     .name = "lookup-mpls-dst",
1059     .vector_size = sizeof (u32),
1060     .sibling_of = "mpls-lookup",
1061     .format_trace = format_lookup_mpls_trace,
1062     .n_next_nodes = 0,
1063 };
1064 VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_node, lookup_mpls_dst)
1065
1066 always_inline uword
1067 lookup_mpls_dst_itf (vlib_main_t * vm,
1068                     vlib_node_runtime_t * node,
1069                     vlib_frame_t * from_frame)
1070 {
1071     return (lookup_dpo_mpls_inline(vm, node, from_frame, 1));
1072 }
1073
1074 VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = {
1075     .function = lookup_mpls_dst_itf,
1076     .name = "lookup-mpls-dst-itf",
1077     .vector_size = sizeof (u32),
1078     .sibling_of = "mpls-lookup",
1079     .format_trace = format_lookup_mpls_trace,
1080     .n_next_nodes = 0,
1081 };
1082 VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_itf_node, lookup_mpls_dst_itf)
1083
1084 static void
1085 lookup_dpo_mem_show (void)
1086 {
1087     fib_show_memory_usage("Lookup",
1088                           pool_elts(lookup_dpo_pool),
1089                           pool_len(lookup_dpo_pool),
1090                           sizeof(lookup_dpo_t));
1091 }
1092
1093 const static dpo_vft_t lkd_vft = {
1094     .dv_lock = lookup_dpo_lock,
1095     .dv_unlock = lookup_dpo_unlock,
1096     .dv_format = format_lookup_dpo,
1097 };
1098 const static dpo_vft_t lkd_vft_w_mem_show = {
1099     .dv_lock = lookup_dpo_lock,
1100     .dv_unlock = lookup_dpo_unlock,
1101     .dv_format = format_lookup_dpo,
1102     .dv_mem_show = lookup_dpo_mem_show,
1103 };
1104
1105 const static char* const lookup_src_ip4_nodes[] =
1106 {
1107     "lookup-ip4-src",
1108     NULL,
1109 };
1110 const static char* const lookup_src_ip6_nodes[] =
1111 {
1112     "lookup-ip6-src",
1113     NULL,
1114 };
1115 const static char* const * const lookup_src_nodes[DPO_PROTO_NUM] =
1116 {
1117     [DPO_PROTO_IP4]  = lookup_src_ip4_nodes,
1118     [DPO_PROTO_IP6]  = lookup_src_ip6_nodes,
1119     [DPO_PROTO_MPLS] = NULL,
1120 };
1121
1122 const static char* const lookup_dst_ip4_nodes[] =
1123 {
1124     "lookup-ip4-dst",
1125     NULL,
1126 };
1127 const static char* const lookup_dst_ip6_nodes[] =
1128 {
1129     "lookup-ip6-dst",
1130     NULL,
1131 };
1132 const static char* const lookup_dst_mpls_nodes[] =
1133 {
1134     "lookup-mpls-dst",
1135     NULL,
1136 };
1137 const static char* const * const lookup_dst_nodes[DPO_PROTO_NUM] =
1138 {
1139     [DPO_PROTO_IP4]  = lookup_dst_ip4_nodes,
1140     [DPO_PROTO_IP6]  = lookup_dst_ip6_nodes,
1141     [DPO_PROTO_MPLS] = lookup_dst_mpls_nodes,
1142 };
1143
1144 const static char* const lookup_dst_from_interface_ip4_nodes[] =
1145 {
1146     "lookup-ip4-dst-itf",
1147     NULL,
1148 };
1149 const static char* const lookup_dst_from_interface_ip6_nodes[] =
1150 {
1151     "lookup-ip6-dst-itf",
1152     NULL,
1153 };
1154 const static char* const lookup_dst_from_interface_mpls_nodes[] =
1155 {
1156     "lookup-mpls-dst-itf",
1157     NULL,
1158 };
1159 const static char* const * const lookup_dst_from_interface_nodes[DPO_PROTO_NUM] =
1160 {
1161     [DPO_PROTO_IP4]  = lookup_dst_from_interface_ip4_nodes,
1162     [DPO_PROTO_IP6]  = lookup_dst_from_interface_ip6_nodes,
1163     [DPO_PROTO_MPLS] = lookup_dst_from_interface_mpls_nodes,
1164 };
1165
1166
1167 void
1168 lookup_dpo_module_init (void)
1169 {
1170     dpo_register(DPO_LOOKUP, &lkd_vft_w_mem_show, NULL);
1171
1172     /*
1173      * There are various sorts of lookup; src or dst addr v4 /v6 etc.
1174      * there isn't an object type for each (there is only the lookup_dpo_t),
1175      * but, for performance reasons, there is a data plane function, and hence
1176      * VLIB node for each. VLIB graph node construction is based on DPO types
1177      * so we create sub-types.
1178      */
1179     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC] =
1180         dpo_register_new_type(&lkd_vft, lookup_src_nodes);
1181     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST] =
1182         dpo_register_new_type(&lkd_vft, lookup_dst_nodes);
1183     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE] =
1184         dpo_register_new_type(&lkd_vft, lookup_dst_from_interface_nodes);
1185 }