322e0db073321536ff9608a709a6bcb469525d69
[vpp.git] / src / vnet / mpls / mpls_lookup.c
1 /*
2  * mpls_lookup.c: MPLS lookup
3  *
4  * Copyright (c) 2012-2014 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/mpls/mpls.h>
21 #include <vnet/fib/mpls_fib.h>
22 #include <vnet/dpo/load_balance_map.h>
23 #include <vnet/dpo/replicate_dpo.h>
24
25 /**
26  * Static MPLS VLIB forwarding node
27  */
28 static vlib_node_registration_t mpls_lookup_node;
29
30 /**
31  * The arc/edge from the MPLS lookup node to the MPLS replicate node
32  */
33 static u32 mpls_lookup_to_replicate_edge;
34
35 typedef struct {
36   u32 next_index;
37   u32 lb_index;
38   u32 lfib_index;
39   u32 label_net_byte_order;
40   u32 hash;
41 } mpls_lookup_trace_t;
42
43 static u8 *
44 format_mpls_lookup_trace (u8 * s, va_list * args)
45 {
46   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
47   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
48   mpls_lookup_trace_t * t = va_arg (*args, mpls_lookup_trace_t *);
49
50   s = format (s, "MPLS: next [%d], lookup fib index %d, LB index %d hash %x "
51               "label %d eos %d", 
52               t->next_index, t->lfib_index, t->lb_index, t->hash,
53               vnet_mpls_uc_get_label(
54                   clib_net_to_host_u32(t->label_net_byte_order)),
55               vnet_mpls_uc_get_s(t->label_net_byte_order));
56   return s;
57 }
58
59 /*
60  * Compute flow hash. 
61  * We'll use it to select which adjacency to use for this flow.  And other things.
62  */
63 always_inline u32
64 mpls_compute_flow_hash (const mpls_unicast_header_t * hdr,
65                         flow_hash_config_t flow_hash_config)
66 {
67     /*
68      * improve this to include:
69      *  - all labels in the stack.
70      *  - recognise entropy labels.
71      *
72      * We need to byte swap so we use the numerical value. i.e. an odd label
73      * leads to an odd bucket. ass opposed to a label above and below value X.
74      */
75     return (vnet_mpls_uc_get_label(clib_net_to_host_u32(hdr->label_exp_s_ttl)));
76 }
77
78 static inline uword
79 mpls_lookup (vlib_main_t * vm,
80              vlib_node_runtime_t * node,
81              vlib_frame_t * from_frame)
82 {
83   vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
84   u32 n_left_from, next_index, * from, * to_next;
85   mpls_main_t * mm = &mpls_main;
86   u32 thread_index = vlib_get_thread_index();
87
88   from = vlib_frame_vector_args (from_frame);
89   n_left_from = from_frame->n_vectors;
90   next_index = node->cached_next_index;
91
92   while (n_left_from > 0)
93     {
94       u32 n_left_to_next;
95
96       vlib_get_next_frame (vm, node, next_index,
97                            to_next, n_left_to_next);
98
99       while (n_left_from >= 8 && n_left_to_next >= 4)
100         {
101           u32 lbi0, next0, lfib_index0, bi0, hash_c0;
102           const mpls_unicast_header_t * h0;
103           const load_balance_t *lb0;
104           const dpo_id_t *dpo0;
105           vlib_buffer_t * b0;
106           u32 lbi1, next1, lfib_index1, bi1, hash_c1;
107           const mpls_unicast_header_t * h1;
108           const load_balance_t *lb1;
109           const dpo_id_t *dpo1;
110           vlib_buffer_t * b1;
111           u32 lbi2, next2, lfib_index2, bi2, hash_c2;
112           const mpls_unicast_header_t * h2;
113           const load_balance_t *lb2;
114           const dpo_id_t *dpo2;
115           vlib_buffer_t * b2;
116           u32 lbi3, next3, lfib_index3, bi3, hash_c3;
117           const mpls_unicast_header_t * h3;
118           const load_balance_t *lb3;
119           const dpo_id_t *dpo3;
120           vlib_buffer_t * b3;
121
122            /* Prefetch next iteration. */
123           {
124               vlib_buffer_t * p2, * p3, *p4, *p5;
125
126             p2 = vlib_get_buffer (vm, from[2]);
127             p3 = vlib_get_buffer (vm, from[3]);
128             p4 = vlib_get_buffer (vm, from[4]);
129             p5 = vlib_get_buffer (vm, from[5]);
130
131             vlib_prefetch_buffer_header (p2, STORE);
132             vlib_prefetch_buffer_header (p3, STORE);
133             vlib_prefetch_buffer_header (p4, STORE);
134             vlib_prefetch_buffer_header (p5, STORE);
135
136             CLIB_PREFETCH (p2->data, sizeof (h0[0]), STORE);
137             CLIB_PREFETCH (p3->data, sizeof (h0[0]), STORE);
138             CLIB_PREFETCH (p4->data, sizeof (h0[0]), STORE);
139             CLIB_PREFETCH (p5->data, sizeof (h0[0]), STORE);
140           }
141
142           bi0 = to_next[0] = from[0];
143           bi1 = to_next[1] = from[1];
144           bi2 = to_next[2] = from[2];
145           bi3 = to_next[3] = from[3];
146
147           from += 4;
148           n_left_from -= 4;
149           to_next += 4;
150           n_left_to_next -= 4;
151
152           b0 = vlib_get_buffer (vm, bi0);
153           b1 = vlib_get_buffer (vm, bi1);
154           b2 = vlib_get_buffer (vm, bi2);
155           b3 = vlib_get_buffer (vm, bi3);
156           h0 = vlib_buffer_get_current (b0);
157           h1 = vlib_buffer_get_current (b1);
158           h2 = vlib_buffer_get_current (b2);
159           h3 = vlib_buffer_get_current (b3);
160
161           lfib_index0 = vec_elt(mm->fib_index_by_sw_if_index,
162                                 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
163           lfib_index1 = vec_elt(mm->fib_index_by_sw_if_index,
164                                 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
165           lfib_index2 = vec_elt(mm->fib_index_by_sw_if_index,
166                                 vnet_buffer(b2)->sw_if_index[VLIB_RX]);
167           lfib_index3 = vec_elt(mm->fib_index_by_sw_if_index,
168                                 vnet_buffer(b3)->sw_if_index[VLIB_RX]);
169
170           lbi0 = mpls_fib_table_forwarding_lookup (lfib_index0, h0);
171           lbi1 = mpls_fib_table_forwarding_lookup (lfib_index1, h1);
172           lbi2 = mpls_fib_table_forwarding_lookup (lfib_index2, h2);
173           lbi3 = mpls_fib_table_forwarding_lookup (lfib_index3, h3);
174
175           hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
176           hash_c1 = vnet_buffer(b1)->ip.flow_hash = 0;
177           hash_c2 = vnet_buffer(b2)->ip.flow_hash = 0;
178           hash_c3 = vnet_buffer(b3)->ip.flow_hash = 0;
179
180           if (MPLS_IS_REPLICATE & lbi0)
181           {
182               next0 = mpls_lookup_to_replicate_edge;
183               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
184                   (lbi0 & ~MPLS_IS_REPLICATE);
185           }
186           else
187           {
188               lb0 = load_balance_get(lbi0);
189               ASSERT (lb0->lb_n_buckets > 0);
190               ASSERT (is_pow2 (lb0->lb_n_buckets));
191
192               if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
193               {
194                   hash_c0 = vnet_buffer (b0)->ip.flow_hash =
195                       mpls_compute_flow_hash(h0, lb0->lb_hash_config);
196                   dpo0 = load_balance_get_fwd_bucket
197                       (lb0,
198                        (hash_c0 & (lb0->lb_n_buckets_minus_1)));
199               }
200               else
201               {
202                   dpo0 = load_balance_get_bucket_i (lb0, 0);
203               }
204               next0 = dpo0->dpoi_next_node;
205
206               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
207
208               vlib_increment_combined_counter
209                   (cm, thread_index, lbi0, 1,
210                    vlib_buffer_length_in_chain (vm, b0));
211           }
212           if (MPLS_IS_REPLICATE & lbi1)
213           {
214               next1 = mpls_lookup_to_replicate_edge;
215               vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
216                   (lbi1 & ~MPLS_IS_REPLICATE);
217           }
218           else
219           {
220               lb1 = load_balance_get(lbi1);
221               ASSERT (lb1->lb_n_buckets > 0);
222               ASSERT (is_pow2 (lb1->lb_n_buckets));
223
224               if (PREDICT_FALSE(lb1->lb_n_buckets > 1))
225               {
226                   hash_c1 = vnet_buffer (b1)->ip.flow_hash =
227                       mpls_compute_flow_hash(h1, lb1->lb_hash_config);
228                   dpo1 = load_balance_get_fwd_bucket
229                       (lb1,
230                        (hash_c1 & (lb1->lb_n_buckets_minus_1)));
231               }
232               else
233               {
234                   dpo1 = load_balance_get_bucket_i (lb1, 0);
235               }
236               next1 = dpo1->dpoi_next_node;
237
238               vnet_buffer (b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
239
240               vlib_increment_combined_counter
241                   (cm, thread_index, lbi1, 1,
242                    vlib_buffer_length_in_chain (vm, b1));
243           }
244           if (MPLS_IS_REPLICATE & lbi2)
245           {
246               next2 = mpls_lookup_to_replicate_edge;
247               vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
248                   (lbi2 & ~MPLS_IS_REPLICATE);
249           }
250           else
251           {
252               lb2 = load_balance_get(lbi2);
253               ASSERT (lb2->lb_n_buckets > 0);
254               ASSERT (is_pow2 (lb2->lb_n_buckets));
255
256               if (PREDICT_FALSE(lb2->lb_n_buckets > 1))
257               {
258                   hash_c2 = vnet_buffer (b2)->ip.flow_hash =
259                       mpls_compute_flow_hash(h2, lb2->lb_hash_config);
260                   dpo2 = load_balance_get_fwd_bucket
261                       (lb2,
262                        (hash_c2 & (lb2->lb_n_buckets_minus_1)));
263               }
264               else
265               {
266                   dpo2 = load_balance_get_bucket_i (lb2, 0);
267               }
268               next2 = dpo2->dpoi_next_node;
269
270               vnet_buffer (b2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
271
272               vlib_increment_combined_counter
273                   (cm, thread_index, lbi2, 1,
274                    vlib_buffer_length_in_chain (vm, b2));
275           }
276           if (MPLS_IS_REPLICATE & lbi3)
277           {
278               next3 = mpls_lookup_to_replicate_edge;
279               vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
280                   (lbi3 & ~MPLS_IS_REPLICATE);
281           }
282           else
283           {
284               lb3 = load_balance_get(lbi3);
285               ASSERT (lb3->lb_n_buckets > 0);
286               ASSERT (is_pow2 (lb3->lb_n_buckets));
287
288               if (PREDICT_FALSE(lb3->lb_n_buckets > 1))
289               {
290                   hash_c3 = vnet_buffer (b3)->ip.flow_hash =
291                       mpls_compute_flow_hash(h3, lb3->lb_hash_config);
292                   dpo3 = load_balance_get_fwd_bucket
293                       (lb3,
294                        (hash_c3 & (lb3->lb_n_buckets_minus_1)));
295               }
296               else
297               {
298                   dpo3 = load_balance_get_bucket_i (lb3, 0);
299               }
300               next3 = dpo3->dpoi_next_node;
301
302               vnet_buffer (b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
303
304               vlib_increment_combined_counter
305                   (cm, thread_index, lbi3, 1,
306                    vlib_buffer_length_in_chain (vm, b3));
307           }
308
309           /*
310            * before we pop the label copy th values we need to maintain.
311            * The label header is in network byte order.
312            *  last byte is the TTL.
313            *  bits 2 to 4 inclusive are the EXP bits
314            */
315           vnet_buffer (b0)->mpls.ttl = ((char*)h0)[3];
316           vnet_buffer (b0)->mpls.exp = (((char*)h0)[2] & 0xe) >> 1;
317           vnet_buffer (b0)->mpls.first = 1;
318           vnet_buffer (b1)->mpls.ttl = ((char*)h1)[3];
319           vnet_buffer (b1)->mpls.exp = (((char*)h1)[2] & 0xe) >> 1;
320           vnet_buffer (b1)->mpls.first = 1;
321           vnet_buffer (b2)->mpls.ttl = ((char*)h2)[3];
322           vnet_buffer (b2)->mpls.exp = (((char*)h2)[2] & 0xe) >> 1;
323           vnet_buffer (b2)->mpls.first = 1;
324           vnet_buffer (b3)->mpls.ttl = ((char*)h3)[3];
325           vnet_buffer (b3)->mpls.exp = (((char*)h3)[2] & 0xe) >> 1;
326           vnet_buffer (b3)->mpls.first = 1;
327
328           /*
329            * pop the label that was just used in the lookup
330            */
331           vlib_buffer_advance(b0, sizeof(*h0));
332           vlib_buffer_advance(b1, sizeof(*h1));
333           vlib_buffer_advance(b2, sizeof(*h2));
334           vlib_buffer_advance(b3, sizeof(*h3));
335
336           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
337           {
338               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
339                                                         b0, sizeof (*tr));
340               tr->next_index = next0;
341               tr->lb_index = lbi0;
342               tr->lfib_index = lfib_index0;
343               tr->hash = hash_c0;
344               tr->label_net_byte_order = h0->label_exp_s_ttl;
345           }
346
347           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
348           {
349               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
350                                                         b1, sizeof (*tr));
351               tr->next_index = next1;
352               tr->lb_index = lbi1;
353               tr->lfib_index = lfib_index1;
354               tr->hash = hash_c1;
355               tr->label_net_byte_order = h1->label_exp_s_ttl;
356           }
357
358           if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
359           {
360               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
361                                                         b2, sizeof (*tr));
362               tr->next_index = next2;
363               tr->lb_index = lbi2;
364               tr->lfib_index = lfib_index2;
365               tr->hash = hash_c2;
366               tr->label_net_byte_order = h2->label_exp_s_ttl;
367           }
368
369           if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
370           {
371               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
372                                                         b3, sizeof (*tr));
373               tr->next_index = next3;
374               tr->lb_index = lbi3;
375               tr->lfib_index = lfib_index3;
376               tr->hash = hash_c3;
377               tr->label_net_byte_order = h3->label_exp_s_ttl;
378           }
379
380           vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
381                                            to_next, n_left_to_next,
382                                            bi0, bi1, bi2, bi3,
383                                            next0, next1, next2, next3);
384         }
385
386       while (n_left_from > 0 && n_left_to_next > 0)
387       {
388           u32 lbi0, next0, lfib_index0, bi0, hash_c0;
389           const mpls_unicast_header_t * h0;
390           const load_balance_t *lb0;
391           const dpo_id_t *dpo0;
392           vlib_buffer_t * b0;
393
394           bi0 = from[0];
395           to_next[0] = bi0;
396           from += 1;
397           to_next += 1;
398           n_left_from -= 1;
399           n_left_to_next -= 1;
400
401           b0 = vlib_get_buffer (vm, bi0);
402           h0 = vlib_buffer_get_current (b0);
403
404           lfib_index0 = vec_elt(mm->fib_index_by_sw_if_index,
405                                 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
406
407           lbi0 = mpls_fib_table_forwarding_lookup(lfib_index0, h0);
408           hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
409
410           if (MPLS_IS_REPLICATE & lbi0)
411           {
412               next0 = mpls_lookup_to_replicate_edge;
413               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
414                   (lbi0 & ~MPLS_IS_REPLICATE);
415           }
416           else
417           {
418               lb0 = load_balance_get(lbi0);
419               ASSERT (lb0->lb_n_buckets > 0);
420               ASSERT (is_pow2 (lb0->lb_n_buckets));
421
422               if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
423               {
424                   hash_c0 = vnet_buffer (b0)->ip.flow_hash =
425                       mpls_compute_flow_hash(h0, lb0->lb_hash_config);
426                   dpo0 = load_balance_get_fwd_bucket
427                       (lb0,
428                        (hash_c0 & (lb0->lb_n_buckets_minus_1)));
429               }
430               else
431               {
432                   dpo0 = load_balance_get_bucket_i (lb0, 0);
433               }
434               next0 = dpo0->dpoi_next_node;
435               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
436
437               vlib_increment_combined_counter
438                   (cm, thread_index, lbi0, 1,
439                    vlib_buffer_length_in_chain (vm, b0));
440           }
441
442           /*
443            * before we pop the label copy, values we need to maintain.
444            * The label header is in network byte order.
445            *  last byte is the TTL.
446            *  bits 2 to 4 inclusive are the EXP bits
447            */
448           vnet_buffer (b0)->mpls.ttl = ((char*)h0)[3];
449           vnet_buffer (b0)->mpls.exp = (((char*)h0)[2] & 0xe) >> 1;
450           vnet_buffer (b0)->mpls.first = 1;
451
452           /*
453            * pop the label that was just used in the lookup
454            */
455           vlib_buffer_advance(b0, sizeof(*h0));
456
457           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
458           {
459               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
460                                                         b0, sizeof (*tr));
461               tr->next_index = next0;
462               tr->lb_index = lbi0;
463               tr->lfib_index = lfib_index0;
464               tr->hash = hash_c0;
465               tr->label_net_byte_order = h0->label_exp_s_ttl;
466           }
467
468           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
469                                            to_next, n_left_to_next,
470                                            bi0, next0);
471         }
472
473       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
474     }
475   vlib_node_increment_counter (vm, mpls_lookup_node.index,
476                                MPLS_ERROR_PKTS_DECAP, from_frame->n_vectors);
477   return from_frame->n_vectors;
478 }
479
480 static char * mpls_error_strings[] = {
481 #define mpls_error(n,s) s,
482 #include "error.def"
483 #undef mpls_error
484 };
485
486 VLIB_REGISTER_NODE (mpls_lookup_node, static) = {
487   .function = mpls_lookup,
488   .name = "mpls-lookup",
489   /* Takes a vector of packets. */
490   .vector_size = sizeof (u32),
491   .n_errors = MPLS_N_ERROR,
492   .error_strings = mpls_error_strings,
493
494   .sibling_of = "mpls-load-balance",
495
496   .format_buffer = format_mpls_header,
497   .format_trace = format_mpls_lookup_trace,
498   .unformat_buffer = unformat_mpls_header,
499 };
500
501 VLIB_NODE_FUNCTION_MULTIARCH (mpls_lookup_node, mpls_lookup)
502
503 typedef struct {
504   u32 next_index;
505   u32 lb_index;
506   u32 hash;
507 } mpls_load_balance_trace_t;
508
509 static u8 *
510 format_mpls_load_balance_trace (u8 * s, va_list * args)
511 {
512   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
513   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
514   mpls_load_balance_trace_t * t = va_arg (*args, mpls_load_balance_trace_t *);
515
516   s = format (s, "MPLS: next [%d], LB index %d hash %d",
517               t->next_index, t->lb_index, t->hash);
518   return s;
519 }
520
521 always_inline uword
522 mpls_load_balance (vlib_main_t * vm,
523                   vlib_node_runtime_t * node,
524                   vlib_frame_t * frame)
525 {
526   vlib_combined_counter_main_t * cm = &load_balance_main.lbm_via_counters;
527   u32 n_left_from, n_left_to_next, * from, * to_next;
528   u32 thread_index = vlib_get_thread_index();
529   u32 next;
530
531   from = vlib_frame_vector_args (frame);
532   n_left_from = frame->n_vectors;
533   next = node->cached_next_index;
534
535   while (n_left_from > 0)
536     {
537       vlib_get_next_frame (vm, node, next,
538                            to_next, n_left_to_next);
539
540
541       while (n_left_from >= 4 && n_left_to_next >= 2)
542         {
543           const load_balance_t *lb0, *lb1;
544           vlib_buffer_t * p0, *p1;
545           u32 pi0, lbi0, hc0, pi1, lbi1, hc1, next0, next1;
546           const mpls_unicast_header_t *mpls0, *mpls1;
547           const dpo_id_t *dpo0, *dpo1;
548
549           /* Prefetch next iteration. */
550           {
551             vlib_buffer_t * p2, * p3;
552
553             p2 = vlib_get_buffer (vm, from[2]);
554             p3 = vlib_get_buffer (vm, from[3]);
555
556             vlib_prefetch_buffer_header (p2, STORE);
557             vlib_prefetch_buffer_header (p3, STORE);
558
559             CLIB_PREFETCH (p2->data, sizeof (mpls0[0]), STORE);
560             CLIB_PREFETCH (p3->data, sizeof (mpls0[0]), STORE);
561           }
562
563           pi0 = to_next[0] = from[0];
564           pi1 = to_next[1] = from[1];
565
566           from += 2;
567           n_left_from -= 2;
568           to_next += 2;
569           n_left_to_next -= 2;
570
571           p0 = vlib_get_buffer (vm, pi0);
572           p1 = vlib_get_buffer (vm, pi1);
573
574           mpls0 = vlib_buffer_get_current (p0);
575           mpls1 = vlib_buffer_get_current (p1);
576           lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
577           lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
578
579           lb0 = load_balance_get(lbi0);
580           lb1 = load_balance_get(lbi1);
581
582           /*
583            * this node is for via FIBs we can re-use the hash value from the
584            * to node if present.
585            * We don't want to use the same hash value at each level in the recursion
586            * graph as that would lead to polarisation
587            */
588           hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
589           hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
590
591           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
592           {
593               if (PREDICT_TRUE (vnet_buffer(p0)->ip.flow_hash))
594               {
595                   hc0 = vnet_buffer(p0)->ip.flow_hash = vnet_buffer(p0)->ip.flow_hash >> 1;
596               }
597               else
598               {
599                   hc0 = vnet_buffer(p0)->ip.flow_hash = mpls_compute_flow_hash(mpls0, hc0);
600               }
601               dpo0 = load_balance_get_fwd_bucket(lb0, (hc0 & lb0->lb_n_buckets_minus_1));
602           }
603           else
604           {
605               dpo0 = load_balance_get_bucket_i (lb0, 0);
606           }
607           if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
608           {
609               if (PREDICT_TRUE (vnet_buffer(p1)->ip.flow_hash))
610               {
611                   hc1 = vnet_buffer(p1)->ip.flow_hash = vnet_buffer(p1)->ip.flow_hash >> 1;
612               }
613               else
614               {
615                   hc1 = vnet_buffer(p1)->ip.flow_hash = mpls_compute_flow_hash(mpls1, hc1);
616               }
617               dpo1 = load_balance_get_fwd_bucket(lb1, (hc1 & lb1->lb_n_buckets_minus_1));
618           }
619           else
620           {
621               dpo1 = load_balance_get_bucket_i (lb1, 0);
622           }
623
624           next0 = dpo0->dpoi_next_node;
625           next1 = dpo1->dpoi_next_node;
626
627           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
628           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
629
630           vlib_increment_combined_counter
631               (cm, thread_index, lbi0, 1,
632                vlib_buffer_length_in_chain (vm, p0));
633           vlib_increment_combined_counter
634               (cm, thread_index, lbi1, 1,
635                vlib_buffer_length_in_chain (vm, p1));
636
637           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
638           {
639               mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
640                                                               p0, sizeof (*tr));
641               tr->next_index = next0;
642               tr->lb_index = lbi0;
643               tr->hash = hc0;
644           }
645
646           vlib_validate_buffer_enqueue_x2 (vm, node, next,
647                                            to_next, n_left_to_next,
648                                            pi0, pi1, next0, next1);
649        }
650
651       while (n_left_from > 0 && n_left_to_next > 0)
652         {
653           const load_balance_t *lb0;
654           vlib_buffer_t * p0;
655           u32 pi0, lbi0, hc0, next0;
656           const mpls_unicast_header_t *mpls0;
657           const dpo_id_t *dpo0;
658
659           pi0 = from[0];
660           to_next[0] = pi0;
661           from += 1;
662           to_next += 1;
663           n_left_to_next -= 1;
664           n_left_from -= 1;
665
666           p0 = vlib_get_buffer (vm, pi0);
667
668           mpls0 = vlib_buffer_get_current (p0);
669           lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
670
671           lb0 = load_balance_get(lbi0);
672
673           hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
674           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
675           {
676               if (PREDICT_TRUE (vnet_buffer(p0)->ip.flow_hash))
677               {
678                   hc0 = vnet_buffer(p0)->ip.flow_hash = vnet_buffer(p0)->ip.flow_hash >> 1;
679               }
680               else
681               {
682                   hc0 = vnet_buffer(p0)->ip.flow_hash = mpls_compute_flow_hash(mpls0, hc0);
683               }
684                dpo0 = load_balance_get_fwd_bucket(lb0, (hc0 & lb0->lb_n_buckets_minus_1));
685           }
686           else
687           {
688               dpo0 = load_balance_get_bucket_i (lb0, 0);
689           }
690
691           next0 = dpo0->dpoi_next_node;
692           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
693
694           vlib_increment_combined_counter
695               (cm, thread_index, lbi0, 1,
696                vlib_buffer_length_in_chain (vm, p0));
697
698           vlib_validate_buffer_enqueue_x1 (vm, node, next,
699                                            to_next, n_left_to_next,
700                                            pi0, next0);
701         }
702
703       vlib_put_next_frame (vm, node, next, n_left_to_next);
704     }
705
706   return frame->n_vectors;
707 }
708
709 VLIB_REGISTER_NODE (mpls_load_balance_node) = {
710   .function = mpls_load_balance,
711   .name = "mpls-load-balance",
712   .vector_size = sizeof (u32),
713   .format_trace = format_mpls_load_balance_trace,
714   .n_next_nodes = 1,
715   .next_nodes =
716   {
717       [0] = "mpls-drop",
718   },
719
720 };
721
722 VLIB_NODE_FUNCTION_MULTIARCH (mpls_load_balance_node, mpls_load_balance)
723
724
725 static clib_error_t *
726 mpls_lookup_init (vlib_main_t * vm)
727 {
728   clib_error_t * error;
729
730   if ((error = vlib_call_init_function (vm, mpls_init)))
731     return error;
732
733   mpls_lookup_to_replicate_edge =
734       vlib_node_add_named_next(vm,
735                                mpls_lookup_node.index,
736                                "mpls-replicate");
737
738   return (NULL);
739 }
740
741 VLIB_INIT_FUNCTION (mpls_lookup_init);