vrrp: add stats support and update API
[vpp.git] / src / plugins / vrrp / vrrp.h
1
2 /*
3  * vrrp.h - vrrp plug-in header file
4  *
5  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  *
9  */
10 #ifndef __included_vrrp_h__
11 #define __included_vrrp_h__
12
13 #include <vnet/vnet.h>
14 #include <vnet/ip/ip.h>
15 #include <vnet/ethernet/ethernet.h>
16
17 #include <vppinfra/hash.h>
18 #include <vppinfra/error.h>
19
20 /* VRRP configuration */
21 typedef enum vrrp_vr_flags
22 {
23   VRRP_VR_PREEMPT = 0x1,
24   VRRP_VR_ACCEPT = 0x2,
25   VRRP_VR_UNICAST = 0x4,
26   VRRP_VR_IPV6 = 0x8,
27 } vrrp_vr_flags_t;
28
29 typedef struct vrrp_vr_key
30 {
31   u32 sw_if_index;
32   u8 vr_id;
33   u8 is_ipv6;
34 } vrrp_vr_key_t;
35
36 /* *INDENT-OFF* */
37 typedef CLIB_PACKED
38 (struct vrrp4_arp_key {
39   union {
40     struct {
41       u32 sw_if_index;
42       ip4_address_t addr;
43     };
44     u64 as_u64;
45   };
46 }) vrrp4_arp_key_t;
47 /* *INDENT-ON* */
48
49 /* *INDENT-OFF* */
50 typedef CLIB_PACKED
51 (struct vrrp6_nd_key {
52   u32 sw_if_index;
53   ip6_address_t addr;
54 }) vrrp6_nd_key_t;
55 /* *INDENT-ON* */
56
57 typedef struct vrrp_vr_tracking_if
58 {
59   u32 sw_if_index;
60   u8 priority;
61 } vrrp_vr_tracking_if_t;
62
63 typedef struct vrrp_vr_tracking
64 {
65   vrrp_vr_tracking_if_t *interfaces;
66   u32 interfaces_dec;
67 } vrrp_vr_tracking_t;
68
69 typedef struct vrrp_vr_config
70 {
71   u32 sw_if_index;
72   u8 vr_id;
73   u8 priority;
74   u16 adv_interval;
75   vrrp_vr_flags_t flags;
76   ip46_address_t *vr_addrs;
77   ip46_address_t *peer_addrs;
78 } vrrp_vr_config_t;
79
80 #define foreach_vrrp_vr_state           \
81 _(0, INIT, "Initialize")                \
82 _(1, BACKUP, "Backup")                  \
83 _(2, MASTER, "Master")                  \
84 _(3, INTF_DOWN, "Interface Down")
85
86 /* VRRP runtime data */
87 typedef enum vrrp_vr_state
88 {
89 #define _(v,f,n) VRRP_VR_STATE_##f = v,
90   foreach_vrrp_vr_state
91 #undef _
92 } vrrp_vr_state_t;
93
94 typedef struct vrrp_vr_runtime
95 {
96   vrrp_vr_state_t state;
97   u16 master_adv_int;
98   u16 skew;
99   u16 master_down_int;
100   mac_address_t mac;
101   f64 last_sent;
102   u32 timer_index;
103 } vrrp_vr_runtime_t;
104
105 /* Per-VR data */
106 typedef struct vrrp_vr
107 {
108   vrrp_vr_config_t config;
109   vrrp_vr_runtime_t runtime;
110   vrrp_vr_tracking_t tracking;
111   u32 stat_index;
112 } vrrp_vr_t;
113
114 /* Timers */
115 typedef enum vrrp_vr_timer_type
116 {
117   VRRP_VR_TIMER_ADV,
118   VRRP_VR_TIMER_MASTER_DOWN,
119 } vrrp_vr_timer_type_t;
120
121 typedef struct vrrp_vr_timer
122 {
123   u32 vr_index;
124   f64 expire_time;              /* monotonic, relative to vlib_time_now() */
125   vrrp_vr_timer_type_t type;
126 } vrrp_vr_timer_t;
127
128 typedef struct
129 {
130   /* vectors of vr indices which are configured on this interface
131    * 0 -> ipv4, 1 -> ipv6 */
132   u32 *vr_indices[2];
133
134   /* vector of VR indices which track the state of this interface
135    * 0 -> ipv4, 1*/
136   u32 *tracking_vrs[2];
137
138   /* multicast adjacency indices. 0 -> ipv4, 1 -> ipv6 */
139   adj_index_t mcast_adj_index[2];
140
141   /* number of VRs in master state on sw intf. 0 -> ipv4, 1 -> ipv6 */
142   u8 n_master_vrs[2];
143
144 } vrrp_intf_t;
145
146 typedef struct
147 {
148   /* API message ID base */
149   u16 msg_id_base;
150
151   /* pool of VRs */
152   vrrp_vr_t *vrs;
153
154   /* pool of timers and ordered vector of pool indices */
155   vrrp_vr_timer_t *vr_timers;
156   u32 *pending_timers;
157
158   /* number of running VRs - don't register for VRRP proto if not running */
159   u16 n_vrs_started;
160
161   /* hash mapping a VR key to a pool entry */
162   mhash_t vr_index_by_key;
163
164   /* hashes mapping sw_if_index and address to a vr index */
165   uword *vrrp4_arp_lookup;
166   uword *vrrp6_nd_lookup;
167
168   /* vector of interface data indexed by sw_if_index */
169   vrrp_intf_t *vrrp_intfs;
170
171   /* convenience */
172   vlib_main_t *vlib_main;
173   vnet_main_t *vnet_main;
174   ethernet_main_t *ethernet_main;
175
176   u32 intf_output_node_idx;
177 } vrrp_main_t;
178
179 extern vrrp_main_t vrrp_main;
180
181 extern vlib_node_registration_t vrrp_node;
182 extern vlib_node_registration_t vrrp_periodic_node;
183
184 /* Periodic function events */
185 #define VRRP_EVENT_VR_TIMER_UPDATE 1
186 #define VRRP_EVENT_VR_STOP 2
187 #define VRRP_EVENT_PERIODIC_ENABLE_DISABLE 3
188
189 /* global error counter types */
190 #define foreach_vrrp_err_counter                                              \
191   _ (CHKSUM, 0)                                                               \
192   _ (VERSION, 1)                                                              \
193   _ (VRID, 2)                                                                 \
194   _ (TTL, 3)                                                                  \
195   _ (ADDR_LIST, 4)                                                            \
196   _ (PKT_LEN, 5)
197
198 typedef enum vrrp_err_counter_
199 {
200 #define _(sym, val) VRRP_ERR_COUNTER_##sym = val,
201   foreach_vrrp_err_counter
202 #undef _
203 } vrrp_err_counter_t;
204
205 #define VRRP_ERR_COUNTER_MAX 6
206
207 /* per-instance stats */
208 #define foreach_vrrp_stat_counter                                             \
209   _ (MASTER_TRANS, 0)                                                         \
210   _ (ADV_SENT, 1)                                                             \
211   _ (ADV_RCVD, 2)                                                             \
212   _ (PRIO0_SENT, 3)                                                           \
213   _ (PRIO0_RCVD, 4)
214
215 typedef enum vrrp_stat_counter_
216 {
217 #define _(sym, val) VRRP_STAT_COUNTER_##sym = val,
218   foreach_vrrp_stat_counter
219 #undef _
220 } vrrp_stat_counter_t;
221
222 #define VRRP_STAT_COUNTER_MAX 5
223
224 clib_error_t *vrrp_plugin_api_hookup (vlib_main_t * vm);
225
226 int vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t *conf, index_t *ret_index);
227 int vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf);
228 int vrrp_vr_del (index_t vrrp_index);
229 int vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key);
230 extern u8 *format_vrrp_vr (u8 * s, va_list * args);
231 extern u8 *format_vrrp_vr_key (u8 * s, va_list * args);
232 extern u8 *format_vrrp_vr_state (u8 * s, va_list * args);
233 extern u8 *format_vrrp_packet_hdr (u8 * s, va_list * args);
234 void vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type);
235 void vrrp_vr_timer_cancel (vrrp_vr_t * vr);
236 void vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state,
237                          void *data);
238 int vrrp_vr_set_peers (vrrp_vr_key_t * key, ip46_address_t * peers);
239 int vrrp_vr_multicast_group_join (vrrp_vr_t * vr);
240 int vrrp_adv_send (vrrp_vr_t * vr, int shutdown);
241 int vrrp_garp_or_na_send (vrrp_vr_t * vr);
242 u16 vrrp_adv_csum (void *l3_hdr, void *payload, u8 is_ipv6, u16 len);
243 int vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index,
244                                  u8 priority, u8 is_add);
245 int vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
246                                   vrrp_vr_tracking_if_t * track_ifs,
247                                   u8 is_add);
248 void vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state);
249
250 // stats
251 void vrrp_incr_err_counter (vrrp_err_counter_t err_type);
252 void vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index);
253
254 always_inline void
255 vrrp_vr_skew_compute (vrrp_vr_t * vr)
256 {
257   vrrp_vr_config_t *vrc = &vr->config;
258   vrrp_vr_runtime_t *vrt = &vr->runtime;
259
260   vrt->skew = (((256 - vrc->priority) * vrt->master_adv_int) / 256);
261 }
262
263 always_inline void
264 vrrp_vr_master_down_compute (vrrp_vr_t * vr)
265 {
266   vrrp_vr_runtime_t *vrt = &vr->runtime;
267
268   vrt->master_down_int = (3 * vrt->master_adv_int) + vrt->skew;
269 }
270
271 always_inline vrrp_vr_t *
272 vrrp_vr_lookup (u32 sw_if_index, u8 vr_id, u8 is_ipv6)
273 {
274   vrrp_main_t *vmp = &vrrp_main;
275   vrrp_vr_key_t key;
276   uword *p;
277
278   clib_memset (&key, 0, sizeof (key));
279
280   key.sw_if_index = sw_if_index;
281   key.vr_id = vr_id;
282   key.is_ipv6 = (is_ipv6 != 0);
283
284   p = mhash_get (&vmp->vr_index_by_key, &key);
285   if (p)
286     return pool_elt_at_index (vmp->vrs, p[0]);
287
288   return 0;
289 }
290
291 always_inline vrrp_vr_t *
292 vrrp_vr_lookup_index (u32 vr_index)
293 {
294   vrrp_main_t *vmp = &vrrp_main;
295
296   if (pool_is_free_index (vmp->vrs, vr_index))
297     return 0;
298
299   return pool_elt_at_index (vmp->vrs, vr_index);
300 }
301
302 always_inline u32
303 vrrp_vr_lookup_address (u32 sw_if_index, u8 is_ipv6, void *addr)
304 {
305   vrrp_main_t *vmp = &vrrp_main;
306   uword *p;
307   vrrp4_arp_key_t key4;
308   vrrp6_nd_key_t key6;
309
310   if (is_ipv6)
311     {
312       key6.sw_if_index = sw_if_index;
313       key6.addr = ((ip6_address_t *) addr)[0];
314       p = hash_get_mem (vmp->vrrp6_nd_lookup, &key6);
315     }
316   else
317     {
318       key4.sw_if_index = sw_if_index;
319       key4.addr = ((ip4_address_t *) addr)[0];
320       p = hash_get (vmp->vrrp4_arp_lookup, key4.as_u64);
321     }
322
323   if (p)
324     return p[0];
325
326   return ~0;
327 }
328
329 always_inline vrrp_intf_t *
330 vrrp_intf_get (u32 sw_if_index)
331 {
332   vrrp_main_t *vrm = &vrrp_main;
333
334   if (sw_if_index == ~0)
335     return NULL;
336
337   vec_validate (vrm->vrrp_intfs, sw_if_index);
338   return vec_elt_at_index (vrm->vrrp_intfs, sw_if_index);
339 }
340
341 always_inline int
342 vrrp_intf_num_vrs (u32 sw_if_index, u8 is_ipv6)
343 {
344   vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);
345
346   if (intf)
347     return vec_len (intf->vr_indices[is_ipv6]);
348
349   return 0;
350 }
351
352 always_inline u8
353 vrrp_vr_is_ipv6 (vrrp_vr_t * vr)
354 {
355   return ((vr->config.flags & VRRP_VR_IPV6) != 0);
356 }
357
358 always_inline u8
359 vrrp_vr_is_unicast (vrrp_vr_t * vr)
360 {
361   return ((vr->config.flags & VRRP_VR_UNICAST) != 0);
362 }
363
364 always_inline u8
365 vrrp_vr_is_owner (vrrp_vr_t * vr)
366 {
367   return (vr->config.priority == 255);
368 }
369
370 always_inline u8
371 vrrp_vr_n_vr_addrs (vrrp_vr_t * vr)
372 {
373   return vec_len (vr->config.vr_addrs);
374 }
375
376 always_inline u8
377 vrrp_vr_n_peer_addrs (vrrp_vr_t * vr)
378 {
379   return vec_len (vr->config.peer_addrs);
380 }
381
382 always_inline u8
383 vrrp_vr_accept_mode_enabled (vrrp_vr_t * vr)
384 {
385   return ((vr->config.flags & VRRP_VR_ACCEPT) != 0);
386 }
387
388 always_inline u32
389 vrrp_vr_index (vrrp_vr_t * vr)
390 {
391   vrrp_main_t *vmp = &vrrp_main;
392
393   return vr - vmp->vrs;
394 }
395
396 always_inline u8
397 vrrp_vr_priority (vrrp_vr_t * vr)
398 {
399   u8 rv;
400
401   if (vr->tracking.interfaces_dec < (u32) vr->config.priority)
402     rv = vr->config.priority - vr->tracking.interfaces_dec;
403   else
404     rv = 1;
405
406   return rv;
407 }
408
409 #endif /* __included_vrrp_h__ */
410
411 /*
412  * fd.io coding-style-patch-verification: ON
413  *
414  * Local Variables:
415  * eval: (c-set-style "gnu")
416  * End:
417  */