Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <lb/lb.h>
17 : #include <vnet/fib/ip4_fib.h>
18 :
19 : #include <vnet/gre/packet.h>
20 : #include <lb/lbhash.h>
21 :
22 : #define foreach_lb_error \
23 : _(NONE, "no error") \
24 : _(PROTO_NOT_SUPPORTED, "protocol not supported")
25 :
26 : typedef enum
27 : {
28 : #define _(sym,str) LB_ERROR_##sym,
29 : foreach_lb_error
30 : #undef _
31 : LB_N_ERROR,
32 : } lb_error_t;
33 :
34 : static char *lb_error_strings[] =
35 : {
36 : #define _(sym,string) string,
37 : foreach_lb_error
38 : #undef _
39 : };
40 :
41 : typedef struct
42 : {
43 : u32 vip_index;
44 : u32 as_index;
45 : } lb_trace_t;
46 :
47 : typedef struct
48 : {
49 : u32 vip_index;
50 :
51 : u32 node_port;
52 : } lb_nodeport_trace_t;
53 :
54 : typedef struct
55 : {
56 : u32 vip_index;
57 : u32 as_index;
58 : u32 rx_sw_if_index;
59 : u32 next_index;
60 : } lb_nat_trace_t;
61 :
62 : u8 *
63 1400 : format_lb_trace (u8 * s, va_list * args)
64 : {
65 1400 : lb_main_t *lbm = &lb_main;
66 1400 : CLIB_UNUSED(vlib_main_t * vm)
67 : = va_arg (*args, vlib_main_t *);
68 1400 : CLIB_UNUSED(vlib_node_t * node)
69 : = va_arg (*args, vlib_node_t *);
70 1400 : lb_trace_t *t = va_arg (*args, lb_trace_t *);
71 1400 : if (pool_is_free_index(lbm->vips, t->vip_index))
72 : {
73 0 : s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
74 : }
75 : else
76 : {
77 1400 : s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
78 1400 : &lbm->vips[t->vip_index]);
79 : }
80 1400 : if (pool_is_free_index(lbm->ass, t->as_index))
81 : {
82 0 : s = format (s, "lb as[%d]: This AS was freed since capture\n");
83 : }
84 : else
85 : {
86 1400 : s = format (s, "lb as[%d]: %U\n", t->as_index, format_lb_as,
87 1400 : &lbm->ass[t->as_index]);
88 : }
89 1400 : return s;
90 : }
91 :
92 : u8 *
93 0 : format_lb_nat_trace (u8 * s, va_list * args)
94 : {
95 0 : lb_main_t *lbm = &lb_main;
96 0 : CLIB_UNUSED(vlib_main_t * vm)
97 : = va_arg (*args, vlib_main_t *);
98 0 : CLIB_UNUSED(vlib_node_t * node)
99 : = va_arg (*args, vlib_node_t *);
100 0 : lb_nat_trace_t *t = va_arg (*args, lb_nat_trace_t *);
101 :
102 0 : if (pool_is_free_index(lbm->vips, t->vip_index))
103 : {
104 0 : s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
105 : }
106 : else
107 : {
108 0 : s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
109 0 : &lbm->vips[t->vip_index]);
110 : }
111 0 : if (pool_is_free_index(lbm->ass, t->as_index))
112 : {
113 0 : s = format (s, "lb as[%d]: This AS was freed since capture\n");
114 : }
115 : else
116 : {
117 0 : s = format (s, "lb as[%d]: %U\n", t->as_index, format_lb_as,
118 0 : &lbm->ass[t->as_index]);
119 : }
120 0 : s = format (s, "lb nat: rx_sw_if_index = %d, next_index = %d",
121 : t->rx_sw_if_index, t->next_index);
122 :
123 0 : return s;
124 : }
125 :
126 : lb_hash_t *
127 14 : lb_get_sticky_table (u32 thread_index)
128 : {
129 14 : lb_main_t *lbm = &lb_main;
130 14 : lb_hash_t *sticky_ht = lbm->per_cpu[thread_index].sticky_ht;
131 : //Check if size changed
132 14 : if (PREDICT_FALSE(
133 : sticky_ht && (lbm->per_cpu_sticky_buckets != lb_hash_nbuckets(sticky_ht))))
134 : {
135 : //Dereference everything in there
136 : lb_hash_bucket_t *b;
137 : u32 i;
138 0 : lb_hash_foreach_entry(sticky_ht, b, i)
139 : {
140 0 : vlib_refcount_add (&lbm->as_refcount, thread_index, b->value[i], -1);
141 0 : vlib_refcount_add (&lbm->as_refcount, thread_index, 0, 1);
142 : }
143 :
144 0 : lb_hash_free (sticky_ht);
145 0 : sticky_ht = NULL;
146 : }
147 :
148 : //Create if necessary
149 14 : if (PREDICT_FALSE(sticky_ht == NULL))
150 : {
151 14 : lbm->per_cpu[thread_index].sticky_ht = lb_hash_alloc (
152 : lbm->per_cpu_sticky_buckets, lbm->flow_timeout);
153 14 : sticky_ht = lbm->per_cpu[thread_index].sticky_ht;
154 14 : clib_warning("Regenerated sticky table %p", sticky_ht);
155 : }
156 :
157 14 : ASSERT(sticky_ht);
158 :
159 : //Update timeout
160 14 : sticky_ht->timeout = lbm->flow_timeout;
161 14 : return sticky_ht;
162 : }
163 :
164 : u64
165 0 : lb_node_get_other_ports4 (ip4_header_t *ip40)
166 : {
167 0 : return 0;
168 : }
169 :
170 : u64
171 0 : lb_node_get_other_ports6 (ip6_header_t *ip60)
172 : {
173 0 : return 0;
174 : }
175 :
176 : static_always_inline void
177 1400 : lb_node_get_hash (lb_main_t *lbm, vlib_buffer_t *p, u8 is_input_v4, u32 *hash,
178 : u32 *vip_idx, u8 per_port_vip)
179 : {
180 : vip_port_key_t key;
181 : clib_bihash_kv_8_8_t kv, value;
182 : ip4_header_t *ip40;
183 : ip6_header_t *ip60;
184 : lb_vip_t *vip0;
185 : u64 ports;
186 :
187 : /* For vip case, retrieve vip index for ip lookup */
188 1400 : *vip_idx = vnet_buffer (p)->ip.adj_index[VLIB_TX];
189 :
190 : /* Extract the L4 port number from the packet */
191 1400 : if (is_input_v4)
192 : {
193 900 : ip40 = vlib_buffer_get_current (p);
194 900 : if (PREDICT_TRUE(
195 : ip40->protocol == IP_PROTOCOL_TCP
196 : || ip40->protocol == IP_PROTOCOL_UDP))
197 900 : ports = ((u64) ((udp_header_t *) (ip40 + 1))->src_port << 16)
198 900 : | ((u64) ((udp_header_t *) (ip40 + 1))->dst_port);
199 : else
200 0 : ports = lb_node_get_other_ports4 (ip40);
201 : }
202 : else
203 : {
204 500 : ip60 = vlib_buffer_get_current (p);
205 :
206 500 : if (PREDICT_TRUE(
207 : ip60->protocol == IP_PROTOCOL_TCP
208 : || ip60->protocol == IP_PROTOCOL_UDP))
209 500 : ports = ((u64) ((udp_header_t *) (ip60 + 1))->src_port << 16)
210 500 : | ((u64) ((udp_header_t *) (ip60 + 1))->dst_port);
211 : else
212 0 : ports = lb_node_get_other_ports6 (ip60);
213 : }
214 :
215 1400 : if (per_port_vip)
216 : {
217 : /* For per-port-vip case, ip lookup stores placeholder index */
218 800 : key.vip_prefix_index = *vip_idx;
219 800 : key.port = (u16) (ports & 0xFFFF);
220 800 : key.rsv = 0;
221 800 : if (is_input_v4)
222 : {
223 500 : key.protocol = ip40->protocol;
224 : }
225 : else
226 : {
227 300 : key.protocol = ip60->protocol;
228 : }
229 :
230 : /* For per-port-vip case, retrieve vip index for vip_port_filter table */
231 800 : kv.key = key.as_u64;
232 800 : if (clib_bihash_search_8_8 (&lbm->vip_index_per_port, &kv, &value) < 0)
233 : {
234 : /* Set default vip */
235 0 : *vip_idx = 0;
236 : }
237 : else
238 : {
239 800 : *vip_idx = value.value;
240 : }
241 : }
242 :
243 1400 : vip0 = pool_elt_at_index (lbm->vips, *vip_idx);
244 :
245 1400 : if (is_input_v4)
246 : {
247 900 : if (lb_vip_is_src_ip_sticky (vip0))
248 : {
249 200 : *hash = lb_hash_hash (*((u64 *) &ip40->address_pair), 0, 0, 0, 0);
250 : }
251 : else
252 : {
253 700 : *hash =
254 700 : lb_hash_hash (*((u64 *) &ip40->address_pair), ports, 0, 0, 0);
255 : }
256 : }
257 : else
258 : {
259 500 : if (lb_vip_is_src_ip_sticky (vip0))
260 : {
261 0 : *hash = lb_hash_hash (
262 : ip60->src_address.as_u64[0], ip60->src_address.as_u64[1],
263 : ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], 0);
264 : }
265 : else
266 : {
267 500 : *hash = lb_hash_hash (
268 : ip60->src_address.as_u64[0], ip60->src_address.as_u64[1],
269 : ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], ports);
270 : }
271 : }
272 1400 : }
273 :
274 : /* clang-format off */
275 : static_always_inline uword
276 14 : lb_node_fn (vlib_main_t * vm,
277 : vlib_node_runtime_t * node,
278 : vlib_frame_t * frame,
279 : u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6)
280 : lb_encap_type_t encap_type, //Compile-time parameter is GRE4/GRE6/L3DSR/NAT4/NAT6
281 : u8 per_port_vip) //Compile-time parameter stating that is per_port_vip or not
282 : {
283 14 : lb_main_t *lbm = &lb_main;
284 : u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
285 14 : u32 thread_index = vm->thread_index;
286 14 : u32 lb_time = lb_hash_time_now (vm);
287 :
288 14 : lb_hash_t *sticky_ht = lb_get_sticky_table (thread_index);
289 14 : from = vlib_frame_vector_args (frame);
290 14 : n_left_from = frame->n_vectors;
291 14 : next_index = node->cached_next_index;
292 :
293 14 : u32 nexthash0 = 0;
294 14 : u32 next_vip_idx0 = ~0;
295 14 : if (PREDICT_TRUE(n_left_from > 0))
296 : {
297 14 : vlib_buffer_t *p0 = vlib_get_buffer (vm, from[0]);
298 14 : lb_node_get_hash (lbm, p0, is_input_v4, &nexthash0,
299 : &next_vip_idx0, per_port_vip);
300 : }
301 :
302 28 : while (n_left_from > 0)
303 : {
304 14 : vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
305 1414 : while (n_left_from > 0 && n_left_to_next > 0)
306 : {
307 : u32 pi0;
308 : vlib_buffer_t *p0;
309 : lb_vip_t *vip0;
310 1400 : u32 asindex0 = 0;
311 : u16 len0;
312 : u32 available_index0;
313 1400 : u8 counter = 0;
314 1400 : u32 hash0 = nexthash0;
315 1400 : u32 vip_index0 = next_vip_idx0;
316 : u32 next0;
317 :
318 1400 : if (PREDICT_TRUE(n_left_from > 1))
319 : {
320 1386 : vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]);
321 : //Compute next hash and prefetch bucket
322 1386 : lb_node_get_hash (lbm, p1, is_input_v4,
323 : &nexthash0, &next_vip_idx0,
324 : per_port_vip);
325 1386 : lb_hash_prefetch_bucket (sticky_ht, nexthash0);
326 : //Prefetch for encap, next
327 1386 : CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE);
328 : }
329 :
330 1400 : if (PREDICT_TRUE(n_left_from > 2))
331 : {
332 : vlib_buffer_t *p2;
333 1372 : p2 = vlib_get_buffer (vm, from[2]);
334 : /* prefetch packet header and data */
335 1372 : vlib_prefetch_buffer_header(p2, STORE);
336 1372 : CLIB_PREFETCH(vlib_buffer_get_current (p2), 64, STORE);
337 : }
338 :
339 1400 : pi0 = to_next[0] = from[0];
340 1400 : from += 1;
341 1400 : n_left_from -= 1;
342 1400 : to_next += 1;
343 1400 : n_left_to_next -= 1;
344 :
345 1400 : p0 = vlib_get_buffer (vm, pi0);
346 :
347 1400 : vip0 = pool_elt_at_index(lbm->vips, vip_index0);
348 :
349 1400 : if (is_input_v4)
350 : {
351 : ip4_header_t *ip40;
352 900 : ip40 = vlib_buffer_get_current (p0);
353 900 : len0 = clib_net_to_host_u16 (ip40->length);
354 : }
355 : else
356 : {
357 : ip6_header_t *ip60;
358 500 : ip60 = vlib_buffer_get_current (p0);
359 500 : len0 = clib_net_to_host_u16 (ip60->payload_length)
360 : + sizeof(ip6_header_t);
361 : }
362 :
363 1400 : lb_hash_get (sticky_ht, hash0,
364 : vip_index0, lb_time,
365 : &available_index0, &asindex0);
366 :
367 1400 : if (PREDICT_TRUE(asindex0 != 0))
368 : {
369 : //Found an existing entry
370 100 : counter = LB_VIP_COUNTER_NEXT_PACKET;
371 : }
372 1300 : else if (PREDICT_TRUE(available_index0 != ~0))
373 : {
374 : //There is an available slot for a new flow
375 1300 : asindex0 =
376 1300 : vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index;
377 1300 : counter = LB_VIP_COUNTER_FIRST_PACKET;
378 1300 : counter = (asindex0 == 0) ? LB_VIP_COUNTER_NO_SERVER : counter;
379 :
380 : //TODO: There are race conditions with as0 and vip0 manipulation.
381 : //Configuration may be changed, vectors resized, etc...
382 :
383 : //Dereference previously used
384 1300 : vlib_refcount_add (
385 : &lbm->as_refcount, thread_index,
386 : lb_hash_available_value (sticky_ht, hash0, available_index0),
387 : -1);
388 1300 : vlib_refcount_add (&lbm->as_refcount, thread_index, asindex0, 1);
389 :
390 : //Add sticky entry
391 : //Note that when there is no AS configured, an entry is configured anyway.
392 : //But no configured AS is not something that should happen
393 1300 : lb_hash_put (sticky_ht, hash0, asindex0,
394 : vip_index0,
395 : available_index0, lb_time);
396 : }
397 : else
398 : {
399 : //Could not store new entry in the table
400 0 : asindex0 =
401 0 : vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index;
402 0 : counter = LB_VIP_COUNTER_UNTRACKED_PACKET;
403 : }
404 :
405 1400 : vlib_increment_simple_counter (
406 1400 : &lbm->vip_counters[counter], thread_index,
407 : vip_index0,
408 : 1);
409 :
410 : //Now let's encap
411 1400 : if ((encap_type == LB_ENCAP_TYPE_GRE4)
412 1000 : || (encap_type == LB_ENCAP_TYPE_GRE6))
413 800 : {
414 : gre_header_t *gre0;
415 800 : if (encap_type == LB_ENCAP_TYPE_GRE4) /* encap GRE4*/
416 : {
417 : ip4_header_t *ip40;
418 400 : vlib_buffer_advance (
419 : p0, -sizeof(ip4_header_t) - sizeof(gre_header_t));
420 400 : ip40 = vlib_buffer_get_current (p0);
421 400 : gre0 = (gre_header_t *) (ip40 + 1);
422 400 : ip40->src_address = lbm->ip4_src_address;
423 400 : ip40->dst_address = lbm->ass[asindex0].address.ip4;
424 400 : ip40->ip_version_and_header_length = 0x45;
425 400 : ip40->ttl = 128;
426 400 : ip40->fragment_id = 0;
427 400 : ip40->flags_and_fragment_offset = 0;
428 800 : ip40->length = clib_host_to_net_u16 (
429 400 : len0 + sizeof(gre_header_t) + sizeof(ip4_header_t));
430 400 : ip40->protocol = IP_PROTOCOL_GRE;
431 400 : ip40->checksum = ip4_header_checksum (ip40);
432 : }
433 : else /* encap GRE6*/
434 : {
435 : ip6_header_t *ip60;
436 400 : vlib_buffer_advance (
437 : p0, -sizeof(ip6_header_t) - sizeof(gre_header_t));
438 400 : ip60 = vlib_buffer_get_current (p0);
439 400 : gre0 = (gre_header_t *) (ip60 + 1);
440 400 : ip60->dst_address = lbm->ass[asindex0].address.ip6;
441 400 : ip60->src_address = lbm->ip6_src_address;
442 400 : ip60->hop_limit = 128;
443 400 : ip60->ip_version_traffic_class_and_flow_label =
444 400 : clib_host_to_net_u32 (0x6 << 28);
445 800 : ip60->payload_length = clib_host_to_net_u16 (
446 400 : len0 + sizeof(gre_header_t));
447 400 : ip60->protocol = IP_PROTOCOL_GRE;
448 : }
449 :
450 800 : gre0->flags_and_version = 0;
451 1600 : gre0->protocol =
452 : (is_input_v4) ?
453 400 : clib_host_to_net_u16 (0x0800) :
454 400 : clib_host_to_net_u16 (0x86DD);
455 : }
456 600 : else if (encap_type == LB_ENCAP_TYPE_L3DSR) /* encap L3DSR*/
457 : {
458 : ip4_header_t *ip40;
459 : ip_csum_t csum;
460 : u32 old_dst, new_dst;
461 : u8 old_tos, new_tos;
462 :
463 400 : ip40 = vlib_buffer_get_current (p0);
464 400 : old_dst = ip40->dst_address.as_u32;
465 400 : new_dst = lbm->ass[asindex0].address.ip4.as_u32;
466 400 : ip40->dst_address.as_u32 = lbm->ass[asindex0].address.ip4.as_u32;
467 : /* Get and rewrite DSCP bit */
468 400 : old_tos = ip40->tos;
469 400 : new_tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2);
470 400 : ip40->tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2);
471 :
472 400 : csum = ip40->checksum;
473 400 : csum = ip_csum_update (csum, old_tos, new_tos,
474 : ip4_header_t,
475 : tos /* changed member */);
476 400 : csum = ip_csum_update (csum, old_dst, new_dst,
477 : ip4_header_t,
478 : dst_address /* changed member */);
479 400 : ip40->checksum = ip_csum_fold (csum);
480 :
481 : /* Recomputing L4 checksum after dst-IP modifying */
482 400 : if (ip40->protocol == IP_PROTOCOL_TCP)
483 : {
484 : tcp_header_t *th0;
485 0 : th0 = ip4_next_header (ip40);
486 0 : th0->checksum = 0;
487 0 : th0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40);
488 : }
489 400 : else if (ip40->protocol == IP_PROTOCOL_UDP)
490 : {
491 : udp_header_t *uh0;
492 400 : uh0 = ip4_next_header (ip40);
493 400 : uh0->checksum = 0;
494 400 : uh0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40);
495 : }
496 : }
497 200 : else if ((encap_type == LB_ENCAP_TYPE_NAT4)
498 100 : || (encap_type == LB_ENCAP_TYPE_NAT6))
499 : {
500 : ip_csum_t csum;
501 : udp_header_t *uh;
502 :
503 : /* do NAT */
504 200 : if ((is_input_v4 == 1) && (encap_type == LB_ENCAP_TYPE_NAT4))
505 100 : {
506 : /* NAT44 */
507 : ip4_header_t *ip40;
508 : u32 old_dst;
509 100 : ip40 = vlib_buffer_get_current (p0);
510 100 : uh = (udp_header_t *) (ip40 + 1);
511 100 : old_dst = ip40->dst_address.as_u32;
512 100 : ip40->dst_address = lbm->ass[asindex0].address.ip4;
513 :
514 100 : csum = ip40->checksum;
515 100 : csum = ip_csum_sub_even (csum, old_dst);
516 100 : csum = ip_csum_add_even (
517 100 : csum, lbm->ass[asindex0].address.ip4.as_u32);
518 100 : ip40->checksum = ip_csum_fold (csum);
519 :
520 100 : if (ip40->protocol == IP_PROTOCOL_UDP)
521 : {
522 100 : uh->dst_port = vip0->encap_args.target_port;
523 100 : csum = uh->checksum;
524 100 : csum = ip_csum_sub_even (csum, old_dst);
525 100 : csum = ip_csum_add_even (
526 100 : csum, lbm->ass[asindex0].address.ip4.as_u32);
527 100 : uh->checksum = ip_csum_fold (csum);
528 : }
529 : else
530 : {
531 0 : asindex0 = 0;
532 : }
533 : }
534 100 : else if ((is_input_v4 == 0) && (encap_type == LB_ENCAP_TYPE_NAT6))
535 : {
536 : /* NAT66 */
537 : ip6_header_t *ip60;
538 : ip6_address_t old_dst;
539 :
540 100 : ip60 = vlib_buffer_get_current (p0);
541 100 : uh = (udp_header_t *) (ip60 + 1);
542 :
543 100 : old_dst.as_u64[0] = ip60->dst_address.as_u64[0];
544 100 : old_dst.as_u64[1] = ip60->dst_address.as_u64[1];
545 100 : ip60->dst_address.as_u64[0] =
546 100 : lbm->ass[asindex0].address.ip6.as_u64[0];
547 100 : ip60->dst_address.as_u64[1] =
548 100 : lbm->ass[asindex0].address.ip6.as_u64[1];
549 :
550 100 : if (PREDICT_TRUE(ip60->protocol == IP_PROTOCOL_UDP))
551 : {
552 100 : uh->dst_port = vip0->encap_args.target_port;
553 100 : csum = uh->checksum;
554 100 : csum = ip_csum_sub_even (csum, old_dst.as_u64[0]);
555 100 : csum = ip_csum_sub_even (csum, old_dst.as_u64[1]);
556 100 : csum = ip_csum_add_even (
557 100 : csum, lbm->ass[asindex0].address.ip6.as_u64[0]);
558 100 : csum = ip_csum_add_even (
559 100 : csum, lbm->ass[asindex0].address.ip6.as_u64[1]);
560 100 : uh->checksum = ip_csum_fold (csum);
561 : }
562 : else
563 : {
564 0 : asindex0 = 0;
565 : }
566 : }
567 : }
568 1400 : next0 = lbm->ass[asindex0].dpo.dpoi_next_node;
569 : //Note that this is going to error if asindex0 == 0
570 1400 : vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
571 1400 : lbm->ass[asindex0].dpo.dpoi_index;
572 :
573 1400 : if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
574 : {
575 1400 : lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof(*tr));
576 1400 : tr->as_index = asindex0;
577 1400 : tr->vip_index = vip_index0;
578 : }
579 :
580 : //Enqueue to next
581 1400 : vlib_validate_buffer_enqueue_x1(
582 : vm, node, next_index, to_next, n_left_to_next, pi0, next0);
583 : }
584 14 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
585 : }
586 :
587 14 : return frame->n_vectors;
588 : }
589 : /* clang-format on */
590 :
591 : u8 *
592 0 : format_nodeport_lb_trace (u8 * s, va_list * args)
593 : {
594 0 : lb_main_t *lbm = &lb_main;
595 0 : CLIB_UNUSED(vlib_main_t * vm)
596 : = va_arg (*args, vlib_main_t *);
597 0 : CLIB_UNUSED(vlib_node_t * node)
598 : = va_arg (*args, vlib_node_t *);
599 0 : lb_nodeport_trace_t *t = va_arg (*args, lb_nodeport_trace_t *);
600 0 : if (pool_is_free_index(lbm->vips, t->vip_index))
601 : {
602 0 : s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
603 : }
604 : else
605 : {
606 0 : s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
607 0 : &lbm->vips[t->vip_index]);
608 : }
609 :
610 0 : s = format (s, " lb node_port: %d", t->node_port);
611 :
612 0 : return s;
613 : }
614 :
615 : static uword
616 0 : lb_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
617 : vlib_frame_t * frame, u8 is_input_v4)
618 : {
619 0 : lb_main_t *lbm = &lb_main;
620 : u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
621 :
622 0 : from = vlib_frame_vector_args (frame);
623 0 : n_left_from = frame->n_vectors;
624 0 : next_index = node->cached_next_index;
625 :
626 0 : while (n_left_from > 0)
627 : {
628 0 : vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
629 :
630 0 : while (n_left_from > 0 && n_left_to_next > 0)
631 : {
632 : u32 pi0;
633 : vlib_buffer_t *p0;
634 : udp_header_t * udp_0;
635 : uword * entry0;
636 :
637 0 : if (PREDICT_TRUE(n_left_from > 1))
638 : {
639 0 : vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]);
640 : //Prefetch for encap, next
641 0 : CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE);
642 : }
643 :
644 0 : if (PREDICT_TRUE(n_left_from > 2))
645 : {
646 : vlib_buffer_t *p2;
647 0 : p2 = vlib_get_buffer (vm, from[2]);
648 : /* prefetch packet header and data */
649 0 : vlib_prefetch_buffer_header(p2, STORE);
650 0 : CLIB_PREFETCH(vlib_buffer_get_current (p2), 64, STORE);
651 : }
652 :
653 0 : pi0 = to_next[0] = from[0];
654 0 : from += 1;
655 0 : n_left_from -= 1;
656 0 : to_next += 1;
657 0 : n_left_to_next -= 1;
658 :
659 0 : p0 = vlib_get_buffer (vm, pi0);
660 :
661 0 : if (is_input_v4)
662 : {
663 : ip4_header_t *ip40;
664 0 : vlib_buffer_advance (
665 : p0, -(word) (sizeof(udp_header_t) + sizeof(ip4_header_t)));
666 0 : ip40 = vlib_buffer_get_current (p0);
667 0 : udp_0 = (udp_header_t *) (ip40 + 1);
668 : }
669 : else
670 : {
671 : ip6_header_t *ip60;
672 0 : vlib_buffer_advance (
673 : p0, -(word) (sizeof(udp_header_t) + sizeof(ip6_header_t)));
674 0 : ip60 = vlib_buffer_get_current (p0);
675 0 : udp_0 = (udp_header_t *) (ip60 + 1);
676 : }
677 :
678 0 : entry0 = hash_get_mem(lbm->vip_index_by_nodeport, &(udp_0->dst_port));
679 :
680 : //Enqueue to next
681 0 : vnet_buffer(p0)->ip.adj_index[VLIB_TX] = entry0 ? entry0[0]
682 : : ADJ_INDEX_INVALID;
683 :
684 0 : if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
685 : {
686 0 : lb_nodeport_trace_t *tr = vlib_add_trace (vm, node, p0,
687 : sizeof(*tr));
688 0 : tr->vip_index = entry0 ? entry0[0] : ADJ_INDEX_INVALID;
689 0 : tr->node_port = (u32) clib_net_to_host_u16 (udp_0->dst_port);
690 : }
691 :
692 0 : vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
693 : n_left_to_next, pi0,
694 : is_input_v4 ?
695 : LB4_NODEPORT_NEXT_IP4_NAT4 : LB6_NODEPORT_NEXT_IP6_NAT6);
696 : }
697 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
698 : }
699 :
700 0 : return frame->n_vectors;
701 :
702 : }
703 :
704 : /**
705 : * @brief Match NAT44 static mapping.
706 : *
707 : * @param sm NAT main.
708 : * @param match Address and port to match.
709 : * @param index index to the pool.
710 : *
711 : * @returns 0 if match found, otherwise -1.
712 : */
713 : int
714 0 : lb_nat44_mapping_match (lb_main_t *lbm, lb_snat4_key_t * match, u32 *index)
715 : {
716 : clib_bihash_kv_8_8_t kv4, value;
717 0 : clib_bihash_8_8_t *mapping_hash = &lbm->mapping_by_as4;
718 :
719 0 : kv4.key = match->as_u64;
720 0 : kv4.value = 0;
721 0 : if (clib_bihash_search_8_8 (mapping_hash, &kv4, &value))
722 : {
723 0 : return 1;
724 : }
725 :
726 0 : *index = value.value;
727 0 : return 0;
728 : }
729 :
730 : /**
731 : * @brief Match NAT66 static mapping.
732 : *
733 : * @param sm NAT main.
734 : * @param match Address and port to match.
735 : * @param mapping External or local address and port of the matched mapping.
736 : *
737 : * @returns 0 if match found otherwise 1.
738 : */
739 : int
740 0 : lb_nat66_mapping_match (lb_main_t *lbm, lb_snat6_key_t * match, u32 *index)
741 : {
742 : clib_bihash_kv_24_8_t kv6, value;
743 : lb_snat6_key_t m_key6;
744 0 : clib_bihash_24_8_t *mapping_hash = &lbm->mapping_by_as6;
745 :
746 0 : m_key6.addr.as_u64[0] = match->addr.as_u64[0];
747 0 : m_key6.addr.as_u64[1] = match->addr.as_u64[1];
748 0 : m_key6.port = match->port;
749 0 : m_key6.protocol = 0;
750 0 : m_key6.fib_index = 0;
751 :
752 0 : kv6.key[0] = m_key6.as_u64[0];
753 0 : kv6.key[1] = m_key6.as_u64[1];
754 0 : kv6.key[2] = m_key6.as_u64[2];
755 0 : kv6.value = 0;
756 0 : if (clib_bihash_search_24_8 (mapping_hash, &kv6, &value))
757 : {
758 0 : return 1;
759 : }
760 :
761 0 : *index = value.value;
762 0 : return 0;
763 : }
764 :
765 : static uword
766 0 : lb_nat_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
767 : vlib_frame_t * frame, u32 is_nat4)
768 : {
769 : u32 n_left_from, *from, *to_next;
770 : u32 next_index;
771 0 : u32 pkts_processed = 0;
772 0 : lb_main_t *lbm = &lb_main;
773 : u32 stats_node_index;
774 :
775 0 : stats_node_index =
776 0 : is_nat4 ? lb_nat4_in2out_node.index : lb_nat6_in2out_node.index;
777 :
778 0 : from = vlib_frame_vector_args (frame);
779 0 : n_left_from = frame->n_vectors;
780 0 : next_index = node->cached_next_index;
781 :
782 0 : while (n_left_from > 0)
783 : {
784 : u32 n_left_to_next;
785 :
786 0 : vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
787 :
788 0 : while (n_left_from > 0 && n_left_to_next > 0)
789 : {
790 : u32 bi0;
791 : vlib_buffer_t * b0;
792 : u32 next0;
793 : u32 sw_if_index0;
794 : ip_csum_t csum;
795 : u16 old_port0, new_port0;
796 : udp_header_t * udp0;
797 : tcp_header_t * tcp0;
798 :
799 : u32 proto0;
800 : u32 rx_fib_index0;
801 :
802 : /* speculatively enqueue b0 to the current next frame */
803 0 : bi0 = from[0];
804 0 : to_next[0] = bi0;
805 0 : from += 1;
806 0 : to_next += 1;
807 0 : n_left_from -= 1;
808 0 : n_left_to_next -= 1;
809 :
810 0 : b0 = vlib_get_buffer (vm, bi0);
811 0 : next0 = LB_NAT4_IN2OUT_NEXT_LOOKUP;
812 0 : sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
813 0 : rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (
814 : sw_if_index0);
815 :
816 0 : if (is_nat4)
817 : {
818 : ip4_header_t * ip40;
819 : u32 old_addr0, new_addr0;
820 : lb_snat4_key_t key40;
821 : lb_snat_mapping_t *sm40;
822 : u32 index40;
823 :
824 0 : ip40 = vlib_buffer_get_current (b0);
825 0 : udp0 = ip4_next_header (ip40);
826 0 : tcp0 = (tcp_header_t *) udp0;
827 0 : proto0 = lb_ip_proto_to_nat_proto (ip40->protocol);
828 :
829 0 : key40.addr = ip40->src_address;
830 0 : key40.protocol = proto0;
831 0 : key40.port = udp0->src_port;
832 0 : key40.fib_index = rx_fib_index0;
833 :
834 0 : if (lb_nat44_mapping_match (lbm, &key40, &index40))
835 : {
836 0 : next0 = LB_NAT4_IN2OUT_NEXT_DROP;
837 0 : goto trace0;
838 : }
839 :
840 0 : sm40 = pool_elt_at_index(lbm->snat_mappings, index40);
841 0 : new_addr0 = sm40->src_ip.ip4.as_u32;
842 0 : new_port0 = sm40->src_port;
843 0 : vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm40->fib_index;
844 0 : old_addr0 = ip40->src_address.as_u32;
845 0 : ip40->src_address.as_u32 = new_addr0;
846 :
847 0 : csum = ip40->checksum;
848 0 : csum = ip_csum_sub_even (csum, old_addr0);
849 0 : csum = ip_csum_add_even (csum, new_addr0);
850 0 : ip40->checksum = ip_csum_fold (csum);
851 :
852 0 : if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_TCP))
853 : {
854 0 : old_port0 = tcp0->src_port;
855 0 : tcp0->src_port = new_port0;
856 :
857 0 : csum = tcp0->checksum;
858 0 : csum = ip_csum_sub_even (csum, old_addr0);
859 0 : csum = ip_csum_sub_even (csum, old_port0);
860 0 : csum = ip_csum_add_even (csum, new_addr0);
861 0 : csum = ip_csum_add_even (csum, new_port0);
862 0 : tcp0->checksum = ip_csum_fold (csum);
863 : }
864 0 : else if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_UDP))
865 : {
866 0 : old_port0 = udp0->src_port;
867 0 : udp0->src_port = new_port0;
868 :
869 0 : csum = udp0->checksum;
870 0 : csum = ip_csum_sub_even (csum, old_addr0);
871 0 : csum = ip_csum_sub_even (csum, old_port0);
872 0 : csum = ip_csum_add_even (csum, new_addr0);
873 0 : csum = ip_csum_add_even (csum, new_port0);
874 0 : udp0->checksum = ip_csum_fold (csum);
875 : }
876 :
877 0 : pkts_processed += next0 != LB_NAT4_IN2OUT_NEXT_DROP;
878 : }
879 : else
880 : {
881 : ip6_header_t * ip60;
882 : ip6_address_t old_addr0, new_addr0;
883 : lb_snat6_key_t key60;
884 : lb_snat_mapping_t *sm60;
885 : u32 index60;
886 :
887 0 : ip60 = vlib_buffer_get_current (b0);
888 0 : udp0 = ip6_next_header (ip60);
889 0 : tcp0 = (tcp_header_t *) udp0;
890 0 : proto0 = lb_ip_proto_to_nat_proto (ip60->protocol);
891 :
892 0 : key60.addr.as_u64[0] = ip60->src_address.as_u64[0];
893 0 : key60.addr.as_u64[1] = ip60->src_address.as_u64[1];
894 0 : key60.protocol = proto0;
895 0 : key60.port = udp0->src_port;
896 0 : key60.fib_index = rx_fib_index0;
897 :
898 0 : if (lb_nat66_mapping_match (lbm, &key60, &index60))
899 : {
900 0 : next0 = LB_NAT6_IN2OUT_NEXT_DROP;
901 0 : goto trace0;
902 : }
903 :
904 0 : sm60 = pool_elt_at_index(lbm->snat_mappings, index60);
905 0 : new_addr0.as_u64[0] = sm60->src_ip.as_u64[0];
906 0 : new_addr0.as_u64[1] = sm60->src_ip.as_u64[1];
907 0 : new_port0 = sm60->src_port;
908 0 : vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm60->fib_index;
909 0 : old_addr0.as_u64[0] = ip60->src_address.as_u64[0];
910 0 : old_addr0.as_u64[1] = ip60->src_address.as_u64[1];
911 0 : ip60->src_address.as_u64[0] = new_addr0.as_u64[0];
912 0 : ip60->src_address.as_u64[1] = new_addr0.as_u64[1];
913 :
914 0 : if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_TCP))
915 : {
916 0 : old_port0 = tcp0->src_port;
917 0 : tcp0->src_port = new_port0;
918 :
919 0 : csum = tcp0->checksum;
920 0 : csum = ip_csum_sub_even (csum, old_addr0.as_u64[0]);
921 0 : csum = ip_csum_sub_even (csum, old_addr0.as_u64[1]);
922 0 : csum = ip_csum_add_even (csum, new_addr0.as_u64[0]);
923 0 : csum = ip_csum_add_even (csum, new_addr0.as_u64[1]);
924 0 : csum = ip_csum_sub_even (csum, old_port0);
925 0 : csum = ip_csum_add_even (csum, new_port0);
926 0 : tcp0->checksum = ip_csum_fold (csum);
927 : }
928 0 : else if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_UDP))
929 : {
930 0 : old_port0 = udp0->src_port;
931 0 : udp0->src_port = new_port0;
932 :
933 0 : csum = udp0->checksum;
934 0 : csum = ip_csum_sub_even (csum, old_addr0.as_u64[0]);
935 0 : csum = ip_csum_sub_even (csum, old_addr0.as_u64[1]);
936 0 : csum = ip_csum_add_even (csum, new_addr0.as_u64[0]);
937 0 : csum = ip_csum_add_even (csum, new_addr0.as_u64[1]);
938 0 : csum = ip_csum_sub_even (csum, old_port0);
939 0 : csum = ip_csum_add_even (csum, new_port0);
940 0 : udp0->checksum = ip_csum_fold (csum);
941 : }
942 :
943 0 : pkts_processed += next0 != LB_NAT4_IN2OUT_NEXT_DROP;
944 : }
945 :
946 0 : trace0: if (PREDICT_FALSE(
947 : (node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED)))
948 : {
949 0 : lb_nat_trace_t *t = vlib_add_trace (vm, node, b0, sizeof(*t));
950 0 : t->rx_sw_if_index = sw_if_index0;
951 0 : t->next_index = next0;
952 : }
953 :
954 : /* verify speculative enqueue, maybe switch current next frame */
955 0 : vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
956 : n_left_to_next, bi0, next0);
957 : }
958 :
959 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
960 : }
961 :
962 0 : vlib_node_increment_counter (vm, stats_node_index,
963 : LB_NAT_IN2OUT_ERROR_IN2OUT_PACKETS,
964 : pkts_processed);
965 0 : return frame->n_vectors;
966 : }
967 :
968 : static uword
969 1 : lb6_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
970 : vlib_frame_t * frame)
971 : {
972 1 : return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 0);
973 : }
974 :
975 : static uword
976 1 : lb6_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
977 : vlib_frame_t * frame)
978 : {
979 1 : return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 0);
980 : }
981 :
982 : static uword
983 1 : lb4_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
984 : vlib_frame_t * frame)
985 : {
986 1 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 0);
987 : }
988 :
989 : static uword
990 1 : lb4_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
991 : vlib_frame_t * frame)
992 : {
993 1 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 0);
994 : }
995 :
996 : static uword
997 1 : lb6_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
998 : vlib_frame_t * frame)
999 : {
1000 1 : return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 1);
1001 : }
1002 :
1003 : static uword
1004 1 : lb6_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1005 : vlib_frame_t * frame)
1006 : {
1007 1 : return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 1);
1008 : }
1009 :
1010 : static uword
1011 1 : lb4_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1012 : vlib_frame_t * frame)
1013 : {
1014 1 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 1);
1015 : }
1016 :
1017 : static uword
1018 1 : lb4_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1019 : vlib_frame_t * frame)
1020 : {
1021 1 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 1);
1022 : }
1023 :
1024 : static uword
1025 2 : lb4_l3dsr_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1026 : vlib_frame_t * frame)
1027 : {
1028 2 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 0);
1029 : }
1030 :
1031 : static uword
1032 2 : lb4_l3dsr_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1033 : vlib_frame_t * frame)
1034 : {
1035 2 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 1);
1036 : }
1037 :
1038 : static uword
1039 1 : lb6_nat6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1040 : vlib_frame_t * frame)
1041 : {
1042 1 : return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_NAT6, 1);
1043 : }
1044 :
1045 : static uword
1046 1 : lb4_nat4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1047 : vlib_frame_t * frame)
1048 : {
1049 1 : return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_NAT4, 1);
1050 : }
1051 :
1052 : static uword
1053 0 : lb_nat4_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1054 : vlib_frame_t * frame)
1055 : {
1056 0 : return lb_nat_in2out_node_fn (vm, node, frame, 1);
1057 : }
1058 :
1059 : static uword
1060 0 : lb_nat6_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1061 : vlib_frame_t * frame)
1062 : {
1063 0 : return lb_nat_in2out_node_fn (vm, node, frame, 0);
1064 : }
1065 :
1066 101996 : VLIB_REGISTER_NODE (lb6_gre6_node) =
1067 : {
1068 : .function = lb6_gre6_node_fn,
1069 : .name = "lb6-gre6",
1070 : .vector_size = sizeof(u32),
1071 : .format_trace = format_lb_trace,
1072 : .n_errors = LB_N_ERROR,
1073 : .error_strings = lb_error_strings,
1074 : .n_next_nodes = LB_N_NEXT,
1075 : .next_nodes =
1076 : { [LB_NEXT_DROP] = "error-drop" },
1077 : };
1078 :
1079 101996 : VLIB_REGISTER_NODE (lb6_gre4_node) =
1080 : {
1081 : .function = lb6_gre4_node_fn,
1082 : .name = "lb6-gre4",
1083 : .vector_size = sizeof(u32),
1084 : .format_trace = format_lb_trace,
1085 : .n_errors = LB_N_ERROR,
1086 : .error_strings = lb_error_strings,
1087 : .n_next_nodes = LB_N_NEXT,
1088 : .next_nodes =
1089 : { [LB_NEXT_DROP] = "error-drop" },
1090 : };
1091 :
1092 101996 : VLIB_REGISTER_NODE (lb4_gre6_node) =
1093 : {
1094 : .function = lb4_gre6_node_fn,
1095 : .name = "lb4-gre6",
1096 : .vector_size = sizeof(u32),
1097 : .format_trace = format_lb_trace,
1098 : .n_errors = LB_N_ERROR,
1099 : .error_strings = lb_error_strings,
1100 : .n_next_nodes = LB_N_NEXT,
1101 : .next_nodes =
1102 : { [LB_NEXT_DROP] = "error-drop" },
1103 : };
1104 :
1105 101996 : VLIB_REGISTER_NODE (lb4_gre4_node) =
1106 : {
1107 : .function = lb4_gre4_node_fn,
1108 : .name = "lb4-gre4",
1109 : .vector_size = sizeof(u32),
1110 : .format_trace = format_lb_trace,
1111 : .n_errors = LB_N_ERROR,
1112 : .error_strings = lb_error_strings,
1113 : .n_next_nodes = LB_N_NEXT,
1114 : .next_nodes =
1115 : { [LB_NEXT_DROP] = "error-drop" },
1116 : };
1117 :
1118 101996 : VLIB_REGISTER_NODE (lb6_gre6_port_node) =
1119 : {
1120 : .function = lb6_gre6_port_node_fn,
1121 : .name = "lb6-gre6-port",
1122 : .vector_size = sizeof(u32),
1123 : .format_trace = format_lb_trace,
1124 : .n_errors = LB_N_ERROR,
1125 : .error_strings = lb_error_strings,
1126 : .n_next_nodes = LB_N_NEXT,
1127 : .next_nodes =
1128 : { [LB_NEXT_DROP] = "error-drop" },
1129 : };
1130 :
1131 101996 : VLIB_REGISTER_NODE (lb6_gre4_port_node) =
1132 : {
1133 : .function = lb6_gre4_port_node_fn,
1134 : .name = "lb6-gre4-port",
1135 : .vector_size = sizeof(u32),
1136 : .format_trace = format_lb_trace,
1137 : .n_errors = LB_N_ERROR,
1138 : .error_strings = lb_error_strings,
1139 : .n_next_nodes = LB_N_NEXT,
1140 : .next_nodes =
1141 : { [LB_NEXT_DROP] = "error-drop" },
1142 : };
1143 :
1144 101996 : VLIB_REGISTER_NODE (lb4_gre6_port_node) =
1145 : {
1146 : .function = lb4_gre6_port_node_fn,
1147 : .name = "lb4-gre6-port",
1148 : .vector_size = sizeof(u32),
1149 : .format_trace = format_lb_trace,
1150 : .n_errors = LB_N_ERROR,
1151 : .error_strings = lb_error_strings,
1152 : .n_next_nodes = LB_N_NEXT,
1153 : .next_nodes =
1154 : { [LB_NEXT_DROP] = "error-drop" },
1155 : };
1156 :
1157 101996 : VLIB_REGISTER_NODE (lb4_gre4_port_node) =
1158 : {
1159 : .function = lb4_gre4_port_node_fn,
1160 : .name = "lb4-gre4-port",
1161 : .vector_size = sizeof(u32),
1162 : .format_trace = format_lb_trace,
1163 : .n_errors = LB_N_ERROR,
1164 : .error_strings = lb_error_strings,
1165 : .n_next_nodes = LB_N_NEXT,
1166 : .next_nodes =
1167 : { [LB_NEXT_DROP] = "error-drop" },
1168 : };
1169 :
1170 101996 : VLIB_REGISTER_NODE (lb4_l3dsr_port_node) =
1171 : {
1172 : .function = lb4_l3dsr_port_node_fn,
1173 : .name = "lb4-l3dsr-port",
1174 : .vector_size = sizeof(u32),
1175 : .format_trace = format_lb_trace,
1176 : .n_errors = LB_N_ERROR,
1177 : .error_strings = lb_error_strings,
1178 : .n_next_nodes = LB_N_NEXT,
1179 : .next_nodes =
1180 : { [LB_NEXT_DROP] = "error-drop" },
1181 : };
1182 :
1183 101996 : VLIB_REGISTER_NODE (lb4_l3dsr_node) =
1184 : {
1185 : .function = lb4_l3dsr_node_fn,
1186 : .name = "lb4-l3dsr",
1187 : .vector_size = sizeof(u32),
1188 : .format_trace = format_lb_trace,
1189 : .n_errors = LB_N_ERROR,
1190 : .error_strings = lb_error_strings,
1191 : .n_next_nodes = LB_N_NEXT,
1192 : .next_nodes =
1193 : { [LB_NEXT_DROP] = "error-drop" },
1194 : };
1195 :
1196 101996 : VLIB_REGISTER_NODE (lb6_nat6_port_node) =
1197 : {
1198 : .function = lb6_nat6_port_node_fn,
1199 : .name = "lb6-nat6-port",
1200 : .vector_size = sizeof(u32),
1201 : .format_trace = format_lb_trace,
1202 : .n_errors = LB_N_ERROR,
1203 : .error_strings = lb_error_strings,
1204 : .n_next_nodes = LB_N_NEXT,
1205 : .next_nodes =
1206 : { [LB_NEXT_DROP] = "error-drop" },
1207 : };
1208 :
1209 101996 : VLIB_REGISTER_NODE (lb4_nat4_port_node) =
1210 : {
1211 : .function = lb4_nat4_port_node_fn,
1212 : .name = "lb4-nat4-port",
1213 : .vector_size = sizeof(u32),
1214 : .format_trace = format_lb_trace,
1215 : .n_errors = LB_N_ERROR,
1216 : .error_strings = lb_error_strings,
1217 : .n_next_nodes = LB_N_NEXT,
1218 : .next_nodes =
1219 : { [LB_NEXT_DROP] = "error-drop" },
1220 : };
1221 :
1222 : static uword
1223 0 : lb4_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1224 : vlib_frame_t * frame)
1225 : {
1226 0 : return lb_nodeport_node_fn (vm, node, frame, 1);
1227 : }
1228 :
1229 : static uword
1230 0 : lb6_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1231 : vlib_frame_t * frame)
1232 : {
1233 0 : return lb_nodeport_node_fn (vm, node, frame, 0);
1234 : }
1235 :
1236 101996 : VLIB_REGISTER_NODE (lb4_nodeport_node) =
1237 : {
1238 : .function = lb4_nodeport_node_fn,
1239 : .name = "lb4-nodeport",
1240 : .vector_size = sizeof(u32),
1241 : .format_trace = format_nodeport_lb_trace,
1242 : .n_errors = LB_N_ERROR,
1243 : .error_strings = lb_error_strings,
1244 : .n_next_nodes = LB4_NODEPORT_N_NEXT,
1245 : .next_nodes =
1246 : {
1247 : [LB4_NODEPORT_NEXT_IP4_NAT4] = "lb4-nat4-port",
1248 : [LB4_NODEPORT_NEXT_DROP] = "error-drop",
1249 : },
1250 : };
1251 :
1252 101996 : VLIB_REGISTER_NODE (lb6_nodeport_node) =
1253 : {
1254 : .function = lb6_nodeport_node_fn,
1255 : .name = "lb6-nodeport",
1256 : .vector_size = sizeof(u32),
1257 : .format_trace = format_nodeport_lb_trace,
1258 : .n_errors = LB_N_ERROR,
1259 : .error_strings = lb_error_strings,
1260 : .n_next_nodes = LB6_NODEPORT_N_NEXT,
1261 : .next_nodes =
1262 : {
1263 : [LB6_NODEPORT_NEXT_IP6_NAT6] = "lb6-nat6-port",
1264 : [LB6_NODEPORT_NEXT_DROP] = "error-drop",
1265 : },
1266 : };
1267 :
1268 50139 : VNET_FEATURE_INIT (lb_nat4_in2out_node_fn, static) =
1269 : {
1270 : .arc_name = "ip4-unicast",
1271 : .node_name = "lb-nat4-in2out",
1272 : .runs_before = VNET_FEATURES("ip4-lookup"),
1273 : };
1274 :
1275 101996 : VLIB_REGISTER_NODE (lb_nat4_in2out_node) =
1276 : {
1277 : .function = lb_nat4_in2out_node_fn,
1278 : .name = "lb-nat4-in2out",
1279 : .vector_size = sizeof(u32),
1280 : .format_trace = format_lb_nat_trace,
1281 : .n_errors = LB_N_ERROR,
1282 : .error_strings = lb_error_strings,
1283 : .n_next_nodes = LB_NAT4_IN2OUT_N_NEXT,
1284 : .next_nodes =
1285 : {
1286 : [LB_NAT4_IN2OUT_NEXT_DROP] = "error-drop",
1287 : [LB_NAT4_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1288 : },
1289 : };
1290 :
1291 50139 : VNET_FEATURE_INIT (lb_nat6_in2out_node_fn, static) =
1292 : {
1293 : .arc_name = "ip6-unicast",
1294 : .node_name = "lb-nat6-in2out",
1295 : .runs_before = VNET_FEATURES("ip6-lookup"),
1296 : };
1297 :
1298 101996 : VLIB_REGISTER_NODE (lb_nat6_in2out_node) =
1299 : {
1300 : .function = lb_nat6_in2out_node_fn,
1301 : .name = "lb-nat6-in2out",
1302 : .vector_size = sizeof(u32),
1303 : .format_trace = format_lb_nat_trace,
1304 : .n_errors = LB_N_ERROR,
1305 : .error_strings = lb_error_strings,
1306 : .n_next_nodes = LB_NAT6_IN2OUT_N_NEXT,
1307 : .next_nodes =
1308 : {
1309 : [LB_NAT6_IN2OUT_NEXT_DROP] = "error-drop",
1310 : [LB_NAT6_IN2OUT_NEXT_LOOKUP] = "ip6-lookup",
1311 : },
1312 : };
|