]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp.c
vrrpd: add .gitignore
[mirror_frr.git] / vrrpd / vrrp.c
CommitLineData
5435a2bf
QY
1/*
2 * VRRPD global definitions
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
5435a2bf
QY
22#include "memory.h"
23#include "if.h"
24#include "linklist.h"
25#include "prefix.h"
26#include "hash.h"
27#include "vrf.h"
28#include "hook.h"
29
30#include "vrrp.h"
31
32/* Utility functions ------------------------------------------------------- */
33
34/*
35 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
36 *
37 * mac
38 * ethaddr to set
39 *
40 * v6
41 * Whether this is a V6 or V4 Virtual Router MAC
42 *
43 * vrid
44 * Virtual Router Identifier
45 */
46static void vrrp_mac_set(struct ethaddr *mac, bool v6, uint8_t vrid)
47{
48 /*
49 * V4: 00-00-5E-00-01-{VRID}
50 * V6: 00-00-5E-00-02-{VRID}
51 */
52 mac->octet[0] = 0x00;
53 mac->octet[1] = 0x00;
54 mac->octet[2] = 0x5E;
55 mac->octet[3] = 0x00;
56 mac->octet[4] = v6 ? 0x02 : 0x01;
57 mac->octet[5] = vrid;
58}
59
60/*
61 * Sets advertisement_interval and master_adver_interval on a Virtual Router,
62 * then recalculates and sets skew_time and master_down_interval based on these
63 * values.
64 *
65 * vr
66 * Virtual Router to operate on
67 *
68 * advertisement_interval
69 * Advertisement_Interval to set
70 *
71 * master_adver_interval
72 * Master_Adver_Interval to set
73 */
74static void vrrp_update_times(struct vrrp_vrouter *vr, uint16_t advertisement_interval,
75 uint16_t master_adver_interval)
76{
77 vr->advertisement_interval = advertisement_interval;
78 vr->master_adver_interval = master_adver_interval;
79 vr->skew_time = (256 - vr->priority) * vr->master_adver_interval;
80 vr->skew_time /= 256;
81 vr->master_down_interval = (3 * vr->master_adver_interval);
82 vr->master_down_interval /= 256;
83}
84
85struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid)
86{
87 struct vrrp_vrouter *vr =
88 XCALLOC(MTYPE_TMP, sizeof(struct vrrp_vrouter));
89
90 vr->sock = -1;
91 vr->ifp = ifp;
92 vr->vrid = vrid;
93 vr->v4 = list_new();
94 vr->v6 = list_new();
95 vr->advint = VRRP_DEFAULT_ADVINT;
96 vr->is_master = false;
97 vr->priority = VRRP_DEFAULT_PRIORITY;
98 vr->advertisement_interval = VRRP_DEFAULT_ADVINT;
99 vr->master_adver_interval = 0;
100 vr->skew_time = 0;
101 vr->master_down_interval = 0;
102 vr->preempt_mode = true;
103 vr->accept_mode = false;
104 vrrp_mac_set(&vr->vr_mac_v4, false, vrid);
105 vrrp_mac_set(&vr->vr_mac_v6, true, vrid);
106 vr->fsm.state = VRRP_STATE_INITIALIZE;
107
108 hash_get(vrrp_vrouters_hash, vr, hash_alloc_intern);
109
110 return vr;
111}
112
113struct vrrp_vrouter *vrrp_lookup(uint8_t vrid)
114{
115 struct vrrp_vrouter vr;
116 vr.vrid = vrid;
117
118 return hash_lookup(vrrp_vrouters_hash, &vr);
119}
120
121/* Network ----------------------------------------------------------------- */
122
123/*
124 * Create and broadcast VRRP ADVERTISEMENT message.
125 *
126 * vr
127 * Virtual Router for which to send ADVERTISEMENT
128 */
129static void vrrp_send_advertisement(struct vrrp_vrouter *vr)
130{
131}
132
133/* FIXME:
134static void vrrp_recv_advertisement(struct thread *thread)
135{
136}
137*/
138
139/*
140 * Create Virtual Router listen socket and join it to the VRRP multicast group.
141 *
142 * The first connected address on the Virtual Router's interface is used as the
143 * interface address.
144 *
145 * vr
146 * Virtual Router for which to create listen socket
147 */
148static int vrrp_socket(struct vrrp_vrouter *vr)
149{
150 struct ip_mreqn req;
151 int ret;
152
153 vr->sock = socket(AF_INET, SOCK_RAW, IPPROTO_VRRP);
154
155 if (vr->sock < 0) {
156 /* FIXME */
157 }
158
159 /* Join the multicast group.*/
160
161 /* FIXME: Use first address on the interface and for imr_interface */
162 struct connected *c = listhead(vr->ifp->connected)->data;
163 struct in_addr v4 = c->address->u.prefix4;
164
165 memset(&req, 0, sizeof(req));
166 req.imr_multiaddr.s_addr = htonl(VRRP_MCAST_GROUP_HEX);
167 req.imr_address = v4;
168 req.imr_ifindex = 0; // FIXME: vr->ifp->ifindex ?
169 ret = setsockopt(vr->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&req,
170 sizeof(struct ip_mreq));
171 if (ret < 0) {
172 // int err = errno;
173 /* VRRP_LOG(("cant do IP_ADD_MEMBERSHIP errno=%d\n", err)); */
174 return -1;
175 }
176 return 0;
177}
178
179
180/* State machine ----------------------------------------------------------- */
181
182DEFINE_HOOK(vrrp_change_state_hook, (struct vrrp_vrouter *vr, int to), (vr, to));
183
184/*
185 * Handle any necessary actions during state change to MASTER state.
186 *
187 * vr
188 * Virtual Router to operate on
189 */
190static void vrrp_change_state_master(struct vrrp_vrouter *vr)
191{
192}
193
194/*
195 * Handle any necessary actions during state change to BACKUP state.
196 *
197 * vr
198 * Virtual Router to operate on
199 */
200static void vrrp_change_state_backup(struct vrrp_vrouter *vr)
201{
202 /* Uninstall ARP entry for vrouter MAC */
203 /* ... */
204}
205
206/*
207 * Handle any necessary actions during state change to INITIALIZE state.
208 *
209 * This is not called for initial startup, only when transitioning from MASTER
210 * or BACKUP.
211 *
212 * vr
213 * Virtual Router to operate on
214 */
215static void vrrp_change_state_initialize(struct vrrp_vrouter *vr)
216{
217}
218
219void (*vrrp_change_state_handlers[])(struct vrrp_vrouter *vr) = {
220 [VRRP_STATE_MASTER] = vrrp_change_state_master,
221 [VRRP_STATE_BACKUP] = vrrp_change_state_backup,
222 [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize,
223};
224
225/*
226 * Change Virtual Router FSM position. Handles transitional actions and calls
227 * any subscribers to the state change hook.
228 *
229 * vr
230 * Virtual Router for which to change state
231 *
232 * to
233 * State to change to
234 */
235static void vrrp_change_state(struct vrrp_vrouter *vr, int to)
236{
237 /* Call our handlers, then any subscribers */
238 vrrp_change_state_handlers[to](vr);
239 hook_call(vrrp_change_state_hook, vr, to);
240 vr->fsm.state = to;
241}
242
243/*
244 * Called when Adver_Timer expires.
245 */
246static int vrrp_adver_timer_expire(struct thread *thread)
247{
248 struct vrrp_vrouter *vr = thread->arg;
249
250 if (vr->fsm.state == VRRP_STATE_BACKUP) {
251 vrrp_send_advertisement(vr);
252 /* FIXME: vrrp_send_gratuitous_arp(vr); */
253 } else if (vr->fsm.state == VRRP_STATE_MASTER) {
254
255 } else if (vr->fsm.state == VRRP_STATE_INITIALIZE) {
256 assert(!"FUCK");
257 }
258 return 0;
259}
260
261/*
262 * Called when Master_Down timer expires.
263 */
264static int vrrp_master_down_timer_expire(struct thread *thread)
265{
266 /* struct vrrp_vrouter *vr = thread->arg; */
267
268 return 0;
269}
270
271/*
272 * Event handler for Startup event.
273 *
274 * Creates sockets, sends advertisements and ARP requests, starts timers,
275 * updates state machine.
276 *
277 * vr
278 * Virtual Router on which to apply Startup event
279 */
280static void vrrp_startup(struct vrrp_vrouter *vr)
281{
282 /* Create socket */
283 vrrp_socket(vr);
284
285 /* Schedule listener */
286 /* ... */
287
288 if (vr->priority == VRRP_PRIO_MASTER) {
289 vrrp_send_advertisement(vr);
290 /* FIXME: vrrp_send_gratuitous_arp(vr); */
291
292 thread_add_timer_msec(master, vrrp_adver_timer_expire, vr,
293 vr->advertisement_interval * 10,
294 &vr->t_adver_timer);
295 vrrp_change_state(vr, VRRP_STATE_MASTER);
296 } else {
297 vrrp_update_times(vr, vr->advertisement_interval,
298 vr->advertisement_interval);
299 thread_add_timer_msec(master, vrrp_master_down_timer_expire, vr,
300 vr->master_down_interval * 10,
301 &vr->t_master_down_timer);
302 vrrp_change_state(vr, VRRP_STATE_BACKUP);
303 }
304}
305
306static void vrrp_shutdown(struct vrrp_vrouter *vr)
307{
308 /* NOTHING */
309}
310
311static void (*vrrp_event_handlers[])(struct vrrp_vrouter *vr) = {
312 [VRRP_EVENT_STARTUP] = vrrp_startup,
313 [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown,
314};
315
316/*
317 * Spawn a VRRP FSM event on a Virtual Router.
318 *
319 * vr
320 * Virtual Router on which to spawn event
321 *
322 * event
323 * The event to spawn
324 */
325void vrrp_event(struct vrrp_vrouter *vr, int event)
326{
327 vrrp_event_handlers[event](vr);
328}
329
330
331/* Other ------------------------------------------------------------------- */
332
333static unsigned int vrrp_hash_key(void *arg)
334{
335 struct vrrp_vrouter *vr = arg;
336
337 return vr->vrid;
338}
339
340static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
341{
342 const struct vrrp_vrouter *vr1 = arg1;
343 const struct vrrp_vrouter *vr2 = arg2;
344
345 return vr1->vrid > vr2->vrid;
346}
347
348void vrrp_init(void)
349{
350 vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
351 "VRRP virtual router hash");
352 vrf_init(NULL, NULL, NULL, NULL, NULL);
353}