6bd38ff2968f413dab5724d199cf90d484409add
[vpp.git] / src / plugins / ioam / lib-e2e / ioam_seqno_lib.h
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 #ifndef PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_
17 #define PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_
18
19 #include <vppinfra/types.h>
20
21 #define SEQ_CHECK_VALUE 0x80000000      /* for seq number wraparound detection */
22
23 #define SEQNO_WINDOW_SIZE 2048
24 #define SEQNO_WINDOW_ARRAY_SIZE 64
25
26 typedef struct seqno_bitmap_
27 {
28   u32 window_size;
29   u32 array_size;
30   u32 mask;
31   u32 pad;
32   u64 highest;
33   u64 array[SEQNO_WINDOW_ARRAY_SIZE];   /* Will be alloc to array_size */
34 } seqno_bitmap;
35
36 typedef struct seqno_rx_info_
37 {
38   u64 rx_packets;
39   u64 lost_packets;
40   u64 reordered_packets;
41   u64 dup_packets;
42   seqno_bitmap bitmap;
43 } seqno_rx_info;
44
45 /* This structure is 64-byte aligned */
46 typedef struct ioam_seqno_data_
47 {
48   union
49   {
50     u32 seq_num;                /* Useful only for encap node */
51     seqno_rx_info seqno_rx;
52   };
53 } ioam_seqno_data;
54
55 static inline void
56 BIT_SET (u64 * p, u32 n)
57 {
58   p[n >> 5] |= (1 << (n & 31));
59 }
60
61 static inline int
62 BIT_TEST (u64 * p, u32 n)
63 {
64   return p[n >> 5] & (1 << (n & 31));
65 }
66
67 static void
68 BIT_CLEAR (u64 * p, u64 start, int num_bits, u32 mask)
69 {
70   int n, t;
71   int start_index = (start >> 5);
72   int mask_index = (mask >> 5);
73
74   start_index &= mask_index;
75   if (start & 0x1f)
76     {
77       int start_bit = (start & 0x1f);
78
79       n = (1 << start_bit) - 1;
80       t = start_bit + num_bits;
81       if (t < 32)
82         {
83           n |= ~((1 << t) - 1);
84           p[start_index] &= n;
85           return;
86         }
87       p[start_index] &= n;
88       start_index = (start_index + 1) & mask_index;
89       num_bits -= (32 - start_bit);
90     }
91   while (num_bits >= 32)
92     {
93       p[start_index] = 0;
94       start_index = (start_index + 1) & mask_index;
95       num_bits -= 32;
96     }
97   n = ~((1 << num_bits) - 1);
98   p[start_index] &= n;
99 }
100
101 static inline u8
102 seqno_check_wraparound (u32 a, u32 b)
103 {
104   if ((a != b) && (a > b) && ((a - b) > SEQ_CHECK_VALUE))
105     {
106       return 1;
107     }
108   return 0;
109 }
110
111 /*
112  * Function to analyze the PPC value recevied.
113  *     - Updates the bitmap with received sequence number
114  *     - counts the received/lost/duplicate/reordered packets
115  */
116 inline static void
117 ioam_analyze_seqno (seqno_rx_info * seqno_rx, u64 seqno)
118 {
119   int diff;
120   static int peer_dead_count;
121   seqno_bitmap *bitmap = &seqno_rx->bitmap;
122
123   seqno_rx->rx_packets++;
124
125   if (seqno > bitmap->highest)
126     {                           /* new larger sequence number */
127       peer_dead_count = 0;
128       diff = seqno - bitmap->highest;
129       if (diff < bitmap->window_size)
130         {
131           if (diff > 1)
132             {                   /* diff==1 is *such* a common case it's a win to optimize it */
133               BIT_CLEAR (bitmap->array, bitmap->highest + 1, diff - 1,
134                          bitmap->mask);
135               seqno_rx->lost_packets += diff - 1;
136             }
137         }
138       else
139         {
140           seqno_rx->lost_packets += diff - 1;
141           memset (bitmap->array, 0, bitmap->array_size * sizeof (u64));
142         }
143       BIT_SET (bitmap->array, seqno & bitmap->mask);
144       bitmap->highest = seqno;
145       return;
146     }
147
148   /* we've seen a bigger seq number before */
149   diff = bitmap->highest - seqno;
150   if (diff >= bitmap->window_size)
151     {
152       if (seqno_check_wraparound (bitmap->highest, seqno))
153         {
154           memset (bitmap->array, 0, bitmap->array_size * sizeof (u64));
155           BIT_SET (bitmap->array, seqno & bitmap->mask);
156           bitmap->highest = seqno;
157           return;
158         }
159       else
160         {
161           peer_dead_count++;
162           if (peer_dead_count > 25)
163             {
164               peer_dead_count = 0;
165               memset (bitmap->array, 0, bitmap->array_size * sizeof (u64));
166               BIT_SET (bitmap->array, seqno & bitmap->mask);
167               bitmap->highest = seqno;
168             }
169           //ppc_rx->reordered_packets++;
170         }
171       return;
172     }
173
174   if (BIT_TEST (bitmap->array, seqno & bitmap->mask))
175     {
176       seqno_rx->dup_packets++;
177       return;                   /* Already seen */
178     }
179   seqno_rx->reordered_packets++;
180   seqno_rx->lost_packets--;
181   BIT_SET (bitmap->array, seqno & bitmap->mask);
182   return;
183 }
184
185 u8 *show_ioam_seqno_analyse_data_fn (u8 * s, seqno_rx_info * rx);
186
187 u8 *show_ioam_seqno_cmd_fn (u8 * s, ioam_seqno_data * seqno_data, u8 enc);
188
189 void ioam_seqno_init_data (ioam_seqno_data * data);
190
191 void ioam_seqno_init_rx_info (seqno_rx_info * data);
192
193 #endif /* PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_ */
194
195 /*
196  * fd.io coding-style-patch-verification: ON
197  *
198  * Local Variables:
199  * eval: (c-set-style "gnu")
200  * End:
201  */