blob: 059fa3fd869ac9688988c59bdfb9c82e7114f03b [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
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>
Neale Ranns6af1c042017-05-26 03:48:53 -070018#include <vnet/dpo/load_balance_map.h>
19#include <vnet/mpls/mpls_lookup.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010020#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>
Neale Ranns0f26c5a2017-03-01 15:12:11 -080024#include <vnet/mfib/mfib_table.h>
25#include <vnet/mfib/ip4_mfib.h>
26#include <vnet/mfib/ip6_mfib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010027
28static const char *const lookup_input_names[] = LOOKUP_INPUTS;
Neale Ranns0f26c5a2017-03-01 15:12:11 -080029static const char *const lookup_cast_names[] = LOOKUP_CASTS;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010030
31/**
32 * @brief Enumeration of the lookup subtypes
33 */
34typedef enum lookup_sub_type_t_
35{
36 LOOKUP_SUB_TYPE_SRC,
37 LOOKUP_SUB_TYPE_DST,
Neale Ranns0f26c5a2017-03-01 15:12:11 -080038 LOOKUP_SUB_TYPE_DST_MCAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010039 LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE,
40} lookup_sub_type_t;
41#define LOOKUP_SUB_TYPE_NUM (LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE+1)
42
43#define FOR_EACH_LOOKUP_SUB_TYPE(_st) \
44 for (_st = LOOKUP_SUB_TYPE_IP4_SRC; _st < LOOKUP_SUB_TYPE_NUM; _st++)
45
46/**
47 * @brief pool of all MPLS Label DPOs
48 */
49lookup_dpo_t *lookup_dpo_pool;
50
51/**
52 * @brief An array of registered DPO type values for the sub-types
53 */
54static dpo_type_t lookup_dpo_sub_types[LOOKUP_SUB_TYPE_NUM];
55
56static lookup_dpo_t *
57lookup_dpo_alloc (void)
58{
59 lookup_dpo_t *lkd;
60
61 pool_get_aligned(lookup_dpo_pool, lkd, CLIB_CACHE_LINE_BYTES);
62
63 return (lkd);
64}
65
66static index_t
67lookup_dpo_get_index (lookup_dpo_t *lkd)
68{
69 return (lkd - lookup_dpo_pool);
70}
71
72static void
73lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
74 dpo_proto_t proto,
Neale Ranns0f26c5a2017-03-01 15:12:11 -080075 lookup_cast_t cast,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010076 lookup_input_t input,
77 lookup_table_t table_config,
78 dpo_id_t *dpo)
79{
80 lookup_dpo_t *lkd;
81 dpo_type_t type;
82
83 lkd = lookup_dpo_alloc();
84 lkd->lkd_fib_index = fib_index;
85 lkd->lkd_proto = proto;
86 lkd->lkd_input = input;
87 lkd->lkd_table = table_config;
Neale Ranns0f26c5a2017-03-01 15:12:11 -080088 lkd->lkd_cast = cast;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010089
90 /*
91 * use the input type to select the lookup sub-type
92 */
93 type = 0;
94
95 switch (input)
96 {
97 case LOOKUP_INPUT_SRC_ADDR:
98 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC];
99 break;
100 case LOOKUP_INPUT_DST_ADDR:
101 switch (table_config)
102 {
103 case LOOKUP_TABLE_FROM_INPUT_INTERFACE:
104 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE];
105 break;
106 case LOOKUP_TABLE_FROM_CONFIG:
107 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST];
108 break;
109 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800110 if (LOOKUP_MULTICAST == cast)
111 {
112 type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_MCAST];
113 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100114 }
115
116 if (0 == type)
117 {
118 dpo_reset(dpo);
119 }
120 else
121 {
122 dpo_set(dpo, type, proto, lookup_dpo_get_index(lkd));
123 }
124}
125
126void
127lookup_dpo_add_or_lock_w_fib_index (fib_node_index_t fib_index,
128 dpo_proto_t proto,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800129 lookup_cast_t cast,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100130 lookup_input_t input,
131 lookup_table_t table_config,
132 dpo_id_t *dpo)
133{
134 if (LOOKUP_TABLE_FROM_CONFIG == table_config)
135 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800136 if (LOOKUP_UNICAST == cast)
137 {
Neale Ranns15002542017-09-10 04:39:11 -0700138 fib_table_lock(fib_index,
139 dpo_proto_to_fib(proto),
140 FIB_SOURCE_RR);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800141 }
142 else
143 {
Neale Ranns15002542017-09-10 04:39:11 -0700144 mfib_table_lock(fib_index,
145 dpo_proto_to_fib(proto),
146 MFIB_SOURCE_RR);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800147 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100148 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800149 lookup_dpo_add_or_lock_i(fib_index, proto, cast, input, table_config, dpo);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100150}
151
152void
153lookup_dpo_add_or_lock_w_table_id (u32 table_id,
154 dpo_proto_t proto,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800155 lookup_cast_t cast,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100156 lookup_input_t input,
157 lookup_table_t table_config,
158 dpo_id_t *dpo)
159{
160 fib_node_index_t fib_index = FIB_NODE_INDEX_INVALID;
161
162 if (LOOKUP_TABLE_FROM_CONFIG == table_config)
163 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800164 if (LOOKUP_UNICAST == cast)
165 {
166 fib_index =
167 fib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
Neale Ranns15002542017-09-10 04:39:11 -0700168 table_id,
169 FIB_SOURCE_RR);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800170 }
171 else
172 {
173 fib_index =
174 mfib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
Neale Ranns15002542017-09-10 04:39:11 -0700175 table_id,
176 MFIB_SOURCE_RR);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800177 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100178 }
179
180 ASSERT(FIB_NODE_INDEX_INVALID != fib_index);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800181 lookup_dpo_add_or_lock_i(fib_index, proto, cast, input, table_config, dpo);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100182}
183
184u8*
185format_lookup_dpo (u8 *s, va_list *args)
186{
187 index_t index = va_arg (*args, index_t);
188 lookup_dpo_t *lkd;
189
190 lkd = lookup_dpo_get(index);
191
192 if (LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table)
193 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800194 s = format(s, "%s,%s lookup in interface's %U table",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100195 lookup_input_names[lkd->lkd_input],
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800196 lookup_cast_names[lkd->lkd_cast],
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100197 format_dpo_proto, lkd->lkd_proto);
198 }
199 else
200 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800201 if (LOOKUP_UNICAST == lkd->lkd_cast)
202 {
203 s = format(s, "%s,%s lookup in %U",
204 lookup_input_names[lkd->lkd_input],
205 lookup_cast_names[lkd->lkd_cast],
206 format_fib_table_name, lkd->lkd_fib_index,
207 dpo_proto_to_fib(lkd->lkd_proto));
208 }
209 else
210 {
211 s = format(s, "%s,%s lookup in %U",
212 lookup_input_names[lkd->lkd_input],
213 lookup_cast_names[lkd->lkd_cast],
214 format_mfib_table_name, lkd->lkd_fib_index,
215 dpo_proto_to_fib(lkd->lkd_proto));
216 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100217 }
218 return (s);
219}
220
221static void
222lookup_dpo_lock (dpo_id_t *dpo)
223{
224 lookup_dpo_t *lkd;
225
226 lkd = lookup_dpo_get(dpo->dpoi_index);
227
228 lkd->lkd_locks++;
229}
230
231static void
232lookup_dpo_unlock (dpo_id_t *dpo)
233{
234 lookup_dpo_t *lkd;
235
236 lkd = lookup_dpo_get(dpo->dpoi_index);
237
238 lkd->lkd_locks--;
239
240 if (0 == lkd->lkd_locks)
241 {
242 if (LOOKUP_TABLE_FROM_CONFIG == lkd->lkd_table)
243 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800244 if (LOOKUP_UNICAST == lkd->lkd_cast)
245 {
246 fib_table_unlock(lkd->lkd_fib_index,
Neale Ranns15002542017-09-10 04:39:11 -0700247 dpo_proto_to_fib(lkd->lkd_proto),
248 FIB_SOURCE_RR);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800249 }
250 else
251 {
252 mfib_table_unlock(lkd->lkd_fib_index,
Neale Ranns15002542017-09-10 04:39:11 -0700253 dpo_proto_to_fib(lkd->lkd_proto),
254 MFIB_SOURCE_RR);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800255 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100256 }
257 pool_put(lookup_dpo_pool, lkd);
258 }
259}
260
261always_inline void
262ip4_src_fib_lookup_one (u32 src_fib_index0,
263 const ip4_address_t * addr0,
264 u32 * src_adj_index0)
265{
Neale Ranns04a75e32017-03-23 06:46:01 -0700266 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100267 ip4_fib_mtrie_t * mtrie0;
268
269 mtrie0 = &ip4_fib_get (src_fib_index0)->mtrie;
270
Neale Ranns04a75e32017-03-23 06:46:01 -0700271 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, addr0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100272 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
273 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
274
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100275 src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
276}
277
278always_inline void
279ip4_src_fib_lookup_two (u32 src_fib_index0,
280 u32 src_fib_index1,
281 const ip4_address_t * addr0,
282 const ip4_address_t * addr1,
283 u32 * src_adj_index0,
284 u32 * src_adj_index1)
285{
286 ip4_fib_mtrie_leaf_t leaf0, leaf1;
287 ip4_fib_mtrie_t * mtrie0, * mtrie1;
288
289 mtrie0 = &ip4_fib_get (src_fib_index0)->mtrie;
290 mtrie1 = &ip4_fib_get (src_fib_index1)->mtrie;
291
Neale Ranns04a75e32017-03-23 06:46:01 -0700292 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, addr0);
293 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, addr1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100294
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100295 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
296 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 2);
297
298 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
299 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 3);
300
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100301 src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
302 src_adj_index1[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
303}
304
305/**
306 * @brief Lookup trace data
307 */
308typedef struct lookup_trace_t_
309{
310 union {
311 ip46_address_t addr;
312 mpls_unicast_header_t hdr;
313 };
314 fib_node_index_t fib_index;
315 index_t lbi;
316} lookup_trace_t;
317
318
319always_inline uword
320lookup_dpo_ip4_inline (vlib_main_t * vm,
321 vlib_node_runtime_t * node,
322 vlib_frame_t * from_frame,
323 int input_src_addr,
324 int table_from_interface)
325{
326 u32 n_left_from, next_index, * from, * to_next;
Damjan Marion586afd72017-04-05 19:18:20 +0200327 u32 thread_index = vlib_get_thread_index();
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100328 vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
329
330 from = vlib_frame_vector_args (from_frame);
331 n_left_from = from_frame->n_vectors;
332
333 next_index = node->cached_next_index;
334
335 while (n_left_from > 0)
336 {
337 u32 n_left_to_next;
338
339 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
340
Neale Rannsd3b85b02016-10-22 15:17:21 -0700341 while (n_left_from >= 4 && n_left_to_next > 2)
342 {
Neale Ranns5e575b12016-10-03 09:40:25 +0100343 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
344 flow_hash_config_t flow_hash_config0;
Neale Rannsd3b85b02016-10-22 15:17:21 -0700345 const ip4_address_t *input_addr0;
346 const load_balance_t *lb0;
347 const lookup_dpo_t * lkd0;
348 const ip4_header_t * ip0;
349 const dpo_id_t *dpo0;
350 vlib_buffer_t * b0;
351 u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
352 flow_hash_config_t flow_hash_config1;
353 const ip4_address_t *input_addr1;
354 const load_balance_t *lb1;
355 const lookup_dpo_t * lkd1;
356 const ip4_header_t * ip1;
357 const dpo_id_t *dpo1;
358 vlib_buffer_t * b1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100359
Neale Rannsd3b85b02016-10-22 15:17:21 -0700360 /* Prefetch next iteration. */
361 {
362 vlib_buffer_t * p2, * p3;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100363
Neale Rannsd3b85b02016-10-22 15:17:21 -0700364 p2 = vlib_get_buffer (vm, from[2]);
365 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100366
Neale Rannsd3b85b02016-10-22 15:17:21 -0700367 vlib_prefetch_buffer_header (p2, LOAD);
368 vlib_prefetch_buffer_header (p3, LOAD);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100369
Neale Rannsd3b85b02016-10-22 15:17:21 -0700370 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
371 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
372 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100373
Neale Rannsd3b85b02016-10-22 15:17:21 -0700374 bi0 = from[0];
375 to_next[0] = bi0;
376 bi1 = from[1];
377 to_next[1] = bi1;
378 from += 2;
379 to_next += 2;
380 n_left_from -= 2;
381 n_left_to_next -= 2;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100382
Neale Rannsd3b85b02016-10-22 15:17:21 -0700383 b0 = vlib_get_buffer (vm, bi0);
384 ip0 = vlib_buffer_get_current (b0);
385 b1 = vlib_get_buffer (vm, bi1);
386 ip1 = vlib_buffer_get_current (b1);
387
388 /* dst lookup was done by ip4 lookup */
389 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
390 lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
391 lkd0 = lookup_dpo_get(lkdi0);
392 lkd1 = lookup_dpo_get(lkdi1);
393
394 /*
395 * choose between a lookup using the fib index in the DPO
396 * or getting the FIB index from the interface.
397 */
398 if (table_from_interface)
399 {
400 fib_index0 =
401 ip4_fib_table_get_index_for_sw_if_index(
402 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
403 fib_index1 =
404 ip4_fib_table_get_index_for_sw_if_index(
405 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
406 }
407 else
408 {
409 fib_index0 = lkd0->lkd_fib_index;
410 fib_index1 = lkd1->lkd_fib_index;
411 }
412
413 /*
414 * choose between a source or destination address lookup in the table
415 */
416 if (input_src_addr)
417 {
418 input_addr0 = &ip0->src_address;
419 input_addr1 = &ip1->src_address;
420 }
421 else
422 {
423 input_addr0 = &ip0->dst_address;
424 input_addr1 = &ip1->dst_address;
425 }
426
427 /* do lookup */
Neale Ranns450cd302016-11-09 17:49:42 +0000428 ip4_src_fib_lookup_two (fib_index0, fib_index1,
429 input_addr0, input_addr1,
430 &lbi0, &lbi1);
Neale Rannsd3b85b02016-10-22 15:17:21 -0700431 lb0 = load_balance_get(lbi0);
432 lb1 = load_balance_get(lbi1);
433
Neale Rannscb630ff2016-12-14 13:31:29 +0100434 vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
435 vnet_buffer(b1)->sw_if_index[VLIB_TX] = fib_index1;
436
Neale Rannsd3b85b02016-10-22 15:17:21 -0700437 /* Use flow hash to compute multipath adjacency. */
438 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
439 hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
440
441 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
442 {
443 flow_hash_config0 = lb0->lb_hash_config;
444 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
445 ip4_compute_flow_hash (ip0, flow_hash_config0);
446 }
447
448 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
449 {
450 flow_hash_config1 = lb1->lb_hash_config;
451 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
452 ip4_compute_flow_hash (ip1, flow_hash_config1);
453 }
454
455 dpo0 = load_balance_get_bucket_i(lb0,
456 (hash_c0 &
457 (lb0->lb_n_buckets_minus_1)));
458 dpo1 = load_balance_get_bucket_i(lb1,
459 (hash_c1 &
460 (lb1->lb_n_buckets_minus_1)));
461
462 next0 = dpo0->dpoi_next_node;
463 next1 = dpo1->dpoi_next_node;
464 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
465 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
466
467 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200468 (cm, thread_index, lbi0, 1,
Neale Rannsd3b85b02016-10-22 15:17:21 -0700469 vlib_buffer_length_in_chain (vm, b0));
470 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200471 (cm, thread_index, lbi1, 1,
Neale Rannsd3b85b02016-10-22 15:17:21 -0700472 vlib_buffer_length_in_chain (vm, b1));
473
474 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
475 {
476 lookup_trace_t *tr = vlib_add_trace (vm, node,
477 b0, sizeof (*tr));
478 tr->fib_index = fib_index0;
479 tr->lbi = lbi0;
480 tr->addr.ip4 = *input_addr0;
481 }
482 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
483 {
484 lookup_trace_t *tr = vlib_add_trace (vm, node,
485 b1, sizeof (*tr));
486 tr->fib_index = fib_index1;
487 tr->lbi = lbi1;
488 tr->addr.ip4 = *input_addr1;
489 }
490
491 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
492 to_next, n_left_to_next,
493 bi0, bi1, next0, next1);
494 }
495
496 while (n_left_from > 0 && n_left_to_next > 0)
497 {
498 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
499 flow_hash_config_t flow_hash_config0;
500 const ip4_address_t *input_addr;
501 const load_balance_t *lb0;
502 const lookup_dpo_t * lkd0;
503 const ip4_header_t * ip0;
504 const dpo_id_t *dpo0;
505 vlib_buffer_t * b0;
506
507 bi0 = from[0];
508 to_next[0] = bi0;
509 from += 1;
510 to_next += 1;
511 n_left_from -= 1;
512 n_left_to_next -= 1;
513
514 b0 = vlib_get_buffer (vm, bi0);
515 ip0 = vlib_buffer_get_current (b0);
516
517 /* dst lookup was done by ip4 lookup */
518 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
519 lkd0 = lookup_dpo_get(lkdi0);
520
521 /*
522 * choose between a lookup using the fib index in the DPO
523 * or getting the FIB index from the interface.
524 */
525 if (table_from_interface)
526 {
527 fib_index0 =
528 ip4_fib_table_get_index_for_sw_if_index(
529 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
530 }
531 else
532 {
533 fib_index0 = lkd0->lkd_fib_index;
534 }
535
536 /*
537 * choose between a source or destination address lookup in the table
538 */
539 if (input_src_addr)
540 {
541 input_addr = &ip0->src_address;
542 }
543 else
544 {
545 input_addr = &ip0->dst_address;
546 }
547
548 /* do lookup */
549 ip4_src_fib_lookup_one (fib_index0, input_addr, &lbi0);
550 lb0 = load_balance_get(lbi0);
Neale Ranns5e575b12016-10-03 09:40:25 +0100551
Neale Rannscb630ff2016-12-14 13:31:29 +0100552 vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
553
Neale Ranns5e575b12016-10-03 09:40:25 +0100554 /* Use flow hash to compute multipath adjacency. */
555 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
556
557 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Neale Rannsd3b85b02016-10-22 15:17:21 -0700558 {
Neale Ranns5e575b12016-10-03 09:40:25 +0100559 flow_hash_config0 = lb0->lb_hash_config;
560 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
561 ip4_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsd3b85b02016-10-22 15:17:21 -0700562 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100563
564 dpo0 = load_balance_get_bucket_i(lb0,
565 (hash_c0 &
566 (lb0->lb_n_buckets_minus_1)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100567
Neale Rannsd3b85b02016-10-22 15:17:21 -0700568 next0 = dpo0->dpoi_next_node;
569 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100570
Neale Rannsd3b85b02016-10-22 15:17:21 -0700571 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200572 (cm, thread_index, lbi0, 1,
Neale Rannsd3b85b02016-10-22 15:17:21 -0700573 vlib_buffer_length_in_chain (vm, b0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100574
Neale Rannsd3b85b02016-10-22 15:17:21 -0700575 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
576 {
577 lookup_trace_t *tr = vlib_add_trace (vm, node,
578 b0, sizeof (*tr));
579 tr->fib_index = fib_index0;
580 tr->lbi = lbi0;
581 tr->addr.ip4 = *input_addr;
582 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100583
Neale Rannsd3b85b02016-10-22 15:17:21 -0700584 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
585 n_left_to_next, bi0, next0);
586 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100587 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
588 }
589 return from_frame->n_vectors;
590}
591
592static u8 *
593format_lookup_trace (u8 * s, va_list * args)
594{
595 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
596 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
597 lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200598 u32 indent = format_get_indent (s);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100599 s = format (s, "%U fib-index:%d addr:%U load-balance:%d",
600 format_white_space, indent,
601 t->fib_index,
602 format_ip46_address, &t->addr, IP46_TYPE_ANY,
603 t->lbi);
604 return s;
605}
606
Damjan Marion2574d9f2018-06-26 14:45:49 +0200607static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100608lookup_ip4_dst (vlib_main_t * vm,
609 vlib_node_runtime_t * node,
610 vlib_frame_t * from_frame)
611{
612 return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 0));
613}
614
615VLIB_REGISTER_NODE (lookup_ip4_dst_node) = {
616 .function = lookup_ip4_dst,
617 .name = "lookup-ip4-dst",
618 .vector_size = sizeof (u32),
619 .sibling_of = "ip4-lookup",
620 .format_trace = format_lookup_trace,
621};
622VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_node, lookup_ip4_dst)
623
Damjan Marion2574d9f2018-06-26 14:45:49 +0200624static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100625lookup_ip4_dst_itf (vlib_main_t * vm,
626 vlib_node_runtime_t * node,
627 vlib_frame_t * from_frame)
628{
629 return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 1));
630}
631
632VLIB_REGISTER_NODE (lookup_ip4_dst_itf_node) = {
633 .function = lookup_ip4_dst_itf,
634 .name = "lookup-ip4-dst-itf",
635 .vector_size = sizeof (u32),
636 .sibling_of = "ip4-lookup",
637 .format_trace = format_lookup_trace,
638};
639VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_itf_node, lookup_ip4_dst_itf)
640
Damjan Marion2574d9f2018-06-26 14:45:49 +0200641static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642lookup_ip4_src (vlib_main_t * vm,
643 vlib_node_runtime_t * node,
644 vlib_frame_t * from_frame)
645{
646 return (lookup_dpo_ip4_inline(vm, node, from_frame, 1, 0));
647}
648
649VLIB_REGISTER_NODE (lookup_ip4_src_node) = {
650 .function = lookup_ip4_src,
651 .name = "lookup-ip4-src",
652 .vector_size = sizeof (u32),
653 .format_trace = format_lookup_trace,
654 .sibling_of = "ip4-lookup",
655};
656VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_src_node, lookup_ip4_src)
657
658always_inline uword
659lookup_dpo_ip6_inline (vlib_main_t * vm,
660 vlib_node_runtime_t * node,
661 vlib_frame_t * from_frame,
Billy McFallcfcf1e22016-10-14 09:51:49 -0400662 int input_src_addr,
663 int table_from_interface)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100664{
665 vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
666 u32 n_left_from, next_index, * from, * to_next;
Damjan Marion586afd72017-04-05 19:18:20 +0200667 u32 thread_index = vlib_get_thread_index();
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100668
669 from = vlib_frame_vector_args (from_frame);
670 n_left_from = from_frame->n_vectors;
671
672 next_index = node->cached_next_index;
673
674 while (n_left_from > 0)
675 {
676 u32 n_left_to_next;
677
678 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
679
Neale Rannsd3b85b02016-10-22 15:17:21 -0700680 while (n_left_from >= 4 && n_left_to_next > 2)
681 {
682 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
Neale Ranns5e575b12016-10-03 09:40:25 +0100683 flow_hash_config_t flow_hash_config0;
Neale Rannsd3b85b02016-10-22 15:17:21 -0700684 const ip6_address_t *input_addr0;
685 const load_balance_t *lb0;
686 const lookup_dpo_t * lkd0;
687 const ip6_header_t * ip0;
688 const dpo_id_t *dpo0;
689 vlib_buffer_t * b0;
690 u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
691 flow_hash_config_t flow_hash_config1;
692 const ip6_address_t *input_addr1;
693 const load_balance_t *lb1;
694 const lookup_dpo_t * lkd1;
695 const ip6_header_t * ip1;
696 const dpo_id_t *dpo1;
697 vlib_buffer_t * b1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100698
Neale Rannsd3b85b02016-10-22 15:17:21 -0700699 /* Prefetch next iteration. */
700 {
701 vlib_buffer_t * p2, * p3;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100702
Neale Rannsd3b85b02016-10-22 15:17:21 -0700703 p2 = vlib_get_buffer (vm, from[2]);
704 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705
Neale Rannsd3b85b02016-10-22 15:17:21 -0700706 vlib_prefetch_buffer_header (p2, LOAD);
707 vlib_prefetch_buffer_header (p3, LOAD);
Billy McFallcfcf1e22016-10-14 09:51:49 -0400708
Neale Rannsd3b85b02016-10-22 15:17:21 -0700709 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
710 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
711 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100712
Neale Rannsd3b85b02016-10-22 15:17:21 -0700713 bi0 = from[0];
714 to_next[0] = bi0;
715 bi1 = from[1];
716 to_next[1] = bi1;
717 from += 2;
718 to_next += 2;
719 n_left_from -= 2;
720 n_left_to_next -= 2;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100721
Neale Rannsd3b85b02016-10-22 15:17:21 -0700722 b0 = vlib_get_buffer (vm, bi0);
723 ip0 = vlib_buffer_get_current (b0);
724 b1 = vlib_get_buffer (vm, bi1);
725 ip1 = vlib_buffer_get_current (b1);
726
727 /* dst lookup was done by ip6 lookup */
728 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
729 lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
730 lkd0 = lookup_dpo_get(lkdi0);
731 lkd1 = lookup_dpo_get(lkdi1);
732
733 /*
734 * choose between a lookup using the fib index in the DPO
735 * or getting the FIB index from the interface.
736 */
737 if (table_from_interface)
738 {
739 fib_index0 =
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000740 ip6_fib_table_get_index_for_sw_if_index(
Neale Rannsd3b85b02016-10-22 15:17:21 -0700741 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
742 fib_index1 =
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000743 ip6_fib_table_get_index_for_sw_if_index(
Neale Rannsd3b85b02016-10-22 15:17:21 -0700744 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
745 }
746 else
747 {
748 fib_index0 = lkd0->lkd_fib_index;
749 fib_index1 = lkd1->lkd_fib_index;
750 }
751
752 /*
753 * choose between a source or destination address lookup in the table
754 */
755 if (input_src_addr)
756 {
757 input_addr0 = &ip0->src_address;
758 input_addr1 = &ip1->src_address;
759 }
760 else
761 {
762 input_addr0 = &ip0->dst_address;
763 input_addr1 = &ip1->dst_address;
764 }
765
766 /* do src lookup */
767 lbi0 = ip6_fib_table_fwding_lookup(&ip6_main,
768 fib_index0,
769 input_addr0);
770 lbi1 = ip6_fib_table_fwding_lookup(&ip6_main,
771 fib_index1,
772 input_addr1);
773 lb0 = load_balance_get(lbi0);
774 lb1 = load_balance_get(lbi1);
775
Neale Rannscb630ff2016-12-14 13:31:29 +0100776 vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
777 vnet_buffer(b1)->sw_if_index[VLIB_TX] = fib_index1;
778
Neale Rannsd3b85b02016-10-22 15:17:21 -0700779 /* Use flow hash to compute multipath adjacency. */
780 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
781 hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
782
783 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
784 {
785 flow_hash_config0 = lb0->lb_hash_config;
786 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
787 ip6_compute_flow_hash (ip0, flow_hash_config0);
788 }
789
790 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
791 {
792 flow_hash_config1 = lb1->lb_hash_config;
793 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
794 ip6_compute_flow_hash (ip1, flow_hash_config1);
795 }
796
797 dpo0 = load_balance_get_bucket_i(lb0,
798 (hash_c0 &
799 (lb0->lb_n_buckets_minus_1)));
800 dpo1 = load_balance_get_bucket_i(lb1,
801 (hash_c1 &
802 (lb1->lb_n_buckets_minus_1)));
803
804 next0 = dpo0->dpoi_next_node;
805 next1 = dpo1->dpoi_next_node;
806 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
807 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
808
809 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200810 (cm, thread_index, lbi0, 1,
Neale Rannsd3b85b02016-10-22 15:17:21 -0700811 vlib_buffer_length_in_chain (vm, b0));
812 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200813 (cm, thread_index, lbi1, 1,
Neale Rannsd3b85b02016-10-22 15:17:21 -0700814 vlib_buffer_length_in_chain (vm, b1));
815
816 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
817 {
818 lookup_trace_t *tr = vlib_add_trace (vm, node,
819 b0, sizeof (*tr));
820 tr->fib_index = fib_index0;
821 tr->lbi = lbi0;
822 tr->addr.ip6 = *input_addr0;
823 }
824 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
825 {
826 lookup_trace_t *tr = vlib_add_trace (vm, node,
827 b1, sizeof (*tr));
828 tr->fib_index = fib_index1;
829 tr->lbi = lbi1;
830 tr->addr.ip6 = *input_addr1;
831 }
832 vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
833 n_left_to_next, bi0, bi1,
834 next0, next1);
835 }
836 while (n_left_from > 0 && n_left_to_next > 0)
837 {
838 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
839 flow_hash_config_t flow_hash_config0;
840 const ip6_address_t *input_addr0;
841 const load_balance_t *lb0;
842 const lookup_dpo_t * lkd0;
843 const ip6_header_t * ip0;
844 const dpo_id_t *dpo0;
845 vlib_buffer_t * b0;
846
847 bi0 = from[0];
848 to_next[0] = bi0;
849 from += 1;
850 to_next += 1;
851 n_left_from -= 1;
852 n_left_to_next -= 1;
853
854 b0 = vlib_get_buffer (vm, bi0);
855 ip0 = vlib_buffer_get_current (b0);
856
857 /* dst lookup was done by ip6 lookup */
858 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
859 lkd0 = lookup_dpo_get(lkdi0);
860
861 /*
862 * choose between a lookup using the fib index in the DPO
863 * or getting the FIB index from the interface.
864 */
865 if (table_from_interface)
866 {
867 fib_index0 =
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000868 ip6_fib_table_get_index_for_sw_if_index(
Neale Rannsd3b85b02016-10-22 15:17:21 -0700869 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
870 }
871 else
872 {
873 fib_index0 = lkd0->lkd_fib_index;
874 }
875
876 /*
877 * choose between a source or destination address lookup in the table
878 */
879 if (input_src_addr)
880 {
881 input_addr0 = &ip0->src_address;
882 }
883 else
884 {
885 input_addr0 = &ip0->dst_address;
886 }
887
888 /* do src lookup */
889 lbi0 = ip6_fib_table_fwding_lookup(&ip6_main,
890 fib_index0,
891 input_addr0);
892 lb0 = load_balance_get(lbi0);
Neale Ranns5e575b12016-10-03 09:40:25 +0100893
Neale Rannscb630ff2016-12-14 13:31:29 +0100894 vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
895
Neale Ranns5e575b12016-10-03 09:40:25 +0100896 /* Use flow hash to compute multipath adjacency. */
897 hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
898
899 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Neale Rannsd3b85b02016-10-22 15:17:21 -0700900 {
Neale Ranns5e575b12016-10-03 09:40:25 +0100901 flow_hash_config0 = lb0->lb_hash_config;
902 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
903 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsd3b85b02016-10-22 15:17:21 -0700904 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100905
906 dpo0 = load_balance_get_bucket_i(lb0,
907 (hash_c0 &
908 (lb0->lb_n_buckets_minus_1)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100909
Neale Rannsd3b85b02016-10-22 15:17:21 -0700910 next0 = dpo0->dpoi_next_node;
911 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100912
Neale Rannsd3b85b02016-10-22 15:17:21 -0700913 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200914 (cm, thread_index, lbi0, 1,
Neale Rannsd3b85b02016-10-22 15:17:21 -0700915 vlib_buffer_length_in_chain (vm, b0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100916
Neale Rannsd3b85b02016-10-22 15:17:21 -0700917 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
918 {
919 lookup_trace_t *tr = vlib_add_trace (vm, node,
920 b0, sizeof (*tr));
921 tr->fib_index = fib_index0;
922 tr->lbi = lbi0;
923 tr->addr.ip6 = *input_addr0;
924 }
925 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
926 n_left_to_next, bi0, next0);
927 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100928 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
929 }
930 return from_frame->n_vectors;
931}
932
Damjan Marion2574d9f2018-06-26 14:45:49 +0200933static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100934lookup_ip6_dst (vlib_main_t * vm,
935 vlib_node_runtime_t * node,
936 vlib_frame_t * from_frame)
937{
Billy McFallcfcf1e22016-10-14 09:51:49 -0400938 return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100939}
940
941VLIB_REGISTER_NODE (lookup_ip6_dst_node) = {
942 .function = lookup_ip6_dst,
943 .name = "lookup-ip6-dst",
944 .vector_size = sizeof (u32),
945 .format_trace = format_lookup_trace,
946 .sibling_of = "ip6-lookup",
947};
948VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_node, lookup_ip6_dst)
949
Damjan Marion2574d9f2018-06-26 14:45:49 +0200950static uword
Billy McFallcfcf1e22016-10-14 09:51:49 -0400951lookup_ip6_dst_itf (vlib_main_t * vm,
952 vlib_node_runtime_t * node,
953 vlib_frame_t * from_frame)
954{
955 return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 1));
956}
957
958VLIB_REGISTER_NODE (lookup_ip6_dst_itf_node) = {
959 .function = lookup_ip6_dst_itf,
960 .name = "lookup-ip6-dst-itf",
961 .vector_size = sizeof (u32),
962 .format_trace = format_lookup_trace,
963 .sibling_of = "ip6-lookup",
964};
965VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_itf_node, lookup_ip6_dst_itf)
966
Damjan Marion2574d9f2018-06-26 14:45:49 +0200967static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100968lookup_ip6_src (vlib_main_t * vm,
969 vlib_node_runtime_t * node,
970 vlib_frame_t * from_frame)
971{
Billy McFallcfcf1e22016-10-14 09:51:49 -0400972 return (lookup_dpo_ip6_inline(vm, node, from_frame, 1, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100973}
974
975VLIB_REGISTER_NODE (lookup_ip6_src_node) = {
976 .function = lookup_ip6_src,
977 .name = "lookup-ip6-src",
978 .vector_size = sizeof (u32),
979 .format_trace = format_lookup_trace,
980 .sibling_of = "ip6-lookup",
981};
982VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_src_node, lookup_ip6_src)
983
984always_inline uword
985lookup_dpo_mpls_inline (vlib_main_t * vm,
986 vlib_node_runtime_t * node,
987 vlib_frame_t * from_frame,
988 int table_from_interface)
989{
990 u32 n_left_from, next_index, * from, * to_next;
Damjan Marion586afd72017-04-05 19:18:20 +0200991 u32 thread_index = vlib_get_thread_index();
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100992 vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
993
994 from = vlib_frame_vector_args (from_frame);
995 n_left_from = from_frame->n_vectors;
996
997 next_index = node->cached_next_index;
998
999 while (n_left_from > 0)
1000 {
1001 u32 n_left_to_next;
1002
1003 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
1004
1005 /* while (n_left_from >= 4 && n_left_to_next >= 2) */
1006 /* } */
1007
1008 while (n_left_from > 0 && n_left_to_next > 0)
1009 {
Neale Ranns6af1c042017-05-26 03:48:53 -07001010 u32 bi0, lkdi0, lbi0, fib_index0, next0, hash0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001011 const mpls_unicast_header_t * hdr0;
1012 const load_balance_t *lb0;
1013 const lookup_dpo_t * lkd0;
1014 const dpo_id_t *dpo0;
1015 vlib_buffer_t * b0;
1016
1017 bi0 = from[0];
1018 to_next[0] = bi0;
1019 from += 1;
1020 to_next += 1;
1021 n_left_from -= 1;
1022 n_left_to_next -= 1;
1023
1024 b0 = vlib_get_buffer (vm, bi0);
1025 hdr0 = vlib_buffer_get_current (b0);
1026
1027 /* dst lookup was done by mpls lookup */
1028 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
1029 lkd0 = lookup_dpo_get(lkdi0);
1030
1031 /*
1032 * choose between a lookup using the fib index in the DPO
1033 * or getting the FIB index from the interface.
1034 */
1035 if (table_from_interface)
1036 {
1037 fib_index0 =
1038 mpls_fib_table_get_index_for_sw_if_index(
1039 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
1040 }
1041 else
1042 {
1043 fib_index0 = lkd0->lkd_fib_index;
1044 }
1045
1046 /* do lookup */
1047 lbi0 = mpls_fib_table_forwarding_lookup (fib_index0, hdr0);
1048 lb0 = load_balance_get(lbi0);
1049 dpo0 = load_balance_get_bucket_i(lb0, 0);
1050
1051 next0 = dpo0->dpoi_next_node;
1052 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
1053
Neale Ranns6af1c042017-05-26 03:48:53 -07001054
1055 if (MPLS_IS_REPLICATE & lbi0)
1056 {
1057 next0 = mpls_lookup_to_replicate_edge;
1058 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1059 (lbi0 & ~MPLS_IS_REPLICATE);
1060 }
1061 else
1062 {
1063 lb0 = load_balance_get(lbi0);
1064 ASSERT (lb0->lb_n_buckets > 0);
1065 ASSERT (is_pow2 (lb0->lb_n_buckets));
1066
1067 if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
1068 {
1069 hash0 = vnet_buffer (b0)->ip.flow_hash =
1070 mpls_compute_flow_hash(hdr0, lb0->lb_hash_config);
1071 dpo0 = load_balance_get_fwd_bucket
1072 (lb0,
1073 (hash0 & (lb0->lb_n_buckets_minus_1)));
1074 }
1075 else
1076 {
1077 dpo0 = load_balance_get_bucket_i (lb0, 0);
1078 }
1079 next0 = dpo0->dpoi_next_node;
1080
1081 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
1082
1083 vlib_increment_combined_counter
1084 (cm, thread_index, lbi0, 1,
1085 vlib_buffer_length_in_chain (vm, b0));
1086 }
1087
1088 vnet_buffer (b0)->mpls.ttl = ((char*)hdr0)[3];
1089 vnet_buffer (b0)->mpls.exp = (((char*)hdr0)[2] & 0xe) >> 1;
1090 vnet_buffer (b0)->mpls.first = 1;
1091 vlib_buffer_advance(b0, sizeof(*hdr0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001092
1093 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1094 {
1095 lookup_trace_t *tr = vlib_add_trace (vm, node,
1096 b0, sizeof (*tr));
1097 tr->fib_index = fib_index0;
1098 tr->lbi = lbi0;
1099 tr->hdr = *hdr0;
1100 }
1101
1102 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
1103 n_left_to_next, bi0, next0);
1104 }
1105 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1106 }
1107 return from_frame->n_vectors;
1108}
1109
1110static u8 *
1111format_lookup_mpls_trace (u8 * s, va_list * args)
1112{
1113 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1114 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1115 lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001116 u32 indent = format_get_indent (s);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001117 mpls_unicast_header_t hdr;
1118
1119 hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
1120
1121 s = format (s, "%U fib-index:%d hdr:%U load-balance:%d",
1122 format_white_space, indent,
1123 t->fib_index,
1124 format_mpls_header, hdr,
1125 t->lbi);
1126 return s;
1127}
1128
Damjan Marion2574d9f2018-06-26 14:45:49 +02001129static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001130lookup_mpls_dst (vlib_main_t * vm,
1131 vlib_node_runtime_t * node,
1132 vlib_frame_t * from_frame)
1133{
1134 return (lookup_dpo_mpls_inline(vm, node, from_frame, 0));
1135}
1136
1137VLIB_REGISTER_NODE (lookup_mpls_dst_node) = {
1138 .function = lookup_mpls_dst,
1139 .name = "lookup-mpls-dst",
1140 .vector_size = sizeof (u32),
1141 .sibling_of = "mpls-lookup",
1142 .format_trace = format_lookup_mpls_trace,
1143 .n_next_nodes = 0,
1144};
1145VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_node, lookup_mpls_dst)
1146
Damjan Marion2574d9f2018-06-26 14:45:49 +02001147static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001148lookup_mpls_dst_itf (vlib_main_t * vm,
1149 vlib_node_runtime_t * node,
1150 vlib_frame_t * from_frame)
1151{
1152 return (lookup_dpo_mpls_inline(vm, node, from_frame, 1));
1153}
1154
1155VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = {
1156 .function = lookup_mpls_dst_itf,
1157 .name = "lookup-mpls-dst-itf",
1158 .vector_size = sizeof (u32),
1159 .sibling_of = "mpls-lookup",
1160 .format_trace = format_lookup_mpls_trace,
1161 .n_next_nodes = 0,
1162};
1163VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_itf_node, lookup_mpls_dst_itf)
1164
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001165typedef enum lookup_ip_dst_mcast_next_t_ {
1166 LOOKUP_IP_DST_MCAST_NEXT_RPF,
1167 LOOKUP_IP_DST_MCAST_N_NEXT,
1168} mfib_forward_lookup_next_t;
1169
1170always_inline uword
1171lookup_dpo_ip_dst_mcast_inline (vlib_main_t * vm,
1172 vlib_node_runtime_t * node,
1173 vlib_frame_t * from_frame,
1174 int is_v4)
1175{
1176 u32 n_left_from, next_index, * from, * to_next;
1177
1178 from = vlib_frame_vector_args (from_frame);
1179 n_left_from = from_frame->n_vectors;
1180
1181 next_index = LOOKUP_IP_DST_MCAST_NEXT_RPF;
1182
1183 while (n_left_from > 0)
1184 {
1185 u32 n_left_to_next;
1186
1187 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
1188
1189 /* while (n_left_from >= 4 && n_left_to_next >= 2) */
1190 /* } */
1191
1192 while (n_left_from > 0 && n_left_to_next > 0)
1193 {
1194 u32 bi0, lkdi0, fib_index0, next0;
1195 const lookup_dpo_t * lkd0;
1196 fib_node_index_t mfei0;
1197 vlib_buffer_t * b0;
1198
1199 bi0 = from[0];
1200 to_next[0] = bi0;
1201 from += 1;
1202 to_next += 1;
1203 n_left_from -= 1;
1204 n_left_to_next -= 1;
1205
1206 b0 = vlib_get_buffer (vm, bi0);
1207
1208 /* dst lookup was done by mpls lookup */
1209 lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
1210 lkd0 = lookup_dpo_get(lkdi0);
1211 fib_index0 = lkd0->lkd_fib_index;
1212 next0 = LOOKUP_IP_DST_MCAST_NEXT_RPF;
1213
1214 if (is_v4)
1215 {
1216 ip4_header_t * ip0;
1217
1218 ip0 = vlib_buffer_get_current (b0);
1219 mfei0 = ip4_mfib_table_lookup(ip4_mfib_get(fib_index0),
1220 &ip0->src_address,
1221 &ip0->dst_address,
1222 64);
1223 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1224 {
1225 lookup_trace_t *tr = vlib_add_trace (vm, node,
1226 b0, sizeof (*tr));
1227 tr->fib_index = fib_index0;
1228 tr->lbi = mfei0;
1229 tr->addr.ip4 = ip0->dst_address;
1230 }
1231 }
1232 else
1233 {
1234 ip6_header_t * ip0;
1235
1236 ip0 = vlib_buffer_get_current (b0);
1237 mfei0 = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index0),
1238 &ip0->src_address,
1239 &ip0->dst_address);
1240 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1241 {
1242 lookup_trace_t *tr = vlib_add_trace (vm, node,
1243 b0, sizeof (*tr));
1244 tr->fib_index = fib_index0;
1245 tr->lbi = mfei0;
1246 tr->addr.ip6 = ip0->dst_address;
1247 }
1248 }
1249
1250 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = mfei0;
1251
Neale Ranns31426c62017-05-24 10:32:58 -07001252 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001253 n_left_to_next, bi0, next0);
1254 }
1255 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1256 }
1257 return from_frame->n_vectors;
1258}
1259
Damjan Marion2574d9f2018-06-26 14:45:49 +02001260static uword
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001261lookup_ip4_dst_mcast (vlib_main_t * vm,
1262 vlib_node_runtime_t * node,
1263 vlib_frame_t * from_frame)
1264{
1265 return (lookup_dpo_ip_dst_mcast_inline(vm, node, from_frame, 1));
1266}
1267
1268VLIB_REGISTER_NODE (lookup_ip4_dst_mcast_node) = {
1269 .function = lookup_ip4_dst_mcast,
1270 .name = "lookup-ip4-dst-mcast",
1271 .vector_size = sizeof (u32),
1272
1273 .format_trace = format_lookup_trace,
1274 .n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
1275 .next_nodes = {
1276 [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip4-mfib-forward-rpf",
1277 },
1278};
1279VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_mcast_node,
1280 lookup_ip4_dst_mcast)
1281
Damjan Marion2574d9f2018-06-26 14:45:49 +02001282static uword
Neale Ranns31426c62017-05-24 10:32:58 -07001283lookup_ip6_dst_mcast (vlib_main_t * vm,
1284 vlib_node_runtime_t * node,
1285 vlib_frame_t * from_frame)
1286{
1287 return (lookup_dpo_ip_dst_mcast_inline(vm, node, from_frame, 0));
1288}
1289
1290VLIB_REGISTER_NODE (lookup_ip6_dst_mcast_node) = {
1291 .function = lookup_ip6_dst_mcast,
1292 .name = "lookup-ip6-dst-mcast",
1293 .vector_size = sizeof (u32),
1294
1295 .format_trace = format_lookup_trace,
1296 .n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
1297 .next_nodes = {
1298 [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip6-mfib-forward-rpf",
1299 },
1300};
1301VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip6_dst_mcast_node,
1302 lookup_ip6_dst_mcast)
1303
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001304static void
1305lookup_dpo_mem_show (void)
1306{
1307 fib_show_memory_usage("Lookup",
1308 pool_elts(lookup_dpo_pool),
1309 pool_len(lookup_dpo_pool),
1310 sizeof(lookup_dpo_t));
1311}
1312
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001313const static dpo_vft_t lkd_vft = {
1314 .dv_lock = lookup_dpo_lock,
1315 .dv_unlock = lookup_dpo_unlock,
1316 .dv_format = format_lookup_dpo,
1317};
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001318const static dpo_vft_t lkd_vft_w_mem_show = {
1319 .dv_lock = lookup_dpo_lock,
1320 .dv_unlock = lookup_dpo_unlock,
1321 .dv_format = format_lookup_dpo,
1322 .dv_mem_show = lookup_dpo_mem_show,
1323};
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001324
1325const static char* const lookup_src_ip4_nodes[] =
1326{
1327 "lookup-ip4-src",
1328 NULL,
1329};
1330const static char* const lookup_src_ip6_nodes[] =
1331{
1332 "lookup-ip6-src",
1333 NULL,
1334};
1335const static char* const * const lookup_src_nodes[DPO_PROTO_NUM] =
1336{
1337 [DPO_PROTO_IP4] = lookup_src_ip4_nodes,
1338 [DPO_PROTO_IP6] = lookup_src_ip6_nodes,
1339 [DPO_PROTO_MPLS] = NULL,
1340};
1341
1342const static char* const lookup_dst_ip4_nodes[] =
1343{
1344 "lookup-ip4-dst",
1345 NULL,
1346};
1347const static char* const lookup_dst_ip6_nodes[] =
1348{
1349 "lookup-ip6-dst",
1350 NULL,
1351};
1352const static char* const lookup_dst_mpls_nodes[] =
1353{
1354 "lookup-mpls-dst",
1355 NULL,
1356};
1357const static char* const * const lookup_dst_nodes[DPO_PROTO_NUM] =
1358{
1359 [DPO_PROTO_IP4] = lookup_dst_ip4_nodes,
1360 [DPO_PROTO_IP6] = lookup_dst_ip6_nodes,
1361 [DPO_PROTO_MPLS] = lookup_dst_mpls_nodes,
1362};
1363
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001364const static char* const lookup_dst_mcast_ip4_nodes[] =
1365{
1366 "lookup-ip4-dst-mcast",
1367 NULL,
1368};
1369const static char* const lookup_dst_mcast_ip6_nodes[] =
1370{
1371 "lookup-ip6-dst-mcast",
1372 NULL,
1373};
1374const static char* const * const lookup_dst_mcast_nodes[DPO_PROTO_NUM] =
1375{
1376 [DPO_PROTO_IP4] = lookup_dst_mcast_ip4_nodes,
1377 [DPO_PROTO_IP6] = lookup_dst_mcast_ip6_nodes,
1378};
1379
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001380const static char* const lookup_dst_from_interface_ip4_nodes[] =
1381{
1382 "lookup-ip4-dst-itf",
1383 NULL,
1384};
1385const static char* const lookup_dst_from_interface_ip6_nodes[] =
1386{
1387 "lookup-ip6-dst-itf",
1388 NULL,
1389};
1390const static char* const lookup_dst_from_interface_mpls_nodes[] =
1391{
1392 "lookup-mpls-dst-itf",
1393 NULL,
1394};
1395const static char* const * const lookup_dst_from_interface_nodes[DPO_PROTO_NUM] =
1396{
1397 [DPO_PROTO_IP4] = lookup_dst_from_interface_ip4_nodes,
1398 [DPO_PROTO_IP6] = lookup_dst_from_interface_ip6_nodes,
1399 [DPO_PROTO_MPLS] = lookup_dst_from_interface_mpls_nodes,
1400};
1401
1402
1403void
1404lookup_dpo_module_init (void)
1405{
Neale Ranns6c3ebcc2016-10-02 21:20:15 +01001406 dpo_register(DPO_LOOKUP, &lkd_vft_w_mem_show, NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001407
1408 /*
1409 * There are various sorts of lookup; src or dst addr v4 /v6 etc.
1410 * there isn't an object type for each (there is only the lookup_dpo_t),
1411 * but, for performance reasons, there is a data plane function, and hence
1412 * VLIB node for each. VLIB graph node construction is based on DPO types
1413 * so we create sub-types.
1414 */
1415 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC] =
1416 dpo_register_new_type(&lkd_vft, lookup_src_nodes);
1417 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST] =
1418 dpo_register_new_type(&lkd_vft, lookup_dst_nodes);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001419 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_MCAST] =
1420 dpo_register_new_type(&lkd_vft, lookup_dst_mcast_nodes);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001421 lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE] =
Billy McFallcfcf1e22016-10-14 09:51:49 -04001422 dpo_register_new_type(&lkd_vft, lookup_dst_from_interface_nodes);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001423}