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