vrrp: add plugin providing vrrp support
[vpp.git] / src / plugins / vrrp / vrrp_api.c
1 /*
2  * vrrp.c - vpp vrrp plug-in
3  *
4  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  */
9
10 #include <vnet/vnet.h>
11 #include <vnet/plugin/plugin.h>
12 #include <vrrp/vrrp.h>
13
14 #include <vlibapi/api.h>
15 #include <vlibmemory/api.h>
16 #include <vpp/app/version.h>
17
18 /* define message IDs */
19 #include <vnet/format_fns.h>
20 #include <vrrp/vrrp.api_enum.h>
21 #include <vrrp/vrrp.api_types.h>
22
23 #define REPLY_MSG_ID_BASE vmp->msg_id_base
24 #include <vlibapi/api_helper_macros.h>
25
26 /* API message handlers */
27 static void
28 vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp)
29 {
30   vrrp_main_t *vmp = &vrrp_main;
31   vl_api_vrrp_vr_add_del_reply_t *rmp;
32   vrrp_vr_config_t vr_conf;
33   u32 api_flags;
34   ip46_address_t *addrs = 0;
35   int rv;
36
37   api_flags = htonl (mp->flags);
38
39   clib_memset (&vr_conf, 0, sizeof (vr_conf));
40
41   vr_conf.sw_if_index = ntohl (mp->sw_if_index);
42   vr_conf.vr_id = mp->vr_id;
43   vr_conf.priority = mp->priority;
44   vr_conf.adv_interval = ntohs (mp->interval);
45
46   if (api_flags & VRRP_API_VR_PREEMPT)
47     vr_conf.flags |= VRRP_VR_PREEMPT;
48
49   if (api_flags & VRRP_API_VR_ACCEPT)
50     vr_conf.flags |= VRRP_VR_ACCEPT;
51
52   if (api_flags & VRRP_API_VR_UNICAST)
53     vr_conf.flags |= VRRP_VR_UNICAST;
54
55   if (api_flags & VRRP_API_VR_IPV6)
56     vr_conf.flags |= VRRP_VR_IPV6;
57
58   if (mp->is_add)
59     {
60       int i;
61
62       for (i = 0; i < mp->n_addrs; i++)
63         {
64           ip46_address_t *addr;
65           void *src, *dst;
66           int len;
67
68           vec_add2 (addrs, addr, 1);
69
70           if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
71             {
72               src = &mp->addrs[i].un.ip4;
73               dst = &addr->ip4;
74               len = sizeof (addr->ip4);
75             }
76           else
77             {
78               src = &mp->addrs[i].un.ip6;
79               dst = &addr->ip6;
80               len = sizeof (addr->ip6);
81             }
82
83           clib_memcpy (dst, src, len);
84         }
85
86       vr_conf.vr_addrs = addrs;
87     }
88
89   if (vr_conf.priority == 0)
90     {
91       clib_warning ("VR priority must be > 0");
92       rv = VNET_API_ERROR_INVALID_VALUE;
93     }
94   else if (vr_conf.adv_interval == 0)
95     {
96       clib_warning ("VR advertisement interval must be > 0");
97       rv = VNET_API_ERROR_INVALID_VALUE;
98     }
99   else if (vr_conf.vr_id == 0)
100     {
101       clib_warning ("VR ID must be > 0");
102       rv = VNET_API_ERROR_INVALID_VALUE;
103     }
104   else
105     rv = vrrp_vr_add_del (mp->is_add, &vr_conf);
106
107   vec_free (addrs);
108
109   REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY);
110 }
111
112 static void
113 send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
114                       u32 context)
115 {
116   vrrp_main_t *vmp = &vrrp_main;
117   vl_api_vrrp_vr_details_t *mp;
118   int n_addrs, msg_size;
119   ip46_address_t *addr;
120   vl_api_address_t *api_addr;
121   u32 api_flags = 0;
122
123   n_addrs = vec_len (vr->config.vr_addrs);
124   msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
125   mp = vl_msg_api_alloc (msg_size);
126   if (!mp)
127     return;
128   clib_memset (mp, 0, msg_size);
129   mp->_vl_msg_id = htons (VL_API_VRRP_VR_DETAILS + vmp->msg_id_base);
130   mp->context = context;
131
132   /* config */
133   mp->config.sw_if_index = htonl (vr->config.sw_if_index);
134   mp->config.vr_id = vr->config.vr_id;
135   mp->config.priority = vr->config.priority;
136   mp->config.interval = htons (vr->config.adv_interval);
137
138   if (vr->config.flags & VRRP_VR_PREEMPT)
139     api_flags |= VRRP_API_VR_PREEMPT;
140   if (vr->config.flags & VRRP_VR_ACCEPT)
141     api_flags |= VRRP_API_VR_ACCEPT;
142   if (vrrp_vr_is_unicast (vr))
143     api_flags |= VRRP_API_VR_UNICAST;
144   if (vrrp_vr_is_ipv6 (vr))
145     api_flags |= VRRP_API_VR_IPV6;
146
147   mp->config.flags = htonl (api_flags);
148
149   /* runtime */
150   switch (vr->runtime.state)
151     {
152     case VRRP_VR_STATE_INIT:
153       mp->runtime.state = htonl (VRRP_API_VR_STATE_INIT);
154       break;
155     case VRRP_VR_STATE_BACKUP:
156       mp->runtime.state = htonl (VRRP_API_VR_STATE_BACKUP);
157       break;
158     case VRRP_VR_STATE_MASTER:
159       mp->runtime.state = htonl (VRRP_API_VR_STATE_MASTER);
160       break;
161     case VRRP_VR_STATE_INTF_DOWN:
162       mp->runtime.state = htonl (VRRP_API_VR_STATE_INTF_DOWN);
163       break;
164     default:
165       break;
166     }
167
168   mp->runtime.master_adv_int = htons (vr->runtime.master_adv_int);
169   mp->runtime.skew = htons (vr->runtime.skew);
170   mp->runtime.master_down_int = htons (vr->runtime.master_down_int);
171   clib_memcpy (&mp->runtime.mac, &vr->runtime.mac, sizeof (vr->runtime.mac));
172
173   mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec);
174   mp->runtime.tracking.priority = vrrp_vr_priority (vr);
175
176   /* addrs */
177   mp->n_addrs = vec_len (vr->config.vr_addrs);
178   api_addr = mp->addrs;
179   vec_foreach (addr, vr->config.vr_addrs)
180   {
181     void *src, *dst;
182     size_t len;
183
184     if (vrrp_vr_is_ipv6 (vr))
185       {
186         api_addr->af = htonl (ADDRESS_IP6);
187         dst = &api_addr->un.ip6;
188         src = &addr->ip6;
189         len = sizeof (addr->ip6);
190       }
191     else
192       {
193         api_addr->af = htonl (ADDRESS_IP4);
194         dst = &api_addr->un.ip4;
195         src = &addr->ip4;
196         len = sizeof (addr->ip4);
197       }
198     clib_memcpy (dst, src, len);
199     api_addr++;
200   }
201
202   vl_api_send_msg (reg, (u8 *) mp);
203 }
204
205 static void
206 vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp)
207 {
208   vrrp_main_t *vmp = &vrrp_main;
209   vl_api_registration_t *reg;
210   vrrp_vr_t *vr;
211   u32 sw_if_index;
212
213   reg = vl_api_client_index_to_registration (mp->client_index);
214
215   sw_if_index = htonl (mp->sw_if_index);
216
217   /* *INDENT-OFF* */
218   pool_foreach (vr, vmp->vrs, ({
219
220     if (sw_if_index && (sw_if_index != ~0) &&
221         (sw_if_index != vr->config.sw_if_index))
222       continue;
223
224     send_vrrp_vr_details (vr, reg, mp->context);
225   }));
226   /* *INDENT-ON* */
227 }
228
229 static void
230 vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
231 {
232   vrrp_main_t *vmp = &vrrp_main;
233   vl_api_vrrp_vr_start_stop_reply_t *rmp;
234   vrrp_vr_key_t vr_key;
235   int rv;
236
237   clib_memset (&vr_key, 0, sizeof (vr_key));
238
239   vr_key.sw_if_index = ntohl (mp->sw_if_index);
240   vr_key.vr_id = mp->vr_id;
241   vr_key.is_ipv6 = (mp->is_ipv6 != 0);
242
243   rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);
244
245   REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
246 }
247
248 static void
249 vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
250 {
251   vrrp_main_t *vmp = &vrrp_main;
252   vl_api_vrrp_vr_set_peers_reply_t *rmp;
253   vrrp_vr_key_t vr_key;
254   ip46_address_t *peer_addrs = 0;
255   int i;
256   int rv;
257
258   clib_memset (&vr_key, 0, sizeof (vr_key));
259
260   vr_key.sw_if_index = ntohl (mp->sw_if_index);
261   vr_key.vr_id = mp->vr_id;
262   vr_key.is_ipv6 = (mp->is_ipv6 != 0);
263
264   for (i = 0; i < mp->n_addrs; i++)
265     {
266       ip46_address_t *peer;
267
268       vec_add2 (peer_addrs, peer, 1);
269
270       if (mp->is_ipv6)
271         clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
272       else
273         clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
274     }
275
276   rv = vrrp_vr_set_peers (&vr_key, peer_addrs);
277
278   vec_free (peer_addrs);
279   REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
280 }
281
282 static void
283 send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
284                            u32 context)
285 {
286   vrrp_main_t *vmp = &vrrp_main;
287   vl_api_vrrp_vr_peer_details_t *mp;
288   int n_addrs, msg_size;
289   ip46_address_t *addr;
290   vl_api_address_t *api_addr;
291
292   n_addrs = vec_len (vr->config.peer_addrs);
293   msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
294   mp = vl_msg_api_alloc (msg_size);
295   if (!mp)
296     return;
297   clib_memset (mp, 0, msg_size);
298   mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base);
299   mp->context = context;
300
301   mp->sw_if_index = htonl (vr->config.sw_if_index);
302   mp->vr_id = vr->config.vr_id;
303   mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
304
305   /* addrs */
306   mp->n_peer_addrs = n_addrs;
307   api_addr = mp->peer_addrs;
308   vec_foreach (addr, vr->config.peer_addrs)
309   {
310     void *src, *dst;
311     size_t len;
312
313     if (vrrp_vr_is_ipv6 (vr))
314       {
315         api_addr->af = htonl (ADDRESS_IP6);
316         dst = &api_addr->un.ip6;
317         src = &addr->ip6;
318         len = sizeof (addr->ip6);
319       }
320     else
321       {
322         api_addr->af = htonl (ADDRESS_IP4);
323         dst = &api_addr->un.ip4;
324         src = &addr->ip4;
325         len = sizeof (addr->ip4);
326       }
327     clib_memcpy (dst, src, len);
328     api_addr++;
329   }
330
331   vl_api_send_msg (reg, (u8 *) mp);
332 }
333
334 static void
335 vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp)
336 {
337   vrrp_main_t *vmp = &vrrp_main;
338   vl_api_registration_t *reg;
339   vrrp_vr_t *vr;
340   vrrp_vr_key_t vr_key;
341
342   reg = vl_api_client_index_to_registration (mp->client_index);
343
344   vr_key.sw_if_index = ntohl (mp->sw_if_index);
345
346   if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
347     {
348       uword *p;
349       u32 vr_index = ~0;
350
351       vr_key.vr_id = mp->vr_id;
352       vr_key.is_ipv6 = mp->is_ipv6;
353
354       p = mhash_get (&vmp->vr_index_by_key, &vr_key);
355       if (!p)
356         return;
357
358       vr_index = p[0];
359       vr = pool_elt_at_index (vmp->vrs, vr_index);
360       send_vrrp_vr_peer_details (vr, reg, mp->context);
361
362       return;
363     }
364
365   /* *INDENT-OFF* */
366   pool_foreach (vr, vmp->vrs, ({
367
368     if (!vec_len (vr->config.peer_addrs))
369       continue;
370
371     send_vrrp_vr_details (vr, reg, mp->context);
372
373   }));
374   /* *INDENT-ON* */
375 }
376
377 static void
378   vl_api_vrrp_vr_track_if_add_del_t_handler
379   (vl_api_vrrp_vr_track_if_add_del_t * mp)
380 {
381   vrrp_main_t *vmp = &vrrp_main;
382   vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
383   vrrp_vr_t *vr;
384   vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
385   int rv = 0, i;
386
387   /* lookup VR and return error if it does not exist */
388   vr =
389     vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
390   if (!vr)
391     {
392       rv = VNET_API_ERROR_INVALID_VALUE;
393       goto done;
394     }
395
396   for (i = 0; i < mp->n_ifs; i++)
397     {
398       vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];
399
400       vec_add2 (track_ifs, track_if, 1);
401       track_if->sw_if_index = ntohl (api_track_if->sw_if_index);
402       track_if->priority = api_track_if->priority;
403     }
404
405   rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);
406
407 done:
408   vec_free (track_ifs);
409   REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
410 }
411
412 static void
413 send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
414                                u32 context)
415 {
416   vrrp_main_t *vmp = &vrrp_main;
417   vl_api_vrrp_vr_track_if_details_t *mp;
418   int n_ifs, msg_size;
419   vl_api_vrrp_vr_track_if_t *api_track_if;
420   vrrp_vr_tracking_if_t *track_if;
421
422   if (!vr)
423     return;
424
425   n_ifs = vec_len (vr->tracking.interfaces);
426   msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if);
427   mp = vl_msg_api_alloc (msg_size);
428   if (!mp)
429     return;
430   clib_memset (mp, 0, msg_size);
431   mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base);
432   mp->context = context;
433
434   mp->sw_if_index = htonl (vr->config.sw_if_index);
435   mp->vr_id = vr->config.vr_id;
436   mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);
437
438   /* tracked interfaces */
439   mp->n_ifs = n_ifs;
440   api_track_if = mp->ifs;
441   vec_foreach (track_if, vr->tracking.interfaces)
442   {
443     api_track_if->sw_if_index = htonl (track_if->sw_if_index);
444     api_track_if->priority = track_if->priority;
445     api_track_if += 1;
446   }
447
448   vl_api_send_msg (reg, (u8 *) mp);
449 }
450
451 static void
452 vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
453 {
454   vrrp_main_t *vmp = &vrrp_main;
455   vl_api_registration_t *reg;
456   vrrp_vr_t *vr;
457
458   reg = vl_api_client_index_to_registration (mp->client_index);
459
460   if (!mp->dump_all)
461     {
462       vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6);
463       send_vrrp_vr_track_if_details (vr, reg, mp->context);
464
465       return;
466     }
467
468   /* *INDENT-OFF* */
469   pool_foreach (vr, vmp->vrs, ({
470
471     if (!vec_len (vr->tracking.interfaces))
472       continue;
473
474     send_vrrp_vr_track_if_details (vr, reg, mp->context);
475
476   }));
477   /* *INDENT-ON* */
478 }
479
480 /* Set up the API message handling tables */
481 #include <vrrp/vrrp.api.c>
482 clib_error_t *
483 vrrp_plugin_api_hookup (vlib_main_t * vm)
484 {
485   vrrp_main_t *vmp = &vrrp_main;
486
487   /* Ask for a correctly-sized block of API message decode slots */
488   vmp->msg_id_base = setup_message_id_table ();
489
490   return 0;
491 }
492
493 /* *INDENT-ON* */
494
495 /*
496  * fd.io coding-style-patch-verification: ON
497  *
498  * Local Variables:
499  * eval: (c-set-style "gnu")
500  * End:
501  */