FD.io VPP  v16.09
Vector Packet Processing
node.c
Go to the documentation of this file.
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 
18 #include <vnet/gre/packet.h>
19 #include <lb/lbhash.h>
20 
21 #define foreach_lb_error \
22  _(NONE, "no error") \
23  _(PROTO_NOT_SUPPORTED, "protocol not supported") \
24  _(NO_SERVER, "no configured application server")
25 
26 typedef enum {
27 #define _(sym,str) LB_ERROR_##sym,
29 #undef _
31 } lb_error_t;
32 
33 static char *lb_error_strings[] = {
34 #define _(sym,string) string,
36 #undef _
37 };
38 
39 typedef enum {
44 } lb_next_t;
45 
46 typedef struct {
49 } lb_trace_t;
50 
51 u8 *lb_format_adjacency(u8 * s, va_list * va)
52 {
53  lb_main_t *lbm = &lb_main;
54  __attribute((unused)) ip_lookup_main_t *lm = va_arg (*va, ip_lookup_main_t *);
55  ip_adjacency_t *adj = va_arg (*va, ip_adjacency_t *);
56  lb_adj_data_t *ad = (lb_adj_data_t *) &adj->opaque;
57  __attribute__((unused)) lb_vip_t *vip = pool_elt_at_index (lbm->vips, ad->vip_index);
58  return format(s, "vip idx:%d", ad->vip_index);
59 }
60 
61 u8 *
62 format_lb_trace (u8 * s, va_list * args)
63 {
64  lb_main_t *lbm = &lb_main;
65  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67  lb_trace_t *t = va_arg (*args, lb_trace_t *);
68  s = format(s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip, &lbm->vips[t->vip_index]);
69  s = format(s, "lb as[%d]: %U\n", t->as_index, format_lb_as, &lbm->ass[t->as_index]);
70  return s;
71 }
72 
74 {
75  lb_main_t *lbm = &lb_main;
76  lb_hash_t *sticky_ht = lbm->per_cpu[cpu_index].sticky_ht;
77  //Check if size changed
78  if (PREDICT_FALSE(sticky_ht && (lbm->per_cpu_sticky_buckets != lb_hash_nbuckets(sticky_ht)))) {
79 
80  //Dereference everything in there
81  lb_hash_entry_t *e;
82  lb_hash_foreach_entry(sticky_ht, e) {
83  vlib_refcount_add(&lbm->as_refcount, cpu_index, e->value, -1);
84  vlib_refcount_add(&lbm->as_refcount, cpu_index, 0, -1);
85  }
86 
87  lb_hash_free(sticky_ht);
88  sticky_ht = NULL;
89  }
90 
91  //Create if necessary
92  if (PREDICT_FALSE(sticky_ht == NULL)) {
94  sticky_ht = lbm->per_cpu[cpu_index].sticky_ht;
95  clib_warning("Regenerated sticky table %p", sticky_ht);
96  }
97 
98  ASSERT(sticky_ht);
99 
100  //Update timeout
101  sticky_ht->timeout = lbm->flow_timeout;
102  return sticky_ht;
103 }
104 
107  vlib_node_runtime_t * node, vlib_frame_t * frame,
108  u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6)
109  u8 is_encap_v4) //Compile-time parameter stating that is GRE encap is v4 (or v6)
110 {
112  lb_main_t *lbm = &lb_main;
113  vlib_node_runtime_t *error_node = node;
114  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
115  u32 cpu_index = os_get_cpu_number();
116  u32 lb_time = lb_hash_time_now(vm);
117 
118  lb_hash_t *sticky_ht = lb_get_sticky_table(cpu_index);
119  from = vlib_frame_vector_args (frame);
120  n_left_from = frame->n_vectors;
121  next_index = node->cached_next_index;
122 
123  while (n_left_from > 0)
124  {
125  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
126  while (n_left_from > 0 && n_left_to_next > 0)
127  {
128  u32 pi0;
129  vlib_buffer_t *p0;
130  ip_adjacency_t *adj0;
131  lb_adj_data_t *ad0;
132  lb_vip_t *vip0;
133  lb_as_t *as0;
134  gre_header_t *gre0;
135  u16 len0;
136  u32 value0, available_index0, hash0;
137  u64 key0[5];
138  lb_error_t error0 = LB_ERROR_NONE;
139  lb_next_t next0 = LB_NEXT_LOOKUP;
140 
141  if (PREDICT_TRUE(n_left_from > 1))
142  {
143  vlib_buffer_t *p2;
144  p2 = vlib_get_buffer(vm, from[1]);
145  vlib_prefetch_buffer_header(p2, STORE);
146  /* IPv4 + 8 = 28. possibly plus -40 */
147  CLIB_PREFETCH (vlib_buffer_get_current(p2) - 40, 128, STORE);
148  }
149 
150  pi0 = to_next[0] = from[0];
151  from += 1;
152  n_left_from -= 1;
153  to_next += 1;
154  n_left_to_next -= 1;
155 
156  p0 = vlib_get_buffer (vm, pi0);
157  adj0 = ip_get_adjacency (lm, vnet_buffer (p0)->ip.adj_index[VLIB_TX]);
158  ad0 = (lb_adj_data_t *) &adj0->opaque;
159  vip0 = pool_elt_at_index (lbm->vips, ad0->vip_index);
160 
161  if (is_input_v4) {
162  ip4_header_t *ip40;
163  ip40 = vlib_buffer_get_current (p0);
164  len0 = clib_net_to_host_u16(ip40->length);
165  key0[0] = (u64) ip40->src_address.as_u32;
166  key0[1] = (u64) ip40->dst_address.as_u32;
167  key0[2] = 0;
168  key0[3] = 0;
169  key0[4] = ((u64)((udp_header_t *)(ip40 + 1))->src_port << 32) |
170  ((u64)((udp_header_t *)(ip40 + 1))->dst_port << 16);
171 
172  hash0 = lb_hash_hash(key0);
173  } else {
174  ip6_header_t *ip60;
175  ip60 = vlib_buffer_get_current (p0);
176  len0 = clib_net_to_host_u16(ip60->payload_length) + sizeof(ip6_header_t);
177  key0[0] = ip60->src_address.as_u64[0];
178  key0[1] = ip60->src_address.as_u64[1];
179  key0[2] = ip60->dst_address.as_u64[0];
180  key0[3] = ip60->dst_address.as_u64[1];
181  key0[4] = ((u64)((udp_header_t *)(ip60 + 1))->src_port << 32) |
182  ((u64)((udp_header_t *)(ip60 + 1))->dst_port << 16);
183 
184  hash0 = lb_hash_hash(key0);
185  }
186 
187  //NOTE: This is an ugly trick to not include the VIP index in the hash calculation
188  //but actually use it in the key determination.
189  key0[4] |= ((vip0 - lbm->vips));
190 
191  lb_hash_get(sticky_ht, key0, hash0, lb_time, &available_index0, &value0);
192  if (PREDICT_TRUE(value0 != ~0)) {
193  //Found an existing entry
194  as0 = &lbm->ass[value0];
195  } else if (PREDICT_TRUE(available_index0 != ~0)) {
196  //There is an available slot for a new flow
197  as0 = &lbm->ass[vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index];
198  if (PREDICT_FALSE(as0 == lbm->ass)) { //Special first element
199  error0 = LB_ERROR_NO_SERVER;
200  next0 = LB_NEXT_DROP;
201  } else {
202  vlib_increment_simple_counter(&lbm->vip_counters[LB_VIP_COUNTER_TRACKED_SESSION],
203  cpu_index, vip0 - lbm->vips, 1);
204  }
205 
206  //TODO: There are race conditions with as0 and vip0 manipulation.
207  //Configuration may be changed, vectors resized, etc...
208 
209  //Dereference previously used
210  vlib_refcount_add(&lbm->as_refcount, cpu_index, lb_hash_available_value(sticky_ht, available_index0), -1);
211  vlib_refcount_add(&lbm->as_refcount, cpu_index, as0 - lbm->ass, 1);
212 
213  //Add sticky entry
214  //Note that when there is no AS configured, an entry is configured anyway.
215  //But no configured AS is not something that should happen
216  lb_hash_put(sticky_ht, key0, as0 - lbm->ass, available_index0, lb_time);
217  } else {
218  //Could not store new entry in the table
219  as0 = &lbm->ass[vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index];
220  vlib_increment_simple_counter(&lbm->vip_counters[LB_VIP_COUNTER_UNTRACKED_PACKET],
221  cpu_index, vip0 - lbm->vips, 1);
222  }
223 
224  //Now let's encap
225  if (is_encap_v4) {
226  ip4_header_t *ip40;
227  vlib_buffer_advance(p0, - sizeof(ip4_header_t) - sizeof(gre_header_t));
228  ip40 = vlib_buffer_get_current(p0);
229  gre0 = (gre_header_t *)(ip40 + 1);
230  ip40->src_address = lbm->ip4_src_address;
231  ip40->dst_address = as0->address.ip4;
232  ip40->ip_version_and_header_length = 0x45;
233  ip40->ttl = 128;
234  ip40->length = clib_host_to_net_u16(len0 + sizeof(gre_header_t) + sizeof(ip4_header_t));
235  ip40->protocol = IP_PROTOCOL_GRE;
236  ip40->checksum = ip4_header_checksum (ip40);
237  } else {
238  ip6_header_t *ip60;
239  vlib_buffer_advance(p0, - sizeof(ip6_header_t) - sizeof(gre_header_t));
240  ip60 = vlib_buffer_get_current(p0);
241  gre0 = (gre_header_t *)(ip60 + 1);
242  ip60->dst_address = as0->address.ip6;
243  ip60->src_address = lbm->ip6_src_address;
244  ip60->hop_limit = 128;
245  ip60->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6<<28);
246  ip60->payload_length = clib_host_to_net_u16(len0 + sizeof(gre_header_t));
247  ip60->protocol = IP_PROTOCOL_GRE;
248  }
249 
250  gre0->flags_and_version = 0;
251  gre0->protocol = (is_input_v4)?
252  clib_host_to_net_u16(0x0800):
253  clib_host_to_net_u16(0x86DD);
254 
255  vnet_buffer(p0)->ip.adj_index[VLIB_TX] = as0->adj_index;
256  next0 = (as0->adj_index != ~0)?LB_NEXT_REWRITE:next0;
257 
259  {
260  lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr));
261  tr->as_index = as0 - lbm->ass;
262  tr->vip_index = ad0->vip_index;
263  }
264 
265  p0->error = error_node->errors[error0];
266  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
267  n_left_to_next, pi0, next0);
268  }
269  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
270  }
271 
272  return frame->n_vectors;
273 }
274 
275 static uword
277  vlib_node_runtime_t * node, vlib_frame_t * frame)
278 {
279  return lb_node_fn(vm, node, frame, 0, 0);
280 }
281 
282 static uword
284  vlib_node_runtime_t * node, vlib_frame_t * frame)
285 {
286  return lb_node_fn(vm, node, frame, 0, 1);
287 }
288 
289 static uword
291  vlib_node_runtime_t * node, vlib_frame_t * frame)
292 {
293  return lb_node_fn(vm, node, frame, 1, 0);
294 }
295 
296 static uword
298  vlib_node_runtime_t * node, vlib_frame_t * frame)
299 {
300  return lb_node_fn(vm, node, frame, 1, 1);
301 }
302 
304 {
305  .function = lb6_gre6_node_fn,
306  .name = "lb6-gre6",
307  .vector_size = sizeof (u32),
308  .format_trace = format_lb_trace,
309 
310  .n_errors = LB_N_ERROR,
311  .error_strings = lb_error_strings,
312 
313  .n_next_nodes = LB_N_NEXT,
314  .next_nodes =
315  {
316  [LB_NEXT_LOOKUP] = "ip6-lookup",
317  [LB_NEXT_REWRITE] = "ip6-rewrite",
318  [LB_NEXT_DROP] = "error-drop"
319  },
320 };
321 
322 VNET_IP6_REGISTER_ADJACENCY(lb6_gre6) = {
323  .node_name = "lb6-gre6",
324  .fn = lb_format_adjacency,
326 };
327 
329 {
330  .function = lb6_gre4_node_fn,
331  .name = "lb6-gre4",
332  .vector_size = sizeof (u32),
333  .format_trace = format_lb_trace,
334 
335  .n_errors = LB_N_ERROR,
336  .error_strings = lb_error_strings,
337 
338  .n_next_nodes = LB_N_NEXT,
339  .next_nodes =
340  {
341  [LB_NEXT_LOOKUP] = "ip4-lookup",
342  [LB_NEXT_REWRITE]= "ip4-rewrite-transit",
343  [LB_NEXT_DROP] = "error-drop"
344  },
345 };
346 
347 VNET_IP6_REGISTER_ADJACENCY(lb6_gre4) = {
348  .node_name = "lb6-gre4",
349  .fn = lb_format_adjacency,
351 };
352 
354 {
355  .function = lb4_gre6_node_fn,
356  .name = "lb4-gre6",
357  .vector_size = sizeof (u32),
358  .format_trace = format_lb_trace,
359 
360  .n_errors = LB_N_ERROR,
361  .error_strings = lb_error_strings,
362 
363  .n_next_nodes = LB_N_NEXT,
364  .next_nodes =
365  {
366  [LB_NEXT_LOOKUP] = "ip6-lookup",
367  [LB_NEXT_REWRITE] = "ip6-rewrite",
368  [LB_NEXT_DROP] = "error-drop"
369  },
370 };
371 
372 VNET_IP4_REGISTER_ADJACENCY(lb4_gre6) = {
373  .node_name = "lb4-gre6",
374  .fn = lb_format_adjacency,
376 };
377 
379 {
380  .function = lb4_gre4_node_fn,
381  .name = "lb4-gre4",
382  .vector_size = sizeof (u32),
383  .format_trace = format_lb_trace,
384 
385  .n_errors = LB_N_ERROR,
386  .error_strings = lb_error_strings,
387 
388  .n_next_nodes = LB_N_NEXT,
389  .next_nodes =
390  {
391  [LB_NEXT_LOOKUP] = "ip4-lookup",
392  [LB_NEXT_REWRITE]= "ip4-rewrite-transit",
393  [LB_NEXT_DROP] = "error-drop"
394  },
395 };
396 
397 VNET_IP4_REGISTER_ADJACENCY(lb4_gre4) = {
398  .node_name = "lb4-gre4",
399  .fn = lb_format_adjacency,
401 };
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:457
u32 ip_lookup_next_index[LB_VIP_N_TYPES]
Node next index for IP adjacencies, for each of the traffic types.
Definition: lb.h:236
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 cpu_index, u32 index, u32 increment)
Increment a simple counter.
Definition: counter.h:78
vlib_node_registration_t lb4_gre4_node
(constructor) VLIB_REGISTER_NODE (lb4_gre4_node)
Definition: node.c:378
format_function_t format_lb_vip
Definition: lb.h:196
static uword lb4_gre4_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:297
u32 lb_hash_time_now(vlib_main_t *vm)
Definition: lb.c:31
Each VIP is configured with a set of application server.
Definition: lb.h:48
#define CLIB_UNUSED(x)
Definition: clib.h:79
ip4_address_t src_address
Definition: ip4_packet.h:138
u32 per_cpu_sticky_buckets
Number of buckets in the per-cpu sticky hash table.
Definition: lb.h:251
#define PREDICT_TRUE(x)
Definition: clib.h:98
u64 as_u64[2]
Definition: ip6_packet.h:50
IP unicast adjacency.
Definition: lookup.h:164
#define NULL
Definition: clib.h:55
static_always_inline lb_hash_t * lb_hash_alloc(u32 buckets, u32 timeout)
Definition: lbhash.h:61
VNET_IP4_REGISTER_ADJACENCY(lb4_gre6)
lb_error_t
Definition: node.c:26
ip_lookup_main_t lookup_main
Definition: ip4.h:115
u8 opaque[IP_ADJACENCY_OPAQUE_SZ]
Definition: lookup.h:204
u32 adj_index
Second ip lookup can be avoided by sending directly the packet to ip-rewrite with a configured adjace...
Definition: lb.h:62
vlib_node_registration_t lb6_gre4_node
(constructor) VLIB_REGISTER_NODE (lb6_gre4_node)
Definition: node.c:328
lb_hash_t * lb_get_sticky_table(u32 cpu_index)
Definition: node.c:73
static_always_inline u32 lb_hash_put(lb_hash_t *h, u64 k[5], u32 value, u32 available_index, u32 time_now)
Definition: lbhash.h:158
ip6_address_t src_address
Definition: ip6_packet.h:298
lb_hash_t * sticky_ht
Each CPU has its own sticky flow hash table.
Definition: lb.h:204
ip46_address_t address
Destination address used to tunnel traffic towards that application server.
Definition: lb.h:55
u32 timeout
Definition: lbhash.h:46
u32 vip_index
Definition: node.c:47
#define lb_hash_nbuckets(h)
Definition: lbhash.h:50
#define static_always_inline
Definition: clib.h:85
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:187
ip4_address_t dst_address
Definition: ip4_packet.h:138
lb_main_t lb_main
Definition: lb.c:26
u32 flow_timeout
Flow timeout in seconds.
Definition: lb.h:256
Definition: lb.h:207
vlib_refcount_t as_refcount
Each AS has an associated reference counter.
Definition: lb.h:226
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
Definition: lbhash.h:38
format_function_t format_lb_as
Definition: lb.h:91
lb_vip_t * vips
Pool of all Virtual IPs.
Definition: lb.h:211
u32 value
Definition: lbhash.h:40
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
static_always_inline void lb_hash_get(lb_hash_t *h, u64 k[5], u32 hash, u32 time_now, u32 *available_index, u32 *value)
Definition: lbhash.h:124
#define lb_hash_foreach_entry(h, e)
Definition: lbhash.h:53
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:130
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:348
u16 flags_and_version
Definition: packet.h:36
static_always_inline uword lb_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_input_v4, u8 is_encap_v4)
Definition: node.c:106
static uword lb6_gre4_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:283
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:118
static char * lb_error_strings[]
Definition: node.c:33
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
u32 as_index
Definition: node.c:48
u16 protocol
Definition: packet.h:51
lb_next_t
Definition: node.c:39
u32 vip_index
Index of the VIP associated with that IP adjacency.
Definition: lb.h:278
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:200
u32 as_index
Definition: lb.h:94
static_always_inline u32 lb_hash_available_value(lb_hash_t *h, u32 available_index)
Definition: lbhash.h:152
static_always_inline void lb_hash_free(lb_hash_t *h)
Definition: lbhash.h:79
vlib_node_registration_t lb4_gre6_node
(constructor) VLIB_REGISTER_NODE (lb4_gre6_node)
Definition: node.c:353
lb_as_t * ass
Pool of ASs.
Definition: lb.h:219
#define foreach_lb_error
Definition: node.c:21
u16 cached_next_index
Definition: node.h:462
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
struct stored in adj->opaque data.
Definition: lb.h:274
#define vnet_buffer(b)
Definition: buffer.h:335
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
u32 new_flow_table_mask
New flows table length - 1 (length MUST be a power of 2)
Definition: lb.h:145
static uword lb6_gre6_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:276
lb_per_cpu_t * per_cpu
Some global data is per-cpu.
Definition: lb.h:231
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
Definition: node.c:43
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:285
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
static_always_inline u32 lb_hash_hash(u64 k[5])
Definition: lbhash.h:114
u16 payload_length
Definition: ip6_packet.h:289
unsigned char u8
Definition: types.h:56
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
u8 * format_lb_trace(u8 *s, va_list *args)
Definition: node.c:62
vlib_node_registration_t lb6_gre6_node
(constructor) VLIB_REGISTER_NODE (lb6_gre6_node)
Definition: node.c:303
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:163
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
static uword lb4_gre6_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:290
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
lb_new_flow_entry_t * new_flow_table
Vector mapping (flow-hash & new_connect_table_mask) to AS index.
Definition: lb.h:139
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
static_always_inline void vlib_refcount_add(vlib_refcount_t *r, u32 cpu_index, u32 counter_index, i32 v)
Definition: refcount.h:48
Load balancing service is provided per VIP.
Definition: lb.h:131
VNET_IP6_REGISTER_ADJACENCY(lb6_gre6)
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
u8 * lb_format_adjacency(u8 *s, va_list *va)
Definition: node.c:51
ip6_address_t dst_address
Definition: ip6_packet.h:298
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480