FD.io VPP  v17.04.2-2-ga8f93f8
Vector Packet Processing
ioam_cache.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 #ifndef __included_ioam_cache_h__
16 #define __included_ioam_cache_h__
17 
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip_packet.h>
21 #include <vnet/ip/ip4_packet.h>
22 #include <vnet/ip/ip6_packet.h>
23 #include <vnet/sr/sr.h>
24 
25 #include <vppinfra/pool.h>
26 #include <vppinfra/hash.h>
27 #include <vppinfra/error.h>
28 #include <vppinfra/elog.h>
29 #include <vppinfra/bihash_8_8.h>
32 /*
33  * ioam_cache.h
34  * This header contains routines for caching of ioam header and
35  * buffer:
36  * 1 - On application facing node: to cache ioam header recvd
37  * in request and reattach in response to provide round
38  * trip path visibility. Since request response matching
39  * is needed works with TCP and relies on (5 tuples,seq no)
40  * 2 - On M-Anycast server node: This node replicates requests
41  * towards multiple anycast service nodes serving anycast
42  * IP6 address. It evaluates response and forwards the best
43  * response towards the client of requesting the service.
44  * Again since request-response matching is needed, works
45  * with TCP and relies on (5 tuples,seq no) for matching.
46  * To do this it caches SYN-ACK responses for a short time to
47  * evaluate multiple responses received before the selected
48  * SYN-ACK response is forwared and others dropped.
49  *
50  * M-Anycast server cache:
51  * - There is a pool of cache entries per worker thread.
52  * - Cache entry is created when SYN is received expected
53  * number of responses are marked based on number of
54  * SR tunnels for the anycast destination address
55  * - The pool/thread id and pool index are attached in the
56  * message as an ioam option for quick look up.
57  * - When is received SYN-ACK the ioam option containing
58  * thread id + pool index of the cache entry is used to
59  * look up cache entry.
60  * - Cache synchronization:
61  * - This is achieved by cache entry add/del/update all handled
62  * by the same worker/main thread
63  * - Packets from client to threads - syn packets, can be disctributed
64  * based on incoming interface affinity to the cpu core pinned to
65  * the thread or a simple sequence number based distribution
66  * if thread per interface is not scaling
67  * - Response packets from server towards clients - syn-acks, are
68  * forced to the same thread that created the cache entry
69  * using SR and the destination of SR v6 address assigned
70  * to the core/thread. This adderss is sent as an ioam option
71  * in the syn that can be then used on the other side to
72  * populate v6 dst address in the response
73  * - Timeout: timer wheel per thread is used to track the syn-ack wait
74  * time. The timer wheel tick is updated via an input node per thread.
75  *
76  * Application facing node/Service side cache:
77  * - Single pool of cache entries.
78  * - Cache entry is created when SYN is received. Caches the ioam
79  * header. Hash table entry is created based on 5 tuple and
80  * TCP seq no to pool index
81  * - Response SYN-ACK processed by looking up pool index in hash table
82  * and cache entry in the pool is used to get the ioam header rewrite
83  * string. Entry is freed from pool and hash table after use.
84  * - Locking/Synchronization: Currently this functionality is deployed
85  * with main/single thread only. Hence no locking is used.
86  * - Deployment: A VPP node per application server servicing anycast
87  * address is expected. Locking/synchronization needed when the server
88  * /application facing node is started with multiple worker threads.
89  *
90  */
91 
92 /*
93  * Application facing server side caching:
94  * Cache entry for ioam header
95  * Currently caters to TCP and relies on
96  * TCP - 5 tuples + seqno to cache and reinsert
97  * ioam header b/n TCP request response
98  */
99 typedef struct
100 {
111 
112 /*
113  * Cache entry for anycast server selection
114  * Works for TCP as 5 tuple + sequence number
115  * is required for request response matching
116  * max_responses expected is set based on number
117  * of SR tunnels for the dst_address
118  * Timeout or all response_received = max_responses
119  * will clear the entry
120  * buffer_index index of the response msg vlib buffer
121  * that is currently the best response
122  */
123 typedef struct
124 {
134  ip6_hop_by_hop_header_t *hbh; //pointer to hbh header in the buffer
139  /** Handle returned from tw_start_timer */
141  /** entry should expire at this clock tick */
144 
145 /*
146  * Per thread tunnel selection cache stats
147  */
148 typedef struct
149 {
153 
154 /* Server side: iOAM header caching */
155 #define MAX_CACHE_ENTRIES 4096
156 /* M-Anycast: Cache for SR tunnel selection */
157 #define MAX_CACHE_TS_ENTRIES 1048576
158 
159 #define IOAM_CACHE_TABLE_DEFAULT_HASH_NUM_BUCKETS (4 * 1024)
160 #define IOAM_CACHE_TABLE_DEFAULT_HASH_MEMORY_SIZE (2<<20)
161 
162 typedef struct
163 {
164  /* API message ID base */
166 
167  /* Pool of ioam_cache_buffer_t */
169 
170  /* For steering packets ioam cache entry is followed by
171  * SR header. This is the SR rewrite template */
173  /* The current rewrite string being used */
177 
180  clib_bihash_8_8_t ioam_rewrite_cache_table;
181 
182  /* M-Anycast: Pool of ioam_cache_ts_entry_t per thread */
185  /** per thread single-wheel */
186  tw_timer_wheel_16t_2w_512sl_t *timer_wheels;
187 
188  /*
189  * Selection criteria: oneway delay: Server to M-Anycast
190  * or RTT
191  */
195 
196  /* convenience */
198 
205 
207 
210 
211 /* Compute flow hash. We'll use it to select which Sponge to use for this
212  * flow. And other things.
213  * ip6_compute_flow_hash in ip6.h doesnt locate tcp/udp when
214  * ext headers are present. While it could be made to it will be a
215  * performance hit for ECMP flows.
216  * HEnce this function here, with L4 information directly input
217  * Useful when tcp/udp headers are already located in presence of
218  * ext headers
219  */
222  u8 protocol,
223  u16 src_port,
224  u16 dst_port, flow_hash_config_t flow_hash_config)
225 {
226  u64 a, b, c;
227  u64 t1, t2;
228 
229  t1 = (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1]);
230  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_ADDR) ? t1 : 0;
231 
232  t2 = (ip->dst_address.as_u64[0] ^ ip->dst_address.as_u64[1]);
233  t2 = (flow_hash_config & IP_FLOW_HASH_DST_ADDR) ? t2 : 0;
234 
235  a = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t2 : t1;
236  b = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? t1 : t2;
237  b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? protocol : 0;
238 
239  t1 = src_port;
240  t2 = dst_port;
241 
242  t1 = (flow_hash_config & IP_FLOW_HASH_SRC_PORT) ? t1 : 0;
243  t2 = (flow_hash_config & IP_FLOW_HASH_DST_PORT) ? t2 : 0;
244 
245  c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
246  ((t1 << 16) | t2) : ((t2 << 16) | t1);
247 
248  hash_mix64 (a, b, c);
249  return (u32) c;
250 }
251 
252 
253 /* 2 new ioam E2E options :
254  * 1. HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID: IP6 address
255  * of ioam node that inserted ioam header
256  * 2. HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID: Pool id and index
257  * to look up tunnel select cache entry
258  */
259 #define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID 30
260 #define HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID 31
261 
262 typedef CLIB_PACKED (struct
263  {
264  ip6_hop_by_hop_option_t hdr; u8 e2e_type; u8 reserved[5];
265  ip6_address_t id;
266  }) ioam_e2e_id_option_t;
267 
268 typedef CLIB_PACKED (struct
269  {
270  ip6_hop_by_hop_option_t hdr; u8 e2e_type; u8 pool_id;
271  u32 pool_index;
272  }) ioam_e2e_cache_option_t;
273 
274 #define IOAM_E2E_ID_OPTION_RND ((sizeof(ioam_e2e_id_option_t) + 7) & ~7)
275 #define IOAM_E2E_ID_HBH_EXT_LEN (IOAM_E2E_ID_OPTION_RND >> 3)
276 #define IOAM_E2E_CACHE_OPTION_RND ((sizeof(ioam_e2e_cache_option_t) + 7) & ~7)
277 #define IOAM_E2E_CACHE_HBH_EXT_LEN (IOAM_E2E_CACHE_OPTION_RND >> 3)
278 
279 static inline void
280 ioam_e2e_id_rewrite_handler (ioam_e2e_id_option_t * e2e_option,
281  ip6_address_t * address)
282 {
283  e2e_option->id.as_u64[0] = address->as_u64[0];
284  e2e_option->id.as_u64[1] = address->as_u64[1];
285 
286 }
287 
288 /* Following functions are for the caching of ioam header
289  * to enable reattaching it for a complete request-response
290  * message exchange */
291 inline static void
293 {
295  if (entry)
296  {
297  vec_free (entry->ioam_rewrite_string);
298  memset (entry, 0, sizeof (*entry));
299  pool_put (cm->ioam_rewrite_pool, entry);
300  }
301 }
302 
303 inline static ioam_cache_entry_t *
305 {
307  ioam_cache_entry_t *entry = 0;
308 
309  entry = pool_elt_at_index (cm->ioam_rewrite_pool, pool_index);
310  ioam_cache_entry_free (entry);
311  return (0);
312 }
313 
314 inline static ioam_cache_entry_t *
315 ioam_cache_lookup (ip6_header_t * ip0, u16 src_port, u16 dst_port, u32 seq_no)
316 {
318  u32 flow_hash = ip6_compute_flow_hash_ext (ip0, ip0->protocol,
319  src_port, dst_port,
322  clib_bihash_kv_8_8_t kv, value;
323 
324  kv.key = (u64) flow_hash << 32 | seq_no;
325  kv.value = 0;
326  value.key = 0;
327  value.value = 0;
328 
329  if (clib_bihash_search_8_8 (&cm->ioam_rewrite_cache_table, &kv, &value) >=
330  0)
331  {
332  ioam_cache_entry_t *entry = 0;
333 
334  entry = pool_elt_at_index (cm->ioam_rewrite_pool, value.value);
335  /* match */
336  if (ip6_address_compare (&ip0->src_address, &entry->dst_address) == 0 &&
337  ip6_address_compare (&ip0->dst_address, &entry->src_address) == 0 &&
338  entry->src_port == dst_port &&
339  entry->dst_port == src_port && entry->seq_no == seq_no)
340  {
341  /* If lookup is successful remove it from the hash */
342  clib_bihash_add_del_8_8 (&cm->ioam_rewrite_cache_table, &kv, 0);
343  return (entry);
344  }
345  else
346  return (0);
347 
348  }
349  return (0);
350 }
351 
352 /*
353  * Caches ioam hbh header
354  * Extends the hbh header with option to contain IP6 address of the node
355  * that caches it
356  */
357 inline static int
359  ip6_header_t * ip0,
360  u16 src_port,
361  u16 dst_port, ip6_hop_by_hop_header_t * hbh0, u32 seq_no)
362 {
364  ioam_cache_entry_t *entry = 0;
365  u32 rewrite_len = 0, e2e_id_offset = 0;
366  u32 pool_index = 0;
367  ioam_e2e_id_option_t *e2e = 0;
368 
370  memset (entry, 0, sizeof (*entry));
371  pool_index = entry - cm->ioam_rewrite_pool;
372 
374  sizeof (ip6_address_t));
376  sizeof (ip6_address_t));
377  entry->src_port = src_port;
378  entry->dst_port = dst_port;
379  entry->seq_no = seq_no;
380  rewrite_len = ((hbh0->length + 1) << 3);
381  vec_validate (entry->ioam_rewrite_string, rewrite_len - 1);
383  if (e2e)
384  {
385  entry->next_hop.as_u64[0] = e2e->id.as_u64[0];
386  entry->next_hop.as_u64[1] = e2e->id.as_u64[1];
387  }
388  else
389  {
390  return (-1);
391  }
392  e2e_id_offset = (u8 *) e2e - (u8 *) hbh0;
393  /* setup e2e id option to insert v6 address of the node caching it */
394  clib_memcpy (entry->ioam_rewrite_string, hbh0, rewrite_len);
396 
397  /* suffix rewrite string with e2e ID option */
398  e2e = (ioam_e2e_id_option_t *) (entry->ioam_rewrite_string + e2e_id_offset);
400  entry->my_address_offset = (u8 *) (&e2e->id) - (u8 *) hbh0;
401 
402  /* add it to hash, replacing and freeing any collision for now */
403  u32 flow_hash =
404  ip6_compute_flow_hash_ext (ip0, hbh0->protocol, src_port, dst_port,
406  clib_bihash_kv_8_8_t kv, value;
407  kv.key = (u64) flow_hash << 32 | seq_no;
408  kv.value = 0;
409  if (clib_bihash_search_8_8 (&cm->ioam_rewrite_cache_table, &kv, &value) >=
410  0)
411  {
412  /* replace */
414  }
415  kv.value = pool_index;
416  clib_bihash_add_del_8_8 (&cm->ioam_rewrite_cache_table, &kv, 1);
417  return (0);
418 }
419 
420 /* Creates SR rewrite string
421  * This is appended with ioam header on the server facing
422  * node.
423  * This SR header is necessary to attract packets towards
424  * selected Anycast server.
425  */
426 inline static void
428 {
430  ip6_address_t *segments = 0;
431  ip6_address_t *this_seg = 0;
432 
433  /* This nodes address and the original dest will be
434  * filled when the packet is processed */
435  vec_add2 (segments, this_seg, 1);
436  memset (this_seg, 0xfe, sizeof (ip6_address_t));
438  vec_free (segments);
439 }
440 
441 inline static int
443 {
445 
451 
452  clib_bihash_init_8_8 (&cm->ioam_rewrite_cache_table,
453  "ioam rewrite cache table",
455  /* Create SR rewrite template */
457  return (1);
458 }
459 
460 inline static int
462 {
464  ioam_cache_entry_t *entry = 0;
465  /* free pool and hash table */
466  clib_bihash_free_8_8 (&cm->ioam_rewrite_cache_table);
467  pool_foreach (entry, cm->ioam_rewrite_pool, (
468  {
469  ioam_cache_entry_free (entry);
470  }));
472  cm->ioam_rewrite_pool = 0;
474  cm->sr_rewrite_template = 0;
475  return (0);
476 }
477 
478 inline static u8 *
479 format_ioam_cache_entry (u8 * s, va_list * args)
480 {
481  ioam_cache_entry_t *e = va_arg (*args, ioam_cache_entry_t *);
483  int rewrite_len = vec_len (e->ioam_rewrite_string);
484 
485  s = format (s, "%d: %U:%d to %U:%d seq_no %lu\n",
486  (e - cm->ioam_rewrite_pool),
488  e->src_port,
490 
491  if (rewrite_len)
492  {
493  s = format (s, " %U",
496  rewrite_len - 1);
497  }
498  return s;
499 }
500 
502 
503 #define IOAM_CACHE_TS_TIMEOUT 1.0 //SYN timeout 1 sec
504 #define IOAM_CACHE_TS_TICK 100e-3
505 /* Timer delays as multiples of 100ms */
506 #define IOAM_CACHE_TS_TIMEOUT_TICKS IOAM_CACHE_TS_TICK*9
507 #define TIMER_HANDLE_INVALID ((u32) ~0)
508 
509 
510 void expired_cache_ts_timer_callback (u32 * expired_timers);
511 
512 /*
513  * Following functions are to manage M-Anycast server selection
514  * cache
515  * There is a per worker thread pool to create a cache entry
516  * for a TCP SYN received. TCP SYN-ACK contians ioam header
517  * with HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID option to point to the
518  * entry.
519  */
520 inline static int
522 {
524  int no_of_threads = vec_len (vlib_worker_threads);
525  int i;
526 
527  vec_validate_aligned (cm->ioam_ts_pool, no_of_threads - 1,
529  vec_validate_aligned (cm->ts_stats, no_of_threads - 1,
531  vec_validate_aligned (cm->timer_wheels, no_of_threads - 1,
536  for (i = 0; i < no_of_threads; i++)
537  {
540  memset (&cm->ts_stats[i], 0, sizeof (ioam_cache_ts_pool_stats_t));
541  tw_timer_wheel_init_16t_2w_512sl (&cm->timer_wheels[i],
544  /* timer period 100ms */ ,
545  10e4);
546  cm->timer_wheels[i].last_run_time = vlib_time_now (vm);
547  }
549  return (1);
550 }
551 
552 always_inline void
554  ioam_cache_ts_entry_t * entry, u32 interval)
555 {
556  entry->timer_handle
557  = tw_timer_start_16t_2w_512sl (&cm->timer_wheels[entry->pool_id],
558  entry->pool_index, 1, interval);
559 }
560 
561 always_inline void
563  ioam_cache_ts_entry_t * entry)
564 {
565  tw_timer_stop_16t_2w_512sl (&cm->timer_wheels[entry->pool_id],
566  entry->timer_handle);
568 }
569 
570 inline static void
572  ioam_cache_ts_entry_t * entry, u32 node_index)
573 {
575  vlib_main_t *vm = cm->vlib_main;
576  vlib_frame_t *nf = 0;
577  u32 *to_next;
578 
579  if (entry)
580  {
581  if (entry->hbh != 0)
582  {
583  nf = vlib_get_frame_to_node (vm, node_index);
584  nf->n_vectors = 0;
585  to_next = vlib_frame_vector_args (nf);
586  nf->n_vectors = 1;
587  to_next[0] = entry->buffer_index;
588  vlib_put_frame_to_node (vm, node_index, nf);
589  }
590  pool_put (cm->ioam_ts_pool[thread_id], entry);
591  cm->ts_stats[thread_id].inuse--;
592  memset (entry, 0, sizeof (*entry));
593  }
594 }
595 
596 inline static int
598 {
600  ioam_cache_ts_entry_t *entry = 0;
601  int no_of_threads = vec_len (vlib_worker_threads);
602  int i;
603 
604  /* free pool and hash table */
605  for (i = 0; i < no_of_threads; i++)
606  {
607  pool_foreach (entry, cm->ioam_ts_pool[i], (
608  {
609  ioam_cache_ts_entry_free (i,
610  entry,
611  cm->error_node_index);
612  }
613  ));
614  pool_free (cm->ioam_ts_pool[i]);
615  cm->ioam_ts_pool = 0;
616  tw_timer_wheel_free_16t_2w_512sl (&cm->timer_wheels[i]);
617  }
618  vec_free (cm->ioam_ts_pool);
619  return (0);
620 }
621 
622 inline static int
623 ioam_cache_ts_entry_cleanup (u32 thread_id, u32 pool_index)
624 {
626  ioam_cache_ts_entry_t *entry = 0;
627 
628  entry = pool_elt_at_index (cm->ioam_ts_pool[thread_id], pool_index);
629  ioam_cache_ts_entry_free (thread_id, entry, cm->error_node_index);
630  return (0);
631 }
632 
633 /*
634  * Caches buffer for ioam SR tunnel select for Anycast service
635  */
636 inline static int
638  u16 src_port,
639  u16 dst_port,
640  u32 seq_no,
641  u8 max_responses, u64 now, u32 thread_id, u32 * pool_index)
642 {
644  ioam_cache_ts_entry_t *entry = 0;
645 
646  if (cm->ts_stats[thread_id].inuse == MAX_CACHE_TS_ENTRIES)
647  {
648  cm->ts_stats[thread_id].add_failed++;
649  return (-1);
650  }
651 
652  pool_get_aligned (cm->ioam_ts_pool[thread_id], entry,
654  memset (entry, 0, sizeof (*entry));
655  *pool_index = entry - cm->ioam_ts_pool[thread_id];
656 
658  sizeof (ip6_address_t));
660  sizeof (ip6_address_t));
661  entry->src_port = src_port;
662  entry->dst_port = dst_port;
663  entry->seq_no = seq_no;
664  entry->response_received = 0;
665  entry->max_responses = max_responses;
666  entry->created_at = now;
667  entry->hbh = 0;
668  entry->buffer_index = 0;
669  entry->pool_id = thread_id;
670  entry->pool_index = *pool_index;
672  cm->ts_stats[thread_id].inuse++;
673  return (0);
674 }
675 
676 inline static void
677 ioam_cache_ts_send (u32 thread_id, i32 pool_index)
678 {
680  ioam_cache_ts_entry_t *entry = 0;
681 
682  entry = pool_elt_at_index (cm->ioam_ts_pool[thread_id], pool_index);
683  if (!pool_is_free (cm->ioam_ts_pool[thread_id], entry) && entry)
684  {
685  /* send and free pool entry */
686  ioam_cache_ts_entry_free (thread_id, entry, cm->ip6_hbh_pop_node_index);
687  }
688 }
689 
690 inline static void
691 ioam_cache_ts_check_and_send (u32 thread_id, i32 pool_index)
692 {
694  ioam_cache_ts_entry_t *entry = 0;
695  entry = pool_elt_at_index (cm->ioam_ts_pool[thread_id], pool_index);
696  if (entry && entry->hbh)
697  {
698  if (entry->response_received == entry->max_responses ||
700  vlib_time_now (cm->vlib_main))
701  {
702  ioam_cache_ts_timer_reset (cm, entry);
703  ioam_cache_ts_send (thread_id, pool_index);
704  }
705  }
706 }
707 
708 inline static int
710  i32 pool_index,
711  u32 buffer_index, ip6_hop_by_hop_header_t * hbh)
712 {
714  ioam_cache_ts_entry_t *entry = 0;
715  vlib_main_t *vm = cm->vlib_main;
716  vlib_frame_t *nf = 0;
717  u32 *to_next;
718 
719  entry = pool_elt_at_index (cm->ioam_ts_pool[thread_id], pool_index);
720  if (!pool_is_free (cm->ioam_ts_pool[thread_id], entry) && entry)
721  {
722  /* drop existing buffer */
723  if (entry->hbh != 0)
724  {
726  nf->n_vectors = 0;
727  to_next = vlib_frame_vector_args (nf);
728  nf->n_vectors = 1;
729  to_next[0] = entry->buffer_index;
731  }
732  /* update */
733  entry->buffer_index = buffer_index;
734  entry->hbh = hbh;
735  /* check and send */
736  ioam_cache_ts_check_and_send (thread_id, pool_index);
737  return (0);
738  }
739  return (-1);
740 }
741 
742 /*
743  * looks up the entry based on the e2e option pool index
744  * result = 0 found the entry
745  * result < 0 indicates failture to find an entry
746  */
747 inline static int
749  u8 protocol,
750  u16 src_port,
751  u16 dst_port,
752  u32 seq_no,
754  u32 * pool_index, u8 * thread_id, u8 response_seen)
755 {
757  ip6_hop_by_hop_header_t *hbh0 = 0;
758  ioam_e2e_cache_option_t *e2e = 0;
759 
760  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
761  e2e =
762  (ioam_e2e_cache_option_t *) ((u8 *) hbh0 + cm->rewrite_pool_index_offset);
763  if ((u8 *) e2e < ((u8 *) hbh0 + ((hbh0->length + 1) << 3))
764  && e2e->hdr.type == HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID)
765  {
766  ioam_cache_ts_entry_t *entry = 0;
767  *pool_index = e2e->pool_index;
768  *thread_id = e2e->pool_id;
769  entry = pool_elt_at_index (cm->ioam_ts_pool[*thread_id], *pool_index);
770  /* match */
771  if (entry &&
772  ip6_address_compare (&ip0->src_address, &entry->dst_address) == 0 &&
773  ip6_address_compare (&ip0->dst_address, &entry->src_address) == 0 &&
774  entry->src_port == dst_port &&
775  entry->dst_port == src_port && entry->seq_no == seq_no)
776  {
777  *hbh = entry->hbh;
778  entry->response_received += response_seen;
779  return (0);
780  }
781  else if (entry)
782  {
783  return (-1);
784  }
785  }
786  return (-1);
787 }
788 
789 inline static u8 *
790 format_ioam_cache_ts_entry (u8 * s, va_list * args)
791 {
792  ioam_cache_ts_entry_t *e = va_arg (*args, ioam_cache_ts_entry_t *);
793  u32 thread_id = va_arg (*args, u32);
795  ioam_e2e_id_option_t *e2e = 0;
796  vlib_main_t *vm = cm->vlib_main;
797  clib_time_t *ct = &vm->clib_time;
798 
799  if (!e)
800  goto end;
801 
802  if (e->hbh)
803  {
804  e2e =
807 
808  s =
809  format (s,
810  "%d: %U:%d to %U:%d seq_no %u buffer %u %U \n\t\tCreated at %U Received %d\n",
811  (e - cm->ioam_ts_pool[thread_id]), format_ip6_address,
813  &e->dst_address, e->dst_port, e->seq_no, e->buffer_index,
814  format_ip6_address, e2e ? &e2e->id : 0, format_time_interval,
815  "h:m:s:u",
816  (e->created_at -
818  e->response_received);
819  }
820  else
821  {
822  s =
823  format (s,
824  "%d: %U:%d to %U:%d seq_no %u Buffer %u \n\t\tCreated at %U Received %d\n",
825  (e - cm->ioam_ts_pool[thread_id]), format_ip6_address,
827  &e->dst_address, e->dst_port, e->seq_no, e->buffer_index,
828  format_time_interval, "h:m:s:u",
829  (e->created_at -
831  e->response_received);
832  }
833 
834 end:
835  return s;
836 }
837 
838 /*
839  * Get extended rewrite string for iOAM data in v6
840  * This makes space for an e2e options to carry cache pool info
841  * and manycast server address.
842  * It set the rewrite string per configs in ioam ip6 + new option
843  * for cache along with offset to the option to populate cache
844  * pool id and index
845  */
846 static inline int
848 {
852  u32 rewrite_len = 0;
853  ioam_e2e_cache_option_t *e2e = 0;
854  ioam_e2e_id_option_t *e2e_id = 0;
855 
856  vec_free (cm->rewrite);
859  hbh = (ip6_hop_by_hop_header_t *) cm->rewrite;
860  rewrite_len = ((hbh->length + 1) << 3);
861  vec_validate (cm->rewrite,
862  rewrite_len - 1 + IOAM_E2E_CACHE_OPTION_RND +
864  hbh = (ip6_hop_by_hop_header_t *) cm->rewrite;
865  /* setup e2e id option to insert pool id and index of the node caching it */
867  cm->rewrite_pool_index_offset = rewrite_len;
868  e2e = (ioam_e2e_cache_option_t *) (cm->rewrite + rewrite_len);
869  e2e->hdr.type = HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID
871  e2e->hdr.length = sizeof (ioam_e2e_cache_option_t) -
872  sizeof (ip6_hop_by_hop_option_t);
873  e2e->e2e_type = 2;
874  e2e_id =
875  (ioam_e2e_id_option_t *) ((u8 *) e2e + sizeof (ioam_e2e_cache_option_t));
876  e2e_id->hdr.type =
878  e2e_id->hdr.length =
879  sizeof (ioam_e2e_id_option_t) - sizeof (ip6_hop_by_hop_option_t);
880  e2e_id->e2e_type = 1;
881 
882  return (0);
883 }
884 
885 static inline int
887 {
889 
890  vec_free (cm->rewrite);
891  cm->rewrite = 0;
893  return (0);
894 }
895 #endif /* __included_ioam_cache_h__ */
896 
897 /*
898  * fd.io coding-style-patch-verification: ON
899  *
900  * Local Variables:
901  * eval: (c-set-style "gnu")
902  * End:
903  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
u8 rewrite_pool_index_offset
Definition: ioam_cache.h:175
ip6_address_t sr_localsid_ts
Definition: ioam_cache.h:194
ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
#define MAX_CACHE_TS_ENTRIES
Definition: ioam_cache.h:157
ioam_cache_entry_t * ioam_rewrite_pool
Definition: ioam_cache.h:168
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
static int ioam_cache_ts_table_init(vlib_main_t *vm)
Definition: ioam_cache.h:521
static ioam_cache_entry_t * ioam_cache_lookup(ip6_header_t *ip0, u16 src_port, u16 dst_port, u32 seq_no)
Definition: ioam_cache.h:315
static void ioam_cache_ts_entry_free(u32 thread_id, ioam_cache_ts_entry_t *entry, u32 node_index)
Definition: ioam_cache.h:571
a
Definition: bitmap.h:516
#define MAX_CACHE_ENTRIES
Definition: ioam_cache.h:155
#define IP_FLOW_HASH_SRC_PORT
Definition: lookup.h:147
#define IOAM_E2E_CACHE_HBH_EXT_LEN
Definition: ioam_cache.h:277
u8 protocol
Definition: ioam_cache.h:131
#define TIMER_HANDLE_INVALID
Definition: ioam_cache.h:507
u64 as_u64[2]
Definition: ip6_packet.h:51
#define IOAM_CACHE_TABLE_DEFAULT_HASH_NUM_BUCKETS
Definition: ioam_cache.h:159
Fixed length block allocator.
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:185
u32 seq_no
Definition: ioam_cache.h:106
#define IP_FLOW_HASH_REVERSE_SRC_DST
Definition: lookup.h:149
u8 * sr_rewrite_template
Definition: ioam_cache.h:172
static int ioam_cache_table_init(vlib_main_t *vm)
Definition: ioam_cache.h:442
static int ioam_cache_table_destroy(vlib_main_t *vm)
Definition: ioam_cache.h:461
ip6_address_t src_address
Definition: ioam_cache.h:127
struct _vlib_node_registration vlib_node_registration_t
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
u16 dst_port
Definition: ioam_cache.h:104
#define IP_FLOW_HASH_DST_PORT
Definition: lookup.h:148
ip6_address_t dst_address
Definition: ioam_cache.h:102
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
clib_time_t clib_time
Definition: main.h:62
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
Definition: pool.h:230
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
static void ioam_cache_ts_timer_set(ioam_cache_main_t *cm, ioam_cache_ts_entry_t *entry, u32 interval)
Definition: ioam_cache.h:553
static int ioam_cache_ts_update(u32 thread_id, i32 pool_index, u32 buffer_index, ip6_hop_by_hop_header_t *hbh)
Definition: ioam_cache.h:709
ip6_address_t src_address
Definition: ip6_packet.h:341
Definition: ioam_cache.h:99
static u8 * format_ioam_cache_ts_entry(u8 *s, va_list *args)
Definition: ioam_cache.h:790
ip6_address_t sr_localsid_cache
Definition: ioam_cache.h:176
static void ioam_cache_sr_rewrite_template_create(void)
Definition: ioam_cache.h:427
static ioam_cache_entry_t * ioam_cache_entry_cleanup(u32 pool_index)
Definition: ioam_cache.h:304
static int ip6_ioam_ts_cache_set_rewrite(void)
Definition: ioam_cache.h:847
u8 * format_ip6_hop_by_hop_ext_hdr(u8 *s, va_list *args)
Definition: ip6_forward.c:2344
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
static int ioam_cache_add(vlib_buffer_t *b0, ip6_header_t *ip0, u16 src_port, u16 dst_port, ip6_hop_by_hop_header_t *hbh0, u32 seq_no)
Definition: ioam_cache.h:358
#define IP_FLOW_HASH_DST_ADDR
Definition: lookup.h:145
#define pool_alloc_aligned(P, N, A)
Allocate N more free elements to pool (general version).
Definition: pool.h:262
#define always_inline
Definition: clib.h:84
u64 created_at
Definition: ioam_cache.h:135
u8 protocol
Definition: ioam_cache.h:105
int i32
Definition: types.h:81
static int ioam_cache_ts_add(ip6_header_t *ip0, u16 src_port, u16 dst_port, u32 seq_no, u8 max_responses, u64 now, u32 thread_id, u32 *pool_index)
Definition: ioam_cache.h:637
#define IOAM_CACHE_TABLE_DEFAULT_HASH_MEMORY_SIZE
Definition: ioam_cache.h:160
static u32 ip6_compute_flow_hash_ext(const ip6_header_t *ip, u8 protocol, u16 src_port, u16 dst_port, flow_hash_config_t flow_hash_config)
Definition: ioam_cache.h:221
unsigned long u64
Definition: types.h:89
u64 cpu_time_main_loop_start
Definition: main.h:68
#define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID
Definition: ioam_cache.h:259
tw_timer_wheel_16t_2w_512sl_t * timer_wheels
per thread single-wheel
Definition: ioam_cache.h:186
static void ioam_cache_ts_check_and_send(u32 thread_id, i32 pool_index)
Definition: ioam_cache.h:691
static void ioam_e2e_id_rewrite_handler(ioam_e2e_id_option_t *e2e_option, ip6_address_t *address)
Definition: ioam_cache.h:280
int ip6_ioam_set_rewrite(u8 **rwp, int has_trace_option, int has_pot_option, int has_seqno_option)
vlib_node_registration_t ioam_cache_ts_node
(constructor) VLIB_REGISTER_NODE (ioam_cache_ts_node)
u16 src_port
Definition: ioam_cache.h:103
ioam_cache_ts_pool_stats_t * ts_stats
Definition: ioam_cache.h:184
u32 seq_no
Definition: ioam_cache.h:132
u8 response_received
Definition: ioam_cache.h:136
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:35
Definition: ioam_cache.h:123
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
#define IOAM_CACHE_TS_TIMEOUT
Definition: ioam_cache.h:503
u64 key
the key
Definition: bihash_8_8.h:35
ioam_cache_ts_entry_t ** ioam_ts_pool
Definition: ioam_cache.h:183
vlib_node_registration_t ioam_cache_node
(constructor) VLIB_REGISTER_NODE (ioam_cache_node)
static int ip6_ioam_ts_cache_cleanup_rewrite(void)
Definition: ioam_cache.h:886
#define IOAM_E2E_ID_HBH_EXT_LEN
Definition: ioam_cache.h:275
u32 ip6_hbh_pop_node_index
Definition: ioam_cache.h:201
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
ip6_address_t src_address
Definition: ioam_cache.h:101
int ip6_address_compare(ip6_address_t *a1, ip6_address_t *a2)
Definition: ip46_cli.c:58
static void ioam_cache_entry_free(ioam_cache_entry_t *entry)
Definition: ioam_cache.h:292
static int ioam_cache_ts_lookup(ip6_header_t *ip0, u8 protocol, u16 src_port, u16 dst_port, u32 seq_no, ip6_hop_by_hop_header_t **hbh, u32 *pool_index, u8 *thread_id, u8 response_seen)
Definition: ioam_cache.h:748
f64 seconds_per_clock
Definition: time.h:57
ip6_address_t next_hop
Definition: ioam_cache.h:107
u32 cleanup_process_node_index
Definition: ioam_cache.h:203
u32 expected_to_expire
entry should expire at this clock tick
Definition: ioam_cache.h:142
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
#define pool_free(p)
Free a pool.
Definition: pool.h:290
u64 value
the value
Definition: bihash_8_8.h:36
ip6_address_t dst_address
Definition: ioam_cache.h:128
#define hash_mix64(a0, b0, c0)
Definition: hash.h:507
svmdb_client_t * c
u16 n_vectors
Definition: node.h:344
u32 pool_id
Definition: ioam_cache.h:125
format_function_t format_ip6_address
Definition: format.h:95
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static void * ip6_ioam_find_hbh_option(ip6_hop_by_hop_header_t *hbh0, u8 option)
u32 timer_handle
Handle returned from tw_start_timer.
Definition: ioam_cache.h:140
#define clib_memcpy(a, b, c)
Definition: string.h:69
8 octet key, 8 octet key value pair
Definition: bihash_8_8.h:33
u16 my_address_offset
Definition: ioam_cache.h:108
#define IP_FLOW_HASH_SRC_ADDR
Flow hash configuration.
Definition: lookup.h:144
void expired_cache_ts_timer_callback(u32 *expired_timers)
unsigned int u32
Definition: types.h:88
clib_bihash_8_8_t ioam_rewrite_cache_table
Definition: ioam_cache.h:180
u32 stop_timer_handle
Definition: ioam_cache.h:138
u32 pool_index
Definition: ioam_cache.h:126
void ioam_cache_ts_timer_node_enable(vlib_main_t *vm, u8 enable)
static u8 * format_ioam_cache_entry(u8 *s, va_list *args)
Definition: ioam_cache.h:479
#define IP_FLOW_HASH_DEFAULT
Default: 5-tuple without the "reverse" bit.
Definition: lookup.h:152
static void ioam_cache_ts_send(u32 thread_id, i32 pool_index)
Definition: ioam_cache.h:677
u32 flow_hash_config_t
A flow hash configuration is a mask of the flow hash options.
Definition: lookup.h:165
#define IOAM_E2E_CACHE_OPTION_RND
Definition: ioam_cache.h:276
u64 uword
Definition: types.h:112
static void ioam_cache_ts_timer_reset(ioam_cache_main_t *cm, ioam_cache_ts_entry_t *entry)
Definition: ioam_cache.h:562
u16 dst_port
Definition: ioam_cache.h:130
unsigned short u16
Definition: types.h:57
static int ioam_cache_ts_table_destroy(vlib_main_t *vm)
Definition: ioam_cache.h:597
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static uword max_log2(uword x)
Definition: clib.h:228
vlib_main_t * vlib_main
Definition: ioam_cache.h:197
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
u8 * format_time_interval(u8 *s, va_list *args)
Definition: std-formats.c:122
u32 buffer_index
Definition: ioam_cache.h:133
ip6_hop_by_hop_header_t * hbh
Definition: ioam_cache.h:134
Segment Routing data structures definitions.
#define HBH_OPTION_TYPE_SKIP_UNKNOWN
#define IP_FLOW_HASH_PROTO
Definition: lookup.h:146
static int ioam_cache_ts_entry_cleanup(u32 thread_id, u32 pool_index)
Definition: ioam_cache.h:623
u8 max_responses
Definition: ioam_cache.h:137
u16 src_port
Definition: ioam_cache.h:129
typedef CLIB_PACKED(struct{ip6_hop_by_hop_option_t hdr;u8 e2e_type;u8 reserved[5];ip6_address_t id;}) ioam_e2e_id_option_t
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
ioam_cache_main_t ioam_cache_main
Definition: ioam_cache.h:206
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
#define HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID
Definition: ioam_cache.h:260
u8 * ioam_rewrite_string
Definition: ioam_cache.h:109
#define IOAM_E2E_ID_OPTION_RND
Definition: ioam_cache.h:274
ip6_address_t dst_address
Definition: ip6_packet.h:341
#define IOAM_CACHE_TS_TICK
Definition: ioam_cache.h:504
static u8 * ip6_sr_compute_rewrite_string_insert(ip6_address_t *sl)
SR rewrite string computation for SRH insertion (inline)
Definition: sr.h:284