Line data Source code
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 0 : vrrp_vr_skew_compute (vrrp_vr_t * vr)
256 : {
257 0 : vrrp_vr_config_t *vrc = &vr->config;
258 0 : vrrp_vr_runtime_t *vrt = &vr->runtime;
259 :
260 0 : vrt->skew = (((256 - vrc->priority) * vrt->master_adv_int) / 256);
261 0 : }
262 :
263 : always_inline void
264 0 : vrrp_vr_master_down_compute (vrrp_vr_t * vr)
265 : {
266 0 : vrrp_vr_runtime_t *vrt = &vr->runtime;
267 :
268 0 : vrt->master_down_int = (3 * vrt->master_adv_int) + vrt->skew;
269 0 : }
270 :
271 : always_inline vrrp_vr_t *
272 4 : vrrp_vr_lookup (u32 sw_if_index, u8 vr_id, u8 is_ipv6)
273 : {
274 4 : vrrp_main_t *vmp = &vrrp_main;
275 : vrrp_vr_key_t key;
276 : uword *p;
277 :
278 4 : clib_memset (&key, 0, sizeof (key));
279 :
280 4 : key.sw_if_index = sw_if_index;
281 4 : key.vr_id = vr_id;
282 4 : key.is_ipv6 = (is_ipv6 != 0);
283 :
284 4 : p = mhash_get (&vmp->vr_index_by_key, &key);
285 4 : if (p)
286 4 : return pool_elt_at_index (vmp->vrs, p[0]);
287 :
288 0 : return 0;
289 : }
290 :
291 : always_inline vrrp_vr_t *
292 8 : vrrp_vr_lookup_index (u32 vr_index)
293 : {
294 8 : vrrp_main_t *vmp = &vrrp_main;
295 :
296 8 : if (pool_is_free_index (vmp->vrs, vr_index))
297 0 : return 0;
298 :
299 8 : return pool_elt_at_index (vmp->vrs, vr_index);
300 : }
301 :
302 : always_inline u32
303 4 : vrrp_vr_lookup_address (u32 sw_if_index, u8 is_ipv6, void *addr)
304 : {
305 4 : vrrp_main_t *vmp = &vrrp_main;
306 : uword *p;
307 : vrrp4_arp_key_t key4;
308 : vrrp6_nd_key_t key6;
309 :
310 4 : if (is_ipv6)
311 : {
312 2 : key6.sw_if_index = sw_if_index;
313 2 : key6.addr = ((ip6_address_t *) addr)[0];
314 2 : p = hash_get_mem (vmp->vrrp6_nd_lookup, &key6);
315 : }
316 : else
317 : {
318 2 : key4.sw_if_index = sw_if_index;
319 2 : key4.addr = ((ip4_address_t *) addr)[0];
320 2 : p = hash_get (vmp->vrrp4_arp_lookup, key4.as_u64);
321 : }
322 :
323 4 : if (p)
324 2 : return p[0];
325 :
326 2 : return ~0;
327 : }
328 :
329 : always_inline vrrp_intf_t *
330 87995 : vrrp_intf_get (u32 sw_if_index)
331 : {
332 87995 : vrrp_main_t *vrm = &vrrp_main;
333 :
334 87995 : if (sw_if_index == ~0)
335 0 : return NULL;
336 :
337 87995 : vec_validate (vrm->vrrp_intfs, sw_if_index);
338 87995 : return vec_elt_at_index (vrm->vrrp_intfs, sw_if_index);
339 : }
340 :
341 : always_inline int
342 14 : vrrp_intf_num_vrs (u32 sw_if_index, u8 is_ipv6)
343 : {
344 14 : vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);
345 :
346 14 : if (intf)
347 14 : return vec_len (intf->vr_indices[is_ipv6]);
348 :
349 0 : return 0;
350 : }
351 :
352 : always_inline u8
353 46 : vrrp_vr_is_ipv6 (vrrp_vr_t * vr)
354 : {
355 46 : return ((vr->config.flags & VRRP_VR_IPV6) != 0);
356 : }
357 :
358 : always_inline u8
359 10 : vrrp_vr_is_unicast (vrrp_vr_t * vr)
360 : {
361 10 : return ((vr->config.flags & VRRP_VR_UNICAST) != 0);
362 : }
363 :
364 : always_inline u8
365 2 : vrrp_vr_is_owner (vrrp_vr_t * vr)
366 : {
367 2 : 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 8 : vrrp_vr_accept_mode_enabled (vrrp_vr_t * vr)
384 : {
385 8 : return ((vr->config.flags & VRRP_VR_ACCEPT) != 0);
386 : }
387 :
388 : always_inline u32
389 0 : vrrp_vr_index (vrrp_vr_t * vr)
390 : {
391 0 : vrrp_main_t *vmp = &vrrp_main;
392 :
393 0 : return vr - vmp->vrs;
394 : }
395 :
396 : always_inline u8
397 2 : vrrp_vr_priority (vrrp_vr_t * vr)
398 : {
399 : u8 rv;
400 :
401 2 : if (vr->tracking.interfaces_dec < (u32) vr->config.priority)
402 2 : rv = vr->config.priority - vr->tracking.interfaces_dec;
403 : else
404 0 : rv = 1;
405 :
406 2 : 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 : */
|