]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp.c
vrrpd: fix packet encode
[mirror_frr.git] / vrrpd / vrrp.c
CommitLineData
5435a2bf 1/*
1d21789e 2 * VRRPD global definitions and state machine
5435a2bf
QY
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Quentin Young
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
41ee5442
QY
20#include <zebra.h>
21
40744000
QY
22#include "lib/memory.h"
23#include "lib/if.h"
24#include "lib/linklist.h"
25#include "lib/prefix.h"
26#include "lib/hash.h"
27#include "lib/vrf.h"
28#include "lib/hook.h"
5435a2bf
QY
29
30#include "vrrp.h"
40744000 31#include "vrrp_arp.h"
5435a2bf
QY
32
33/* Utility functions ------------------------------------------------------- */
34
35/*
36 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
37 *
38 * mac
39 * ethaddr to set
40 *
41 * v6
42 * Whether this is a V6 or V4 Virtual Router MAC
43 *
44 * vrid
45 * Virtual Router Identifier
46 */
47static void vrrp_mac_set(struct ethaddr *mac, bool v6, uint8_t vrid)
48{
49 /*
50 * V4: 00-00-5E-00-01-{VRID}
51 * V6: 00-00-5E-00-02-{VRID}
52 */
53 mac->octet[0] = 0x00;
54 mac->octet[1] = 0x00;
55 mac->octet[2] = 0x5E;
56 mac->octet[3] = 0x00;
57 mac->octet[4] = v6 ? 0x02 : 0x01;
58 mac->octet[5] = vrid;
59}
60
1d21789e
QY
61/*
62 * Sets advertisement_interval and master_adver_interval on a Virtual Router,
63 * then recalculates and sets skew_time and master_down_interval based on these
64 * values.
65 *
66 * vr
67 * Virtual Router to operate on
68 *
69 * advertisement_interval
70 * Advertisement_Interval to set
71 *
72 * master_adver_interval
73 * Master_Adver_Interval to set
74 */
75static void vrrp_update_times(struct vrrp_vrouter *vr,
76 uint16_t advertisement_interval,
77 uint16_t master_adver_interval)
5435a2bf
QY
78{
79 vr->advertisement_interval = advertisement_interval;
80 vr->master_adver_interval = master_adver_interval;
1485d9e5
QY
81 vr->skew_time = ((256 - vr->priority) * master_adver_interval) / 256;
82 vr->master_down_interval = (3 * master_adver_interval);
83 vr->master_down_interval += vr->skew_time;
5435a2bf
QY
84}
85
1d21789e
QY
86/*
87 */
88static void vrrp_reset_times(struct vrrp_vrouter *vr)
89{
90 vrrp_update_times(vr, vr->advertisement_interval, 0);
91}
92
93/* Configuration controllers ----------------------------------------------- */
94
95void vrrp_set_priority(struct vrrp_vrouter *vr, uint8_t priority)
c23edd74
QY
96{
97 if (vr->priority == priority)
98 return;
99
100 vr->priority = priority;
101 /* Timers depend on priority value, need to recalculate them */
102 vrrp_update_times(vr, vr->advertisement_interval,
103 vr->master_adver_interval);
104}
105
1d21789e
QY
106void vrrp_set_advertisement_interval(struct vrrp_vrouter *vr,
107 uint16_t advertisement_interval)
108{
109 if (vr->advertisement_interval == advertisement_interval)
110 return;
111
112 vrrp_update_times(vr, advertisement_interval, vr->master_adver_interval);
113}
114
c23edd74
QY
115void vrrp_add_ip(struct vrrp_vrouter *vr, struct in_addr v4)
116{
117 struct in_addr *v4_ins = XCALLOC(MTYPE_TMP, sizeof(struct in_addr));
118
119 *v4_ins = v4;
120 listnode_add(vr->v4, v4_ins);
121}
122
1d21789e
QY
123
124/* Creation and destruction ------------------------------------------------ */
125
5435a2bf
QY
126struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid)
127{
128 struct vrrp_vrouter *vr =
129 XCALLOC(MTYPE_TMP, sizeof(struct vrrp_vrouter));
130
131 vr->sock = -1;
132 vr->ifp = ifp;
133 vr->vrid = vrid;
134 vr->v4 = list_new();
135 vr->v6 = list_new();
5435a2bf
QY
136 vr->is_master = false;
137 vr->priority = VRRP_DEFAULT_PRIORITY;
5435a2bf
QY
138 vr->preempt_mode = true;
139 vr->accept_mode = false;
140 vrrp_mac_set(&vr->vr_mac_v4, false, vrid);
141 vrrp_mac_set(&vr->vr_mac_v6, true, vrid);
142 vr->fsm.state = VRRP_STATE_INITIALIZE;
1485d9e5 143 vrrp_set_advertisement_interval(vr, VRRP_DEFAULT_ADVINT);
1d21789e 144 vrrp_reset_times(vr);
5435a2bf
QY
145
146 hash_get(vrrp_vrouters_hash, vr, hash_alloc_intern);
147
148 return vr;
149}
150
c23edd74
QY
151void vrrp_vrouter_destroy(struct vrrp_vrouter *vr)
152{
153 if (vr->sock >= 0)
154 close(vr->sock);
155 vr->ifp = NULL;
156 list_delete(&vr->v4);
157 list_delete(&vr->v6);
158 hash_release(vrrp_vrouters_hash, vr);
159 XFREE(MTYPE_TMP, vr);
160}
161
5435a2bf
QY
162struct vrrp_vrouter *vrrp_lookup(uint8_t vrid)
163{
164 struct vrrp_vrouter vr;
165 vr.vrid = vrid;
166
167 return hash_lookup(vrrp_vrouters_hash, &vr);
168}
169
170/* Network ----------------------------------------------------------------- */
171
172/*
173 * Create and broadcast VRRP ADVERTISEMENT message.
174 *
175 * vr
176 * Virtual Router for which to send ADVERTISEMENT
177 */
178static void vrrp_send_advertisement(struct vrrp_vrouter *vr)
179{
180}
181
182/* FIXME:
183static void vrrp_recv_advertisement(struct thread *thread)
184{
185}
186*/
187
188/*
189 * Create Virtual Router listen socket and join it to the VRRP multicast group.
190 *
191 * The first connected address on the Virtual Router's interface is used as the
192 * interface address.
193 *
194 * vr
195 * Virtual Router for which to create listen socket
196 */
197static int vrrp_socket(struct vrrp_vrouter *vr)
198{
199 struct ip_mreqn req;
200 int ret;
a8144d7f 201 struct connected *c;
5435a2bf 202
40744000
QY
203 errno = 0;
204 frr_elevate_privs(&vrrp_privs) {
205 vr->sock = socket(AF_INET, SOCK_RAW, IPPROTO_VRRP);
5435a2bf
QY
206 }
207
40744000
QY
208 if (vr->sock < 0)
209 perror("Error opening VRRP socket");
210
5435a2bf
QY
211 /* Join the multicast group.*/
212
213 /* FIXME: Use first address on the interface and for imr_interface */
a8144d7f
QY
214 if (!listcount(vr->ifp->connected))
215 return -1;
216
217 c = listhead(vr->ifp->connected)->data;
5435a2bf
QY
218 struct in_addr v4 = c->address->u.prefix4;
219
220 memset(&req, 0, sizeof(req));
221 req.imr_multiaddr.s_addr = htonl(VRRP_MCAST_GROUP_HEX);
222 req.imr_address = v4;
223 req.imr_ifindex = 0; // FIXME: vr->ifp->ifindex ?
224 ret = setsockopt(vr->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&req,
225 sizeof(struct ip_mreq));
226 if (ret < 0) {
227 // int err = errno;
228 /* VRRP_LOG(("cant do IP_ADD_MEMBERSHIP errno=%d\n", err)); */
229 return -1;
230 }
231 return 0;
232}
233
234
235/* State machine ----------------------------------------------------------- */
236
237DEFINE_HOOK(vrrp_change_state_hook, (struct vrrp_vrouter *vr, int to), (vr, to));
238
239/*
240 * Handle any necessary actions during state change to MASTER state.
241 *
242 * vr
243 * Virtual Router to operate on
244 */
245static void vrrp_change_state_master(struct vrrp_vrouter *vr)
246{
247}
248
249/*
250 * Handle any necessary actions during state change to BACKUP state.
251 *
252 * vr
253 * Virtual Router to operate on
254 */
255static void vrrp_change_state_backup(struct vrrp_vrouter *vr)
256{
257 /* Uninstall ARP entry for vrouter MAC */
258 /* ... */
259}
260
261/*
262 * Handle any necessary actions during state change to INITIALIZE state.
263 *
264 * This is not called for initial startup, only when transitioning from MASTER
265 * or BACKUP.
266 *
267 * vr
268 * Virtual Router to operate on
269 */
270static void vrrp_change_state_initialize(struct vrrp_vrouter *vr)
271{
1d21789e
QY
272 /* Reset timers */
273 vrrp_reset_times(vr);
5435a2bf
QY
274}
275
276void (*vrrp_change_state_handlers[])(struct vrrp_vrouter *vr) = {
277 [VRRP_STATE_MASTER] = vrrp_change_state_master,
278 [VRRP_STATE_BACKUP] = vrrp_change_state_backup,
279 [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize,
280};
281
282/*
283 * Change Virtual Router FSM position. Handles transitional actions and calls
284 * any subscribers to the state change hook.
285 *
286 * vr
287 * Virtual Router for which to change state
288 *
289 * to
290 * State to change to
291 */
292static void vrrp_change_state(struct vrrp_vrouter *vr, int to)
293{
294 /* Call our handlers, then any subscribers */
295 vrrp_change_state_handlers[to](vr);
296 hook_call(vrrp_change_state_hook, vr, to);
297 vr->fsm.state = to;
298}
299
300/*
301 * Called when Adver_Timer expires.
302 */
303static int vrrp_adver_timer_expire(struct thread *thread)
304{
305 struct vrrp_vrouter *vr = thread->arg;
306
307 if (vr->fsm.state == VRRP_STATE_BACKUP) {
308 vrrp_send_advertisement(vr);
309 /* FIXME: vrrp_send_gratuitous_arp(vr); */
310 } else if (vr->fsm.state == VRRP_STATE_MASTER) {
311
312 } else if (vr->fsm.state == VRRP_STATE_INITIALIZE) {
313 assert(!"FUCK");
314 }
315 return 0;
316}
317
318/*
319 * Called when Master_Down timer expires.
320 */
321static int vrrp_master_down_timer_expire(struct thread *thread)
322{
323 /* struct vrrp_vrouter *vr = thread->arg; */
324
325 return 0;
326}
327
328/*
329 * Event handler for Startup event.
330 *
331 * Creates sockets, sends advertisements and ARP requests, starts timers,
1d21789e
QY
332 * and transitions the Virtual Router to either Master or Backup states.
333 *
334 * This function will also initialize the program's global ARP subsystem if it
335 * has not yet been initialized.
5435a2bf
QY
336 *
337 * vr
338 * Virtual Router on which to apply Startup event
1d21789e
QY
339 *
340 * Returns:
341 * < 0 if the session socket could not be created, or the state is not
342 * Initialize
343 * 0 on success
5435a2bf 344 */
a8144d7f 345static int vrrp_startup(struct vrrp_vrouter *vr)
5435a2bf 346{
1d21789e
QY
347 /* May only be called when the state is Initialize */
348 if (vr->fsm.state != VRRP_STATE_INITIALIZE)
349 return -1;
350
40744000
QY
351 /* Initialize global gratuitous ARP socket if necessary */
352 if (!vrrp_garp_is_init())
353 vrrp_garp_init();
354
5435a2bf 355 /* Create socket */
a8144d7f
QY
356 int ret = vrrp_socket(vr);
357 if (ret < 0) {
358 zlog_warn("Cannot create VRRP socket\n");
359 return ret;
360 }
5435a2bf
QY
361
362 /* Schedule listener */
363 /* ... */
364
365 if (vr->priority == VRRP_PRIO_MASTER) {
366 vrrp_send_advertisement(vr);
c23edd74 367 vrrp_garp_send_all(vr);
5435a2bf
QY
368
369 thread_add_timer_msec(master, vrrp_adver_timer_expire, vr,
370 vr->advertisement_interval * 10,
371 &vr->t_adver_timer);
372 vrrp_change_state(vr, VRRP_STATE_MASTER);
373 } else {
374 vrrp_update_times(vr, vr->advertisement_interval,
375 vr->advertisement_interval);
376 thread_add_timer_msec(master, vrrp_master_down_timer_expire, vr,
377 vr->master_down_interval * 10,
378 &vr->t_master_down_timer);
379 vrrp_change_state(vr, VRRP_STATE_BACKUP);
380 }
a8144d7f
QY
381
382 return 0;
5435a2bf
QY
383}
384
1d21789e
QY
385/*
386 * Shuts down a Virtual Router and transitions it to Initialize.
387 *
388 * This call must be idempotent; it is safe to call multiple times on the same
389 * Virtual Router.
390 */
a8144d7f 391static int vrrp_shutdown(struct vrrp_vrouter *vr)
5435a2bf 392{
1d21789e
QY
393 /* close socket */
394 if (vr->sock >= 0)
395 close(vr->sock);
396
397 /* cancel all threads */
398 /* ... */
399
400 vrrp_change_state(vr, VRRP_STATE_INITIALIZE);
401
a8144d7f 402 return 0;
5435a2bf
QY
403}
404
a8144d7f 405static int (*vrrp_event_handlers[])(struct vrrp_vrouter *vr) = {
5435a2bf
QY
406 [VRRP_EVENT_STARTUP] = vrrp_startup,
407 [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown,
408};
409
410/*
411 * Spawn a VRRP FSM event on a Virtual Router.
412 *
413 * vr
414 * Virtual Router on which to spawn event
415 *
416 * event
417 * The event to spawn
418 */
a8144d7f 419int vrrp_event(struct vrrp_vrouter *vr, int event)
5435a2bf 420{
a8144d7f 421 return vrrp_event_handlers[event](vr);
5435a2bf
QY
422}
423
424
425/* Other ------------------------------------------------------------------- */
426
427static unsigned int vrrp_hash_key(void *arg)
428{
429 struct vrrp_vrouter *vr = arg;
430
431 return vr->vrid;
432}
433
434static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
435{
436 const struct vrrp_vrouter *vr1 = arg1;
437 const struct vrrp_vrouter *vr2 = arg2;
438
c23edd74 439 return vr1->vrid == vr2->vrid;
5435a2bf
QY
440}
441
442void vrrp_init(void)
443{
444 vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
445 "VRRP virtual router hash");
446 vrf_init(NULL, NULL, NULL, NULL, NULL);
447}