FD.io VPP  v21.06
Vector Packet Processing
node.c
Go to the documentation of this file.
1 /*
2  * node.c
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vppinfra/error.h>
21 #include <srv6-ad-flow/ad-flow.h>
22 
23 /****************************** Packet tracing ******************************/
24 
25 typedef struct
26 {
29 
30 typedef struct
31 {
33  ip6_address_t src, dst;
35 
36 static u8 *
38 {
39  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
40  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
42  va_arg (*args, srv6_ad_flow_localsid_trace_t *);
43 
44  return format (s, "SRv6-AD-Flow-localsid: localsid_index %d",
45  t->localsid_index);
46 }
47 
48 static u8 *
50 {
51  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
54  va_arg (*args, srv6_ad_flow_rewrite_trace_t *);
55 
56  if (PREDICT_FALSE (t->error != 0))
57  {
58  return format (s, "SRv6-AD-Flow-rewrite: cache is empty");
59  }
60 
61  return format (s, "SRv6-AD-Flow-rewrite: src %U dst %U", format_ip6_address,
62  &t->src, format_ip6_address, &t->dst);
63 }
64 
65 /**************************** Nodes registration *****************************/
66 
69 
70 /****************************** Packet counters ******************************/
71 
72 #define foreach_srv6_ad_flow_rewrite_counter \
73  _ (PROCESSED, "srv6-ad-flow rewritten packets") \
74  _ (NO_RW, "(Error) No header for rewriting.")
75 
76 typedef enum
77 {
78 #define _(sym, str) SRV6_AD_FLOW_REWRITE_COUNTER_##sym,
80 #undef _
83 
85 #define _(sym, string) string,
87 #undef _
88 };
89 
90 /******************************** Next nodes *********************************/
91 
92 typedef enum
93 {
101 
102 typedef enum
103 {
108 
109 /***************************** Inline functions ******************************/
110 
113  f64 now)
114 {
115  dlist_elt_t *lru_list_elt;
116  pool_get (ls->lru_pool, lru_list_elt);
117  e->lru_index = lru_list_elt - ls->lru_pool;
119  lru_list_elt->value = e - ls->cache;
120  e->last_lru_update = now;
121  return 1;
122 }
123 
124 always_inline void
126 {
127  /* don't update too often - timeout is in magnitude of seconds anyway */
128  if (e->last_heard > e->last_lru_update + 1)
129  {
132  e->last_lru_update = e->last_heard;
133  }
134 }
135 
136 always_inline void
138  int lru_delete)
139 {
141 
142  if (ls->inner_type == AD_TYPE_IP4)
143  {
144  kv.key[0] = ((u64) e->key.s_addr.ip4.as_u32 << 32) |
145  (u64) e->key.d_addr.ip4.as_u32;
146  kv.key[1] = ((u64) e->key.s_port << 16) | ((u64) e->key.d_port);
147  kv.key[2] = 0;
148  kv.key[3] = 0;
149  kv.key[4] = 0;
150  }
151  else
152  {
153  kv.key[0] = e->key.s_addr.ip6.as_u64[0];
154  kv.key[1] = e->key.s_addr.ip6.as_u64[1];
155  kv.key[2] = e->key.d_addr.ip6.as_u64[0];
156  kv.key[3] = e->key.d_addr.ip6.as_u64[1];
157  kv.key[4] = ((u64) e->key.s_port << 16) | ((u64) e->key.d_port);
158  }
159 
160  clib_bihash_add_del_40_8 (&ls->ftable, &kv, 0);
161 
162  vec_free (e->rw_data);
163 
164  if (lru_delete)
165  {
167  }
169  pool_put (ls->cache, e);
170 }
171 
174 {
175  srv6_ad_flow_entry_t *e = NULL;
176  dlist_elt_t *oldest_elt;
177  f64 entry_timeout_time;
178  u32 oldest_index;
179  oldest_index = clib_dlist_remove_head (ls->lru_pool, ls->lru_head_index);
180  if (~0 != oldest_index)
181  {
182  oldest_elt = pool_elt_at_index (ls->lru_pool, oldest_index);
183  e = pool_elt_at_index (ls->cache, oldest_elt->value);
184 
185  entry_timeout_time = e->last_heard + (f64) SRV6_AD_CACHE_TIMEOUT;
186  if (now >= entry_timeout_time)
187  {
188  ad_flow_entry_delete (ls, e, 0);
189  return 1;
190  }
191  else
192  {
193  clib_dlist_addhead (ls->lru_pool, ls->lru_head_index, oldest_index);
194  }
195  }
196  return 0;
197 }
198 
201 {
203 
204  ad_flow_lru_free_one (ls, now);
205 
206  pool_get (ls->cache, e);
207  clib_memset (e, 0, sizeof *e);
208 
209  ad_flow_lru_insert (ls, e, now);
210 
211  return e;
212 }
213 
216 {
217  return value->value & ~(u32) 0;
218 }
219 
220 int
222 {
225  u64 entry_timeout_time;
226  srv6_ad_flow_localsid_t *ls = ctx->ls;
227 
229  entry_timeout_time = e->last_heard + (f64) SRV6_AD_CACHE_TIMEOUT;
230  if (ctx->now >= entry_timeout_time)
231  {
232  ad_flow_entry_delete (ls, e, 1);
233  return 1;
234  }
235  return 0;
236 }
237 
238 /****************************** Local SID node *******************************/
239 
240 /**
241  * @brief Function doing SRH processing for AD behavior
242  */
245  ip6_ext_header_t *first_hdr,
246  u8 first_hdr_type, u8 expected_hdr_type,
247  u32 *encap_length, u8 **found_hdr)
248 {
249  if (PREDICT_TRUE (first_hdr_type == expected_hdr_type))
250  {
251  *found_hdr = (void *) first_hdr;
252  }
253  else
254  {
255  u8 ext_hdr_type = first_hdr_type;
256  ip6_ext_header_t *ext_hdr = first_hdr;
257 
258  if (!ip6_ext_hdr (ext_hdr_type))
259  {
260  *found_hdr = NULL;
261  return -1;
262  }
263 
264  u32 ext_hdr_length = ip6_ext_header_len (ext_hdr);
265  if (!vlib_object_within_buffer_data (vm, b, ext_hdr, ext_hdr_length))
266  {
267  *found_hdr = NULL;
268  return -2;
269  }
270  *encap_length += ext_hdr_length;
271  ext_hdr_type = ext_hdr->next_hdr;
272 
273  while (ext_hdr_type != expected_hdr_type && ip6_ext_hdr (ext_hdr_type))
274  {
275  ext_hdr = ip6_ext_next_header (ext_hdr);
276  ext_hdr_length = ip6_ext_header_len (ext_hdr);
277  if (!vlib_object_within_buffer_data (vm, b, ext_hdr, ext_hdr_length))
278  {
279  *found_hdr = NULL;
280  return -2;
281  }
282  *encap_length += ext_hdr_length;
283  ext_hdr_type = ext_hdr->next_hdr;
284  }
285 
286  if (ext_hdr_type != expected_hdr_type)
287  {
288  *found_hdr = NULL;
289  return -1;
290  }
291 
292  *found_hdr = ip6_ext_next_header (ext_hdr);
293  }
294 
295  return 0;
296 }
297 
298 /**
299  * @brief Function doing SRH processing for per-flow AD behavior (IPv6 inner
300  * traffic)
301  */
304  srv6_ad_flow_localsid_t *ls_mem, u32 *next,
305  vlib_combined_counter_main_t **cnt, u32 *cnt_idx,
306  f64 now)
307 {
308  ip6_sr_main_t *srm = &sr_main;
310  ip6_address_t *new_dst;
311  u32 encap_length = sizeof (ip6_header_t);
312  ip6_sr_header_t *srh;
313  clib_bihash_40_8_t *h = &ls_mem->ftable;
314  ip6_header_t *ulh = NULL;
315  u16 src_port = 0, dst_port = 0;
316  srv6_ad_flow_entry_t *e = NULL;
319 
320  /* Find SRH in the extension header chain */
321  end_ad_flow_walk_expect_first_hdr (vm, b, (void *) (ip + 1), ip->protocol,
322  IP_PROTOCOL_IPV6_ROUTE, &encap_length,
323  (u8 **) &srh);
324 
325  /* Punt the packet if no SRH or SRH with SL = 0 */
326  if (PREDICT_FALSE (srh == NULL || srh->type != ROUTING_HEADER_TYPE_SR ||
327  srh->segments_left == 0))
328  {
330  *cnt = &(sm->sid_punt_counters);
331  *cnt_idx = ls_mem->index;
332  return;
333  }
334 
335  /* Decrement Segments Left and update Destination Address */
336  srh->segments_left -= 1;
337  new_dst = (ip6_address_t *) (srh->segments) + srh->segments_left;
338  ip->dst_address.as_u64[0] = new_dst->as_u64[0];
339  ip->dst_address.as_u64[1] = new_dst->as_u64[1];
340 
341  /* Compute the total encapsulation size and determine ULH type */
342  encap_length += ip6_ext_header_len ((ip6_ext_header_t *) srh);
343 
344  /* Find the inner IPv6 header (ULH) */
346  vm, b, ip6_ext_next_header ((ip6_ext_header_t *) srh), srh->protocol,
347  IP_PROTOCOL_IPV6, &encap_length, (u8 **) &ulh);
348 
349  if (PREDICT_FALSE (ulh == NULL))
350  {
351  if (ret == -1) /* Bypass the NF if ULH is not of expected type */
352  {
354  *cnt = &(sm->sid_bypass_counters);
355  *cnt_idx = ls_mem->index;
356  }
357  else
358  {
360  *cnt = &(srm->sr_ls_invalid_counters);
361  }
362  return;
363  }
364 
365  /* Compute flow hash on ULH */
366  if (PREDICT_TRUE (ulh->protocol == IP_PROTOCOL_UDP ||
367  ulh->protocol == IP_PROTOCOL_TCP))
368  {
369  udp_header_t *ulh_l4_hdr = (udp_header_t *) (ulh + 1);
370  src_port = ulh_l4_hdr->src_port;
371  dst_port = ulh_l4_hdr->dst_port;
372  }
373 
374  kv.key[0] = ulh->src_address.as_u64[0];
375  kv.key[1] = ulh->src_address.as_u64[1];
376  kv.key[2] = ulh->dst_address.as_u64[0];
377  kv.key[3] = ulh->dst_address.as_u64[1];
378  kv.key[4] = ((u64) src_port << 16) | ((u64) dst_port);
379 
380  /* Lookup flow in hashtable */
381  if (!clib_bihash_search_40_8 (h, &kv, &value))
382  {
383  e = pool_elt_at_index (ls_mem->cache,
385  }
386 
387  if (!e)
388  {
389  if (pool_elts (ls_mem->cache) >= ls_mem->cache_size)
390  {
391  if (!ad_flow_lru_free_one (ls_mem, now))
392  {
394  *cnt = &(sm->sid_cache_full_counters);
395  *cnt_idx = ls_mem->index;
396  return;
397  }
398  }
399 
400  e = ad_flow_entry_alloc (ls_mem, now);
401  ASSERT (e);
402  e->key.s_addr.ip6.as_u64[0] = ulh->src_address.as_u64[0];
403  e->key.s_addr.ip6.as_u64[1] = ulh->src_address.as_u64[1];
404  e->key.d_addr.ip6.as_u64[0] = ulh->dst_address.as_u64[0];
405  e->key.d_addr.ip6.as_u64[1] = ulh->dst_address.as_u64[1];
406  e->key.s_port = src_port;
407  e->key.d_port = dst_port;
408  e->key.proto = ulh->protocol;
409 
410  kv.value = (u64) (e - ls_mem->cache);
411 
412  ctx.now = now;
413  ctx.ls = ls_mem;
414  clib_bihash_add_or_overwrite_stale_40_8 (h, &kv,
416  }
417  e->last_heard = now;
418 
419  /* Cache encapsulation headers */
420  if (PREDICT_FALSE (encap_length > e->rw_len))
421  {
422  vec_validate (e->rw_data, encap_length - 1);
423  }
424  clib_memcpy_fast (e->rw_data, ip, encap_length);
425  e->rw_len = encap_length;
426 
427  /* Update LRU */
428  ad_flow_entry_update_lru (ls_mem, e);
429 
430  /* Decapsulate the packet */
431  vlib_buffer_advance (b, encap_length);
432 
433  /* Set next node */
435 
436  /* Set Xconnect adjacency to VNF */
437  vnet_buffer (b)->ip.adj_index[VLIB_TX] = ls_mem->nh_adj;
438 }
439 
442  srv6_ad_flow_localsid_t *ls_mem, u32 *next,
443  vlib_combined_counter_main_t **cnt, u32 *cnt_idx,
444  f64 now)
445 {
446  ip6_sr_main_t *srm = &sr_main;
448  ip6_address_t *new_dst;
449  u32 encap_length = sizeof (ip6_header_t);
450  ip6_sr_header_t *srh;
451  clib_bihash_40_8_t *h = &ls_mem->ftable;
452  ip4_header_t *ulh = NULL;
453  u16 src_port = 0, dst_port = 0;
454  srv6_ad_flow_entry_t *e = NULL;
457 
458  /* Find SRH in the extension header chain */
459  end_ad_flow_walk_expect_first_hdr (vm, b, (void *) (ip + 1), ip->protocol,
460  IP_PROTOCOL_IPV6_ROUTE, &encap_length,
461  (u8 **) &srh);
462 
463  /* Punt the packet if no SRH or SRH with SL = 0 */
464  if (PREDICT_FALSE (srh == NULL || srh->type != ROUTING_HEADER_TYPE_SR ||
465  srh->segments_left == 0))
466  {
468  *cnt = &(sm->sid_punt_counters);
469  *cnt_idx = ls_mem->index;
470  return;
471  }
472 
473  /* Decrement Segments Left and update Destination Address */
474  srh->segments_left -= 1;
475  new_dst = (ip6_address_t *) (srh->segments) + srh->segments_left;
476  ip->dst_address.as_u64[0] = new_dst->as_u64[0];
477  ip->dst_address.as_u64[1] = new_dst->as_u64[1];
478 
479  /* Add SRH length to the total encapsulation size */
480  encap_length += ip6_ext_header_len ((ip6_ext_header_t *) srh);
481 
482  /* Find the inner IPv6 header (ULH) */
484  vm, b, ip6_ext_next_header ((ip6_ext_header_t *) srh), srh->protocol,
485  IP_PROTOCOL_IP_IN_IP, &encap_length, (u8 **) &ulh);
486 
487  if (PREDICT_FALSE (ulh == NULL))
488  {
489  if (ret == -1) /* Bypass the NF if ULH is not of expected type */
490  {
492  *cnt = &(sm->sid_bypass_counters);
493  *cnt_idx = ls_mem->index;
494  }
495  else
496  {
498  *cnt = &(srm->sr_ls_invalid_counters);
499  }
500  return;
501  }
502 
503  /* Compute flow hash on ULH */
504  if (PREDICT_TRUE (ulh->protocol == IP_PROTOCOL_UDP ||
505  ulh->protocol == IP_PROTOCOL_TCP))
506  {
507  udp_header_t *ulh_l4_hdr = (udp_header_t *) (ulh + 1);
508  src_port = ulh_l4_hdr->src_port;
509  dst_port = ulh_l4_hdr->dst_port;
510  }
511 
512  kv.key[0] = *((u64 *) &ulh->address_pair);
513  kv.key[1] = ((u64) src_port << 16) | ((u64) dst_port);
514  kv.key[2] = 0;
515  kv.key[3] = 0;
516  kv.key[4] = 0;
517 
518  /* Lookup flow in hashtable */
519  if (!clib_bihash_search_40_8 (h, &kv, &value))
520  {
521  e = pool_elt_at_index (ls_mem->cache,
523  }
524 
525  if (!e)
526  {
527  if (pool_elts (ls_mem->cache) >= ls_mem->cache_size)
528  {
529  if (!ad_flow_lru_free_one (ls_mem, now))
530  {
532  *cnt = &(sm->sid_cache_full_counters);
533  *cnt_idx = ls_mem->index;
534  return;
535  }
536  }
537 
538  e = ad_flow_entry_alloc (ls_mem, now);
539  ASSERT (e);
540  e->key.s_addr.ip4 = ulh->src_address;
541  e->key.d_addr.ip4 = ulh->dst_address;
542  e->key.s_port = src_port;
543  e->key.d_port = dst_port;
544  e->key.proto = ulh->protocol;
545 
546  kv.value = (u64) (e - ls_mem->cache);
547 
548  ctx.now = now;
549  ctx.ls = ls_mem;
550  clib_bihash_add_or_overwrite_stale_40_8 (h, &kv,
552  }
553  e->last_heard = now;
554 
555  /* Cache encapsulation headers */
556  if (PREDICT_FALSE (encap_length > e->rw_len))
557  {
558  vec_validate (e->rw_data, encap_length - 1);
559  }
560  clib_memcpy_fast (e->rw_data, ip, encap_length);
561  e->rw_len = encap_length;
562 
563  /* Update LRU */
564  ad_flow_entry_update_lru (ls_mem, e);
565 
566  /* Decapsulate the packet */
567  vlib_buffer_advance (b, encap_length);
568 
569  /* Set next node */
571 
572  /* Set Xconnect adjacency to VNF */
573  vnet_buffer (b)->ip.adj_index[VLIB_TX] = ls_mem->nh_adj;
574 }
575 
576 /**
577  * @brief SRv6 AD Localsid graph node
578  */
579 static uword
582 {
583  ip6_sr_main_t *srm = &sr_main;
584  f64 now = vlib_time_now (vm);
585  u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
587 
588  from = vlib_frame_vector_args (frame);
589  n_left_from = frame->n_vectors;
590  next_index = node->cached_next_index;
591 
592  while (n_left_from > 0)
593  {
594  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
595 
596  /* TODO: Dual/quad loop */
597 
598  while (n_left_from > 0 && n_left_to_next > 0)
599  {
600  u32 bi0;
601  vlib_buffer_t *b0;
602  ip6_header_t *ip0 = 0;
603  ip6_sr_localsid_t *ls0;
604  srv6_ad_flow_localsid_t *ls_mem0;
605  u32 next0;
607  u32 cnt_idx0;
608 
609  bi0 = from[0];
610  to_next[0] = bi0;
611  from += 1;
612  to_next += 1;
613  n_left_from -= 1;
614  n_left_to_next -= 1;
615 
616  b0 = vlib_get_buffer (vm, bi0);
617  ip0 = vlib_buffer_get_current (b0);
618 
619  /* Retrieve local SID context based on IP DA (adj) */
620  ls0 = pool_elt_at_index (srm->localsids,
621  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
622 
623  cnt_idx0 = ls0 - srm->localsids;
624 
625  /* Retrieve local SID's plugin memory */
626  ls_mem0 = ls0->plugin_mem;
627 
628  /* SRH processing */
629  if (ls_mem0->inner_type == AD_TYPE_IP6)
630  end_ad_flow_processing_v6 (vm, b0, ip0, ls_mem0, &next0, &cnt0,
631  &cnt_idx0, now);
632  else
633  end_ad_flow_processing_v4 (vm, b0, ip0, ls_mem0, &next0, &cnt0,
634  &cnt_idx0, now);
635 
636  /* Trace packet (if enabled) */
637  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
638  {
640  vlib_add_trace (vm, node, b0, sizeof *tr);
641  tr->localsid_index = ls_mem0->index;
642  }
643 
644  /* Increment the appropriate per-SID counter */
646  cnt0, thread_index, cnt_idx0, 1,
647  vlib_buffer_length_in_chain (vm, b0));
648 
649  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
650  n_left_to_next, bi0, next0);
651  }
652  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
653  }
654 
655  return frame->n_vectors;
656 }
657 
659  .function = srv6_ad_flow_localsid_fn,
660  .name = "srv6-ad-flow-localsid",
661  .vector_size = sizeof (u32),
662  .format_trace = format_srv6_ad_flow_localsid_trace,
664  .n_next_nodes = SRV6_AD_FLOW_LOCALSID_N_NEXT,
665  .next_nodes = {
666  [SRV6_AD_FLOW_LOCALSID_NEXT_PUNT] = "ip6-local",
667  [SRV6_AD_FLOW_LOCALSID_NEXT_BYPASS] = "ip6-lookup",
668  [SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE4] = "ip4-rewrite",
669  [SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE6] = "ip6-rewrite",
670  [SRV6_AD_FLOW_LOCALSID_NEXT_ERROR] = "error-drop",
671  },
672 };
673 
674 /****************************** Rewriting node *******************************/
675 
676 /**
677  * @brief Graph node for applying a SR policy into an IPv6 packet.
678  * Encapsulation
679  */
680 static uword
683 {
684  ip6_sr_main_t *srm = &sr_main;
686  u32 n_left_from, next_index, *from, *to_next;
687  u32 cnt_packets = 0;
688 
689  from = vlib_frame_vector_args (frame);
690  n_left_from = frame->n_vectors;
691  next_index = node->cached_next_index;
692 
693  while (n_left_from > 0)
694  {
695  u32 n_left_to_next;
696 
697  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
698 
699  /* TODO: Dual/quad loop */
700 
701  while (n_left_from > 0 && n_left_to_next > 0)
702  {
703  u32 bi0;
704  vlib_buffer_t *b0;
705  ip4_header_t *ip0_encap = 0;
706  ip6_header_t *ip0 = 0;
707  ip6_sr_localsid_t *ls0;
708  srv6_ad_flow_localsid_t *ls0_mem;
711  u16 new_l0 = 0;
712 
713  bi0 = from[0];
714  to_next[0] = bi0;
715  from += 1;
716  to_next += 1;
717  n_left_from -= 1;
718  n_left_to_next -= 1;
719 
720  b0 = vlib_get_buffer (vm, bi0);
721  ip0_encap = vlib_buffer_get_current (b0);
722  ls0 = pool_elt_at_index (
723  srm->localsids,
725  ls0_mem = ls0->plugin_mem;
726 
727  if (PREDICT_FALSE (ls0_mem == NULL))
728  {
730  b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
731  }
732  else
733  {
734  clib_bihash_kv_40_8_t kv0, value0;
735 
736  /* Compute flow hash */
737  u64 ports = 0;
738  if (PREDICT_TRUE (ip0_encap->protocol == IP_PROTOCOL_UDP ||
739  ip0_encap->protocol == IP_PROTOCOL_TCP))
740  {
741  udp_header_t *udp0 = (udp_header_t *) (ip0_encap + 1);
742  ports =
743  ((u64) udp0->src_port << 16) | ((u64) udp0->dst_port);
744  }
745 
746  kv0.key[0] = *((u64 *) &ip0_encap->address_pair);
747  kv0.key[1] = ports;
748  kv0.key[2] = 0;
749  kv0.key[3] = 0;
750  kv0.key[4] = 0;
751 
752  /* Lookup flow in hashtable */
753  if (clib_bihash_search_40_8 (&ls0_mem->ftable, &kv0, &value0) <
754  0)
755  {
756  /* not found */
758  b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
759  }
760  else
761  {
762  /* found */
763  s0 = pool_elt_at_index (
764  ls0_mem->cache, ad_flow_value_get_session_index (&value0));
765  ASSERT (s0);
767  (s0->rw_len + b0->current_data));
768 
769  clib_memcpy_fast (((u8 *) ip0_encap) - s0->rw_len,
770  s0->rw_data, s0->rw_len);
771  vlib_buffer_advance (b0, -(word) s0->rw_len);
772 
773  ip0 = vlib_buffer_get_current (b0);
774 
775  /* Update inner IPv4 TTL and checksum */
776  u32 checksum0;
777  ip0_encap->ttl -= 1;
778  checksum0 =
779  ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
780  checksum0 += checksum0 >= 0xffff;
781  ip0_encap->checksum = checksum0;
782 
783  /* Update outer IPv6 length (in case it has changed) */
784  new_l0 = s0->rw_len - sizeof (ip6_header_t) +
785  clib_net_to_host_u16 (ip0_encap->length);
786  ip0->payload_length = clib_host_to_net_u16 (new_l0);
787  }
788  }
789 
790  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
791  PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
792  {
794  vlib_add_trace (vm, node, b0, sizeof *tr);
795  tr->error = 0;
796 
797  if (next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR)
798  {
799  tr->error = 1;
800  }
801  else
802  {
803  clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
804  sizeof tr->src.as_u8);
805  clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
806  sizeof tr->dst.as_u8);
807  }
808  }
809 
810  /* Increment per-SID AD rewrite counters */
812  ((next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR) ?
813  &(sm->rw_invalid_counters) :
814  &(sm->rw_valid_counters)),
815  vm->thread_index, ls0_mem->index, 1,
816  vlib_buffer_length_in_chain (vm, b0));
817 
818  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
819  n_left_to_next, bi0, next0);
820 
821  cnt_packets++;
822  }
823 
824  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
825  }
826 
827  /* Update counters */
829  SRV6_AD_FLOW_REWRITE_COUNTER_PROCESSED,
830  cnt_packets);
831 
832  return frame->n_vectors;
833 }
834 
836  .function = srv6_ad4_flow_rewrite_fn,
837  .name = "srv6-ad4-flow-rewrite",
838  .vector_size = sizeof (u32),
839  .format_trace = format_srv6_ad_flow_rewrite_trace,
842  .error_strings = srv6_ad_flow_rewrite_counter_strings,
843  .n_next_nodes = SRV6_AD_FLOW_REWRITE_N_NEXT,
844  .next_nodes = {
845  [SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
846  [SRV6_AD_FLOW_REWRITE_NEXT_ERROR] = "error-drop",
847  },
848 };
849 
850 /**
851  * @brief Graph node for applying a SR policy into an IPv6 packet.
852  * Encapsulation
853  */
854 static uword
857 {
858  ip6_sr_main_t *srm = &sr_main;
860  u32 n_left_from, next_index, *from, *to_next;
861  u32 cnt_packets = 0;
862 
863  from = vlib_frame_vector_args (frame);
864  n_left_from = frame->n_vectors;
865  next_index = node->cached_next_index;
866 
867  while (n_left_from > 0)
868  {
869  u32 n_left_to_next;
870 
871  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
872 
873  /* TODO: Dual/quad loop */
874 
875  while (n_left_from > 0 && n_left_to_next > 0)
876  {
877  u32 bi0;
878  vlib_buffer_t *b0;
879  ip6_header_t *ip0 = 0, *ip0_encap = 0;
880  ip6_sr_localsid_t *ls0;
881  srv6_ad_flow_localsid_t *ls0_mem;
884  u16 new_l0 = 0;
885 
886  bi0 = from[0];
887  to_next[0] = bi0;
888  from += 1;
889  to_next += 1;
890  n_left_from -= 1;
891  n_left_to_next -= 1;
892 
893  b0 = vlib_get_buffer (vm, bi0);
894  ip0_encap = vlib_buffer_get_current (b0);
895  ls0 = pool_elt_at_index (
896  srm->localsids,
898  ls0_mem = ls0->plugin_mem;
899 
900  if (PREDICT_FALSE (ls0_mem == NULL))
901  {
903  b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
904  }
905  else
906  {
907  /* ############################################# */
908  clib_bihash_kv_40_8_t kv0, value0;
909 
910  /* Compute flow hash */
911  u64 ports = 0;
912  if (PREDICT_TRUE (ip0_encap->protocol == IP_PROTOCOL_UDP ||
913  ip0_encap->protocol == IP_PROTOCOL_TCP))
914  {
915  udp_header_t *udp0 = (udp_header_t *) (ip0_encap + 1);
916  ports =
917  ((u64) udp0->src_port << 16) | ((u64) udp0->dst_port);
918  }
919 
920  kv0.key[0] = ip0_encap->src_address.as_u64[0];
921  kv0.key[1] = ip0_encap->src_address.as_u64[1];
922  kv0.key[2] = ip0_encap->dst_address.as_u64[0];
923  kv0.key[3] = ip0_encap->dst_address.as_u64[1];
924  kv0.key[4] = ports;
925 
926  /* Lookup flow in hashtable */
927  if (clib_bihash_search_40_8 (&ls0_mem->ftable, &kv0, &value0))
928  {
929  /* not found */
931  b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
932  }
933  else
934  {
935  /* found */
936  s0 = pool_elt_at_index (
937  ls0_mem->cache, ad_flow_value_get_session_index (&value0));
938  ASSERT (s0);
939 
941  (s0->rw_len + b0->current_data));
942 
943  clib_memcpy_fast (((u8 *) ip0_encap) - s0->rw_len,
944  s0->rw_data, s0->rw_len);
945  vlib_buffer_advance (b0, -(word) s0->rw_len);
946 
947  ip0 = vlib_buffer_get_current (b0);
948 
949  /* Update inner IPv6 hop limit */
950  ip0_encap->hop_limit -= 1;
951 
952  /* Update outer IPv6 length (in case it has changed) */
953  new_l0 = s0->rw_len +
954  clib_net_to_host_u16 (ip0_encap->payload_length);
955  ip0->payload_length = clib_host_to_net_u16 (new_l0);
956  }
957  }
958 
959  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
960  PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
961  {
963  vlib_add_trace (vm, node, b0, sizeof *tr);
964  tr->error = 0;
965 
966  if (next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR)
967  {
968  tr->error = 1;
969  }
970  else
971  {
972  clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
973  sizeof tr->src.as_u8);
974  clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
975  sizeof tr->dst.as_u8);
976  }
977  }
978 
979  /* Increment per-SID AD rewrite counters */
981  ((next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR) ?
982  &(sm->rw_invalid_counters) :
983  &(sm->rw_valid_counters)),
984  vm->thread_index, ls0_mem->index, 1,
985  vlib_buffer_length_in_chain (vm, b0));
986 
987  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
988  n_left_to_next, bi0, next0);
989 
990  cnt_packets++;
991  }
992 
993  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
994  }
995 
996  /* Update counters */
998  SRV6_AD_FLOW_REWRITE_COUNTER_PROCESSED,
999  cnt_packets);
1000 
1001  return frame->n_vectors;
1002 }
1003 
1005  .function = srv6_ad6_flow_rewrite_fn,
1006  .name = "srv6-ad6-flow-rewrite",
1007  .vector_size = sizeof (u32),
1008  .format_trace = format_srv6_ad_flow_rewrite_trace,
1010  .n_errors = SRV6_AD_FLOW_REWRITE_N_COUNTERS,
1011  .error_strings = srv6_ad_flow_rewrite_counter_strings,
1012  .n_next_nodes = SRV6_AD_FLOW_REWRITE_N_NEXT,
1013  .next_nodes = {
1014  [SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
1015  [SRV6_AD_FLOW_REWRITE_NEXT_ERROR] = "error-drop",
1016  },
1017 };
1018 
1019 /*
1020  * fd.io coding-style-patch-verification: ON
1021  *
1022  * Local Variables:
1023  * eval: (c-set-style "gnu")
1024  * End:
1025  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:524
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:133
ip6_sr_main_t sr_main
Definition: sr.c:31
f64 now
Definition: ad-flow.h:120
static_always_inline int end_ad_flow_walk_expect_first_hdr(vlib_main_t *vm, vlib_buffer_t *b, ip6_ext_header_t *first_hdr, u8 first_hdr_type, u8 expected_hdr_type, u32 *encap_length, u8 **found_hdr)
Function doing SRH processing for AD behavior.
Definition: node.c:244
#define CLIB_UNUSED(x)
Definition: clib.h:90
u32 lru_index
Definition: ad-flow.h:55
static u32 ad_flow_value_get_session_index(clib_bihash_kv_40_8_t *value)
Definition: node.c:215
static int vlib_object_within_buffer_data(vlib_main_t *vm, vlib_buffer_t *b, void *obj, size_t len)
Definition: ip6_packet.h:555
SR LocalSID.
Definition: sr.h:122
ip6_address_t src
Definition: node.c:33
u32 thread_index
#define PREDICT_TRUE(x)
Definition: clib.h:125
static_always_inline int ad_flow_lru_insert(srv6_ad_flow_localsid_t *ls, srv6_ad_flow_entry_t *e, f64 now)
Definition: node.c:112
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:119
unsigned long u64
Definition: types.h:89
vl_api_ip_port_and_mask_t dst_port
Definition: flow_types.api:92
vlib_increment_combined_counter(ccm, ti, sw_if_index, n_buffers, n_bytes)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:325
srv6_ad_flow_entry_t * cache
Cache table.
Definition: ad-flow.h:82
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:51
u32 thread_index
Definition: main.h:213
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: nat44_ei.c:3048
srv6_ad_flow_rewrite_counters
Definition: node.c:76
ip46_address_t d_addr
Definition: ad-flow.h:44
static void * ip6_ext_next_header(ip6_ext_header_t *ext_hdr)
Definition: ip6_packet.h:549
vlib_node_registration_t srv6_ad4_flow_rewrite_node
(constructor) VLIB_REGISTER_NODE (srv6_ad4_flow_rewrite_node)
Definition: node.c:67
#define ROUTING_HEADER_TYPE_SR
Definition: sr_packet.h:117
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:461
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:433
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
vlib_combined_counter_main_t sr_ls_invalid_counters
Definition: sr.h:303
vlib_combined_counter_main_t sr_ls_valid_counters
Definition: sr.h:302
ip6_address_t src_address
Definition: ip6_packet.h:310
unsigned char u8
Definition: types.h:56
vlib_buffer_t ** b
double f64
Definition: types.h:142
static char * srv6_ad_flow_rewrite_counter_strings[]
Definition: node.c:84
unsigned int u32
Definition: types.h:88
static_always_inline void end_ad_flow_processing_v4(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip, srv6_ad_flow_localsid_t *ls_mem, u32 *next, vlib_combined_counter_main_t **cnt, u32 *cnt_idx, f64 now)
Definition: node.c:441
f64 last_heard
Definition: ad-flow.h:61
#define static_always_inline
Definition: clib.h:112
i64 word
Definition: types.h:111
ip6_address_t dst
Definition: node.c:33
srv6_ad_flow_localsid_t * ls
Definition: ad-flow.h:119
static uword srv6_ad4_flow_rewrite_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Graph node for applying a SR policy into an IPv6 packet.
Definition: node.c:681
u32 * sw_iface_localsid6
Retrieve local SID from iface.
Definition: ad-flow.h:102
#define SRV6_AD_CACHE_TIMEOUT
Definition: ad-flow.h:33
description fragment has unexpected format
Definition: map.api:433
vlib_combined_counter_main_t sid_cache_full_counters
Definition: ad-flow.h:109
#define AD_TYPE_IP4
Definition: ad.h:27
u8 proto
Definition: ad-flow.h:45
static uword srv6_ad6_flow_rewrite_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Graph node for applying a SR policy into an IPv6 packet.
Definition: node.c:855
Definition: ad-flow.h:38
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:145
u16 s_port
Definition: ad-flow.h:46
static void ad_flow_entry_delete(srv6_ad_flow_localsid_t *ls, srv6_ad_flow_entry_t *e, int lru_delete)
Definition: node.c:137
u16 * next
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
struct srv6_ad_flow_entry_t::@134 key
dlist_elt_t * lru_pool
Definition: ad-flow.h:83
long ctx[MAX_CONNS]
Definition: main.c:144
static void clib_dlist_addtail(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:43
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
u8 * rw_data
Definition: ad-flow.h:52
ip4_address_pair_t address_pair
Definition: ip4_packet.h:127
static_always_inline int ad_flow_lru_free_one(srv6_ad_flow_localsid_t *ls, f64 now)
Definition: node.c:173
#define PREDICT_FALSE(x)
Definition: clib.h:124
static u8 * format_srv6_ad_flow_rewrite_trace(u8 *s, va_list *args)
Definition: node.c:49
f64 last_lru_update
Definition: ad-flow.h:58
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
#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:224
#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:395
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1244
#define ip6_ext_header_len(p)
Definition: ip6_packet.h:545
ip6_sr_localsid_t * localsids
Definition: sr.h:272
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
srv6_ad_flow_rewrite_next_t
Definition: node.c:102
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:388
static void clib_dlist_addhead(dlist_elt_t *pool, u32 head_index, u32 new_index)
Definition: dlist.h:71
format_function_t format_ip6_address
Definition: format.h:91
srv6_ad_flow_localsid_next_t
Definition: node.c:92
static u8 * format_srv6_ad_flow_localsid_trace(u8 *s, va_list *args)
Definition: node.c:37
#define AD_TYPE_IP6
Definition: ad.h:28
u32 rw_len
Definition: ad-flow.h:51
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
static void ad_flow_entry_update_lru(srv6_ad_flow_localsid_t *ls, srv6_ad_flow_entry_t *e)
Definition: node.c:125
vlib_combined_counter_main_t sid_bypass_counters
Packets/bytes bypassing NF.
Definition: ad-flow.h:107
static_always_inline srv6_ad_flow_entry_t * ad_flow_entry_alloc(srv6_ad_flow_localsid_t *ls, f64 now)
Definition: node.c:200
vlib_combined_counter_main_t sid_punt_counters
Packets/bytes punted.
Definition: ad-flow.h:108
srv6_ad_flow_main_t srv6_ad_flow_main
Definition: ad-flow.c:41
static u8 ip6_ext_hdr(u8 nexthdr)
Definition: ip6_packet.h:524
static uword srv6_ad_flow_localsid_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
SRv6 AD Localsid graph node.
Definition: node.c:580
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:498
u8 value
Definition: qos.api:54
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:337
clib_bihash_40_8_t ftable
Flow table.
Definition: ad-flow.h:81
#define ASSERT(truth)
u32 * sw_iface_localsid4
Retrieve local SID from iface.
Definition: ad-flow.h:101
void * plugin_mem
Memory to be used by the plugin callback functions.
Definition: sr.h:155
#define always_inline
Definition: rdma_mlx5dv.h:23
vlib_combined_counter_main_t rw_invalid_counters
Invalid rewrite counters.
Definition: ad-flow.h:114
vlib_put_next_frame(vm, node, next_index, 0)
Definition: ad-flow.h:117
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:276
int ad_flow_is_idle_entry_cb(clib_bihash_kv_40_8_t *kv, void *arg)
Definition: node.c:221
static void clib_dlist_remove(dlist_elt_t *pool, u32 index)
Definition: dlist.h:99
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
nat44_ei_hairpin_src_next_t next_index
u32 value
Definition: dlist.h:32
struct _vlib_node_registration vlib_node_registration_t
vlib_node_registration_t srv6_ad6_flow_rewrite_node
(constructor) VLIB_REGISTER_NODE (srv6_ad6_flow_rewrite_node)
Definition: node.c:68
Definition: defs.h:47
u16 payload_length
Definition: ip6_packet.h:301
vl_api_address_t ip
Definition: l2.api:558
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
ip46_address_t s_addr
Definition: ad-flow.h:43
VLIB buffer representation.
Definition: buffer.h:111
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
static_always_inline void end_ad_flow_processing_v6(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip, srv6_ad_flow_localsid_t *ls_mem, u32 *next, vlib_combined_counter_main_t **cnt, u32 *cnt_idx, f64 now)
Function doing SRH processing for per-flow AD behavior (IPv6 inner traffic)
Definition: node.c:303
A collection of combined counters.
Definition: counter.h:203
#define foreach_srv6_ad_flow_rewrite_counter
Definition: node.c:72
#define vnet_buffer(b)
Definition: buffer.h:437
Segment Routing main datastructure.
Definition: sr.h:257
vl_api_ip4_address_t dst
Definition: pnat.api:41
f64 now
u16 flags
Copy of main node flags.
Definition: node.h:492
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
u32 nh_adj
Adjacency index for out.
Definition: ad-flow.h:72
u16 d_port
Definition: ad-flow.h:47
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:292
vlib_combined_counter_main_t rw_valid_counters
Valid rewrite counters.
Definition: ad-flow.h:112
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:310
static u32 clib_dlist_remove_head(dlist_elt_t *pool, u32 head_index)
Definition: dlist.h:117
vlib_node_registration_t srv6_ad_flow_localsid_node
(constructor) VLIB_REGISTER_NODE (srv6_ad_flow_localsid_node)
Definition: node.c:658
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127