4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/sockio.h>
33 #include <sys/sysevent/vrrp.h>
34 #include <sys/sysevent/eventdefs.h>
35 #include <sys/varargs.h>
36 #include <auth_attr.h>
44 #include <libsysevent.h>
47 #include <arpa/inet.h>
52 #include <bsm/adt_event.h>
53 #include <priv_utils.h>
54 #include <libdllink.h>
55 #include <libdlvnic.h>
58 #include <libvrrpadm.h>
59 #include <net/route.h>
60 #include "vrrpd_impl.h"
63 * A VRRP router can be only start participating the VRRP protocol of a virtual
64 * router when all the following conditions are met:
66 * - The VRRP router is enabled (vr->vvr_conf.vvc_enabled is _B_TRUE)
67 * - The RX socket is successfully created over the physical interface to
68 * receive the VRRP multicast advertisement. Note that one RX socket can
69 * be shared by several VRRP routers configured over the same physical
70 * interface. (See vrrpd_init_rxsock())
71 * - The TX socket is successfully created over the VNIC interface to send
72 * the VRRP advertisment. (See vrrpd_init_txsock())
73 * - The primary IP address has been successfully selected over the physical
74 * interface. (See vrrpd_select_primary())
76 * If a VRRP router is enabled but the other conditions haven't be satisfied,
77 * the router will be stay at the VRRP_STATE_INIT state. If all the above
78 * conditions are met, the VRRP router will be transit to either
79 * the VRRP_STATE_MASTER or the VRRP_STATE_BACKUP state, depends on the VRRP
83 #define skip_whitespace(p) while (isspace(*(p))) ++(p)
85 #define BUFFSIZE 65536
87 #define VRRPCONF "/etc/inet/vrrp.conf"
89 typedef struct vrrpd_rtsock_s
{
90 int vrt_af
; /* address family */
91 int vrt_fd
; /* socket for the PF_ROUTE msg */
92 iu_event_id_t vrt_eid
; /* event ID */
95 static ipadm_handle_t vrrp_ipadm_handle
= NULL
; /* libipadm handle */
96 static int vrrp_logflag
= 0;
97 boolean_t vrrp_debug_level
= 0;
98 iu_eh_t
*vrrpd_eh
= NULL
;
99 iu_tq_t
*vrrpd_timerq
= NULL
;
100 static vrrp_handle_t vrrpd_vh
= NULL
;
101 static int vrrpd_cmdsock_fd
= -1; /* socket to communicate */
102 /* between vrrpd/libvrrpadm */
103 static iu_event_id_t vrrpd_cmdsock_eid
= -1;
104 static int vrrpd_ctlsock_fd
= -1; /* socket to bring up/down */
105 /* the virtual IP addresses */
106 static int vrrpd_ctlsock6_fd
= -1;
107 static vrrpd_rtsock_t vrrpd_rtsocks
[2] = {
111 static iu_timer_id_t vrrp_scan_timer_id
= -1;
113 TAILQ_HEAD(vrrp_vr_list_s
, vrrp_vr_s
);
114 TAILQ_HEAD(vrrp_intf_list_s
, vrrp_intf_s
);
115 static struct vrrp_vr_list_s vrrp_vr_list
;
116 static struct vrrp_intf_list_s vrrp_intf_list
;
117 static char vrrpd_conffile
[MAXPATHLEN
];
120 * Multicast address of VRRP advertisement in network byte order
122 static vrrp_addr_t vrrp_muladdr4
;
123 static vrrp_addr_t vrrp_muladdr6
;
125 static int vrrpd_scan_interval
= 20000; /* ms */
129 * macros to calculate skew_time and master_down_timer
131 * Note that the input is in centisecs and output are in msecs
133 #define SKEW_TIME(pri, intv) ((intv) * (256 - (pri)) / 256)
134 #define MASTER_DOWN_INTERVAL(pri, intv) (3 * (intv) + SKEW_TIME((pri), (intv)))
136 #define SKEW_TIME_VR(vr) \
137 SKEW_TIME((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int)
138 #define MASTER_DOWN_INTERVAL_VR(vr) \
139 MASTER_DOWN_INTERVAL((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int)
141 #define VRRP_CONF_UPDATE 0x01
142 #define VRRP_CONF_DELETE 0x02
144 static char *af_str(int);
146 static iu_tq_callback_t vrrp_adv_timeout
;
147 static iu_tq_callback_t vrrp_b2m_timeout
;
148 static iu_eh_callback_t vrrpd_sock_handler
;
149 static iu_eh_callback_t vrrpd_rtsock_handler
;
150 static iu_eh_callback_t vrrpd_cmdsock_handler
;
152 static int daemon_init();
154 static vrrp_err_t
vrrpd_init();
155 static void vrrpd_fini();
156 static vrrp_err_t
vrrpd_cmdsock_create();
157 static void vrrpd_cmdsock_destroy();
158 static vrrp_err_t
vrrpd_rtsock_create();
159 static void vrrpd_rtsock_destroy();
160 static vrrp_err_t
vrrpd_ctlsock_create();
161 static void vrrpd_ctlsock_destroy();
163 static void vrrpd_scan_timer(iu_tq_t
*, void *);
164 static void vrrpd_scan(int);
165 static vrrp_err_t
vrrpd_init_rxsock(vrrp_vr_t
*);
166 static void vrrpd_fini_rxsock(vrrp_vr_t
*);
167 static vrrp_err_t
vrrpd_init_txsock(vrrp_vr_t
*);
168 static vrrp_err_t
vrrpd_init_txsock_v4(vrrp_vr_t
*);
169 static vrrp_err_t
vrrpd_init_txsock_v6(vrrp_vr_t
*);
170 static void vrrpd_fini_txsock(vrrp_vr_t
*);
172 static vrrp_err_t
vrrpd_create_vr(vrrp_vr_conf_t
*);
173 static vrrp_err_t
vrrpd_enable_vr(vrrp_vr_t
*);
174 static void vrrpd_disable_vr(vrrp_vr_t
*, vrrp_intf_t
*, boolean_t
);
175 static void vrrpd_delete_vr(vrrp_vr_t
*);
177 static vrrp_err_t
vrrpd_create(vrrp_vr_conf_t
*, boolean_t
);
178 static vrrp_err_t
vrrpd_delete(const char *);
179 static vrrp_err_t
vrrpd_enable(const char *, boolean_t
);
180 static vrrp_err_t
vrrpd_disable(const char *);
181 static vrrp_err_t
vrrpd_modify(vrrp_vr_conf_t
*, uint32_t);
182 static void vrrpd_list(vrid_t
, char *, int, vrrp_ret_list_t
*, size_t *);
183 static void vrrpd_query(const char *, vrrp_ret_query_t
*, size_t *);
185 static boolean_t
vrrp_rd_prop_name(vrrp_vr_conf_t
*, const char *);
186 static boolean_t
vrrp_rd_prop_vrid(vrrp_vr_conf_t
*, const char *);
187 static boolean_t
vrrp_rd_prop_af(vrrp_vr_conf_t
*, const char *);
188 static boolean_t
vrrp_rd_prop_pri(vrrp_vr_conf_t
*, const char *);
189 static boolean_t
vrrp_rd_prop_adver_int(vrrp_vr_conf_t
*, const char *);
190 static boolean_t
vrrp_rd_prop_preempt(vrrp_vr_conf_t
*, const char *);
191 static boolean_t
vrrp_rd_prop_accept(vrrp_vr_conf_t
*, const char *);
192 static boolean_t
vrrp_rd_prop_ifname(vrrp_vr_conf_t
*, const char *);
193 static boolean_t
vrrp_rd_prop_enabled(vrrp_vr_conf_t
*, const char *);
194 static int vrrp_wt_prop_name(vrrp_vr_conf_t
*, char *, size_t);
195 static int vrrp_wt_prop_vrid(vrrp_vr_conf_t
*, char *, size_t);
196 static int vrrp_wt_prop_af(vrrp_vr_conf_t
*, char *, size_t);
197 static int vrrp_wt_prop_pri(vrrp_vr_conf_t
*, char *, size_t);
198 static int vrrp_wt_prop_adver_int(vrrp_vr_conf_t
*, char *, size_t);
199 static int vrrp_wt_prop_preempt(vrrp_vr_conf_t
*, char *, size_t);
200 static int vrrp_wt_prop_accept(vrrp_vr_conf_t
*, char *, size_t);
201 static int vrrp_wt_prop_ifname(vrrp_vr_conf_t
*, char *, size_t);
202 static int vrrp_wt_prop_enabled(vrrp_vr_conf_t
*, char *, size_t);
204 static void vrrpd_cmd_create(void *, void *, size_t *);
205 static void vrrpd_cmd_delete(void *, void *, size_t *);
206 static void vrrpd_cmd_enable(void *, void *, size_t *);
207 static void vrrpd_cmd_disable(void *, void *, size_t *);
208 static void vrrpd_cmd_modify(void *, void *, size_t *);
209 static void vrrpd_cmd_list(void *, void *, size_t *);
210 static void vrrpd_cmd_query(void *, void *, size_t *);
212 static vrrp_vr_t
*vrrpd_lookup_vr_by_vrid(char *, vrid_t vrid_t
, int);
213 static vrrp_vr_t
*vrrpd_lookup_vr_by_name(const char *);
214 static vrrp_intf_t
*vrrpd_lookup_if(const char *, int);
215 static vrrp_err_t
vrrpd_create_if(const char *, int, uint32_t, vrrp_intf_t
**);
216 static void vrrpd_delete_if(vrrp_intf_t
*, boolean_t
);
217 static vrrp_err_t
vrrpd_create_ip(vrrp_intf_t
*, const char *, vrrp_addr_t
*,
219 static void vrrpd_delete_ip(vrrp_intf_t
*, vrrp_ip_t
*);
221 static void vrrpd_init_ipcache(int);
222 static void vrrpd_update_ipcache(int);
223 static ipadm_status_t
vrrpd_walk_addr_info(int);
224 static vrrp_err_t
vrrpd_add_ipaddr(char *, int, vrrp_addr_t
*,
226 static vrrp_ip_t
*vrrpd_select_primary(vrrp_intf_t
*);
227 static void vrrpd_reselect_primary(vrrp_intf_t
*);
228 static void vrrpd_reenable_all_vr();
229 static void vrrpd_remove_if(vrrp_intf_t
*, boolean_t
);
231 static uint16_t in_cksum(int, uint16_t, void *);
232 static uint16_t vrrp_cksum4(struct in_addr
*, struct in_addr
*,
233 uint16_t, vrrp_pkt_t
*);
234 static uint16_t vrrp_cksum6(struct in6_addr
*, struct in6_addr
*,
235 uint16_t, vrrp_pkt_t
*);
236 static size_t vrrpd_build_vrrp(vrrp_vr_t
*, uchar_t
*, int, boolean_t
);
238 static void vrrpd_process_adv(vrrp_vr_t
*, vrrp_addr_t
*, vrrp_pkt_t
*);
239 static vrrp_err_t
vrrpd_send_adv(vrrp_vr_t
*, boolean_t
);
241 /* state transition functions */
242 static vrrp_err_t
vrrpd_state_i2m(vrrp_vr_t
*);
243 static vrrp_err_t
vrrpd_state_i2b(vrrp_vr_t
*);
244 static void vrrpd_state_m2i(vrrp_vr_t
*);
245 static void vrrpd_state_b2i(vrrp_vr_t
*);
246 static vrrp_err_t
vrrpd_state_b2m(vrrp_vr_t
*);
247 static vrrp_err_t
vrrpd_state_m2b(vrrp_vr_t
*);
248 static void vrrpd_state_trans(vrrp_state_t
, vrrp_state_t
, vrrp_vr_t
*);
250 static vrrp_err_t
vrrpd_set_noaccept(vrrp_vr_t
*, boolean_t
);
251 static vrrp_err_t
vrrpd_virtualip_update(vrrp_vr_t
*, boolean_t
);
252 static vrrp_err_t
vrrpd_virtualip_updateone(vrrp_intf_t
*, vrrp_ip_t
*,
254 static int vrrpd_post_event(const char *, vrrp_state_t
, vrrp_state_t
);
256 static void vrrpd_initconf();
257 static vrrp_err_t
vrrpd_updateconf(vrrp_vr_conf_t
*, uint_t
);
258 static vrrp_err_t
vrrpd_write_vrconf(char *, size_t, vrrp_vr_conf_t
*);
259 static vrrp_err_t
vrrpd_read_vrconf(char *, vrrp_vr_conf_t
*);
260 static vrrp_err_t
vrrpd_readprop(const char *, vrrp_vr_conf_t
*);
261 static void vrrpd_cleanup();
263 static void vrrp_log(int, char *, ...);
264 static int timeval_to_milli(struct timeval
);
265 static struct timeval
timeval_delta(struct timeval
, struct timeval
);
267 typedef struct vrrpd_prop_s
{
269 boolean_t (*vs_propread
)(vrrp_vr_conf_t
*, const char *);
270 int (*vs_propwrite
)(vrrp_vr_conf_t
*, char *, size_t);
274 * persistent VRRP properties array
276 static vrrp_prop_t vrrp_prop_info_tbl
[] = {
277 {"name", vrrp_rd_prop_name
, vrrp_wt_prop_name
},
278 {"vrid", vrrp_rd_prop_vrid
, vrrp_wt_prop_vrid
},
279 {"priority", vrrp_rd_prop_pri
, vrrp_wt_prop_pri
},
280 {"adv_intval", vrrp_rd_prop_adver_int
, vrrp_wt_prop_adver_int
},
281 {"preempt_mode", vrrp_rd_prop_preempt
, vrrp_wt_prop_preempt
},
282 {"accept_mode", vrrp_rd_prop_accept
, vrrp_wt_prop_accept
},
283 {"interface", vrrp_rd_prop_ifname
, vrrp_wt_prop_ifname
},
284 {"af", vrrp_rd_prop_af
, vrrp_wt_prop_af
},
285 {"enabled", vrrp_rd_prop_enabled
, vrrp_wt_prop_enabled
}
288 #define VRRP_PROP_INFO_TABSIZE \
289 (sizeof (vrrp_prop_info_tbl) / sizeof (vrrp_prop_t))
291 typedef void vrrp_cmd_func_t(void *, void *, size_t *);
293 typedef struct vrrp_cmd_info_s
{
294 vrrp_cmd_type_t vi_cmd
;
296 size_t vi_acksize
; /* 0 if the size is variable */
297 boolean_t vi_setop
; /* Set operation? Check credentials */
298 vrrp_cmd_func_t
*vi_cmdfunc
;
301 static vrrp_cmd_info_t vrrp_cmd_info_tbl
[] = {
302 {VRRP_CMD_CREATE
, sizeof (vrrp_cmd_create_t
),
303 sizeof (vrrp_ret_create_t
), _B_TRUE
, vrrpd_cmd_create
},
304 {VRRP_CMD_DELETE
, sizeof (vrrp_cmd_delete_t
),
305 sizeof (vrrp_ret_delete_t
), _B_TRUE
, vrrpd_cmd_delete
},
306 {VRRP_CMD_ENABLE
, sizeof (vrrp_cmd_enable_t
),
307 sizeof (vrrp_ret_enable_t
), _B_TRUE
, vrrpd_cmd_enable
},
308 {VRRP_CMD_DISABLE
, sizeof (vrrp_cmd_disable_t
),
309 sizeof (vrrp_ret_disable_t
), _B_TRUE
, vrrpd_cmd_disable
},
310 {VRRP_CMD_MODIFY
, sizeof (vrrp_cmd_modify_t
),
311 sizeof (vrrp_ret_modify_t
), _B_TRUE
, vrrpd_cmd_modify
},
312 {VRRP_CMD_QUERY
, sizeof (vrrp_cmd_query_t
), 0,
313 _B_FALSE
, vrrpd_cmd_query
},
314 {VRRP_CMD_LIST
, sizeof (vrrp_cmd_list_t
), 0,
315 _B_FALSE
, vrrpd_cmd_list
}
318 #define VRRP_DOOR_INFO_TABLE_SIZE \
319 (sizeof (vrrp_cmd_info_tbl) / sizeof (vrrp_cmd_info_t))
322 ipaddr_cmp(int af
, vrrp_addr_t
*addr1
, vrrp_addr_t
*addr2
)
325 return (memcmp(&addr1
->in4
.sin_addr
,
326 &addr2
->in4
.sin_addr
, sizeof (struct in_addr
)));
328 return (memcmp(&addr1
->in6
.sin6_addr
,
329 &addr2
->in6
.sin6_addr
, sizeof (struct in6_addr
)));
334 vrrpd_lookup_vr_by_vrid(char *ifname
, vrid_t vrid
, int af
)
338 TAILQ_FOREACH(vr
, &vrrp_vr_list
, vvr_next
) {
339 if (strcmp(vr
->vvr_conf
.vvc_link
, ifname
) == 0 &&
340 vr
->vvr_conf
.vvc_vrid
== vrid
&&
341 vr
->vvr_conf
.vvc_af
== af
) {
349 vrrpd_lookup_vr_by_name(const char *name
)
353 TAILQ_FOREACH(vr
, &vrrp_vr_list
, vvr_next
) {
354 if (strcmp(vr
->vvr_conf
.vvc_name
, name
) == 0)
361 vrrpd_lookup_if(const char *ifname
, int af
)
365 TAILQ_FOREACH(intf
, &vrrp_intf_list
, vvi_next
) {
366 if (strcmp(ifname
, intf
->vvi_ifname
) == 0 &&
367 af
== intf
->vvi_af
) {
375 vrrpd_create_if(const char *ifname
, int af
, uint32_t ifindex
,
380 vrrp_log(VRRP_DBG0
, "vrrpd_create_if(%s, %s, %d)",
381 ifname
, af_str(af
), ifindex
);
383 if (((*intfp
) = malloc(sizeof (vrrp_intf_t
))) == NULL
) {
384 vrrp_log(VRRP_ERR
, "vrrpd_create_if(): failed to "
385 "allocate %s/%s interface", ifname
, af_str(af
));
386 return (VRRP_ENOMEM
);
390 TAILQ_INIT(&intf
->vvi_iplist
);
391 (void) strlcpy(intf
->vvi_ifname
, ifname
, sizeof (intf
->vvi_ifname
));
393 intf
->vvi_sockfd
= -1;
396 intf
->vvi_pip
= NULL
;
397 intf
->vvi_ifindex
= ifindex
;
398 intf
->vvi_state
= NODE_STATE_NEW
;
399 intf
->vvi_vr_state
= VRRP_STATE_INIT
;
400 TAILQ_INSERT_TAIL(&vrrp_intf_list
, intf
, vvi_next
);
401 return (VRRP_SUCCESS
);
405 * An interface is deleted. If update_vr is true, the deletion of the interface
406 * may cause the state transition of assoicated VRRP router (if this interface
407 * is either the primary or the VNIC interface of the VRRP router); otherwise,
408 * simply delete the interface without updating the VRRP router.
411 vrrpd_delete_if(vrrp_intf_t
*intf
, boolean_t update_vr
)
415 vrrp_log(VRRP_DBG0
, "vrrpd_delete_if(%s, %s, %supdate_vr)",
416 intf
->vvi_ifname
, af_str(intf
->vvi_af
), update_vr
? "" : "no_");
420 * If a this interface is the physical interface or the VNIC
421 * of a VRRP router, the deletion of the interface (no IP
422 * address exists on this interface) may cause the state
423 * transition of the VRRP router. call vrrpd_remove_if()
424 * to find all corresponding VRRP router and update their
427 vrrpd_remove_if(intf
, _B_FALSE
);
431 * First remove and delete all the IP addresses on the interface
433 while (!TAILQ_EMPTY(&intf
->vvi_iplist
)) {
434 ip
= TAILQ_FIRST(&intf
->vvi_iplist
);
435 vrrpd_delete_ip(intf
, ip
);
439 * Then remove and delete the interface
441 TAILQ_REMOVE(&vrrp_intf_list
, intf
, vvi_next
);
446 vrrpd_create_ip(vrrp_intf_t
*intf
, const char *lifname
, vrrp_addr_t
*addr
,
450 char abuf
[INET6_ADDRSTRLEN
];
452 /* LINTED E_CONSTANT_CONDITION */
453 VRRPADDR2STR(intf
->vvi_af
, addr
, abuf
, INET6_ADDRSTRLEN
, _B_FALSE
);
454 vrrp_log(VRRP_DBG0
, "vrrpd_create_ip(%s, %s, %s, 0x%x)",
455 intf
->vvi_ifname
, lifname
, abuf
, flags
);
457 if ((ip
= malloc(sizeof (vrrp_ip_t
))) == NULL
) {
458 vrrp_log(VRRP_ERR
, "vrrpd_create_ip(%s, %s):"
459 "failed to allocate IP", lifname
, abuf
);
460 return (VRRP_ENOMEM
);
463 (void) strncpy(ip
->vip_lifname
, lifname
, sizeof (ip
->vip_lifname
));
464 ip
->vip_state
= NODE_STATE_NEW
;
465 ip
->vip_flags
= flags
;
466 (void) memcpy(&ip
->vip_addr
, addr
, sizeof (ip
->vip_addr
));
469 * Make sure link-local IPv6 IP addresses are at the head of the list
471 if (intf
->vvi_af
== AF_INET6
&&
472 IN6_IS_ADDR_LINKLOCAL(&addr
->in6
.sin6_addr
)) {
473 TAILQ_INSERT_HEAD(&intf
->vvi_iplist
, ip
, vip_next
);
475 TAILQ_INSERT_TAIL(&intf
->vvi_iplist
, ip
, vip_next
);
477 return (VRRP_SUCCESS
);
481 vrrpd_delete_ip(vrrp_intf_t
*intf
, vrrp_ip_t
*ip
)
483 char abuf
[INET6_ADDRSTRLEN
];
484 int af
= intf
->vvi_af
;
486 /* LINTED E_CONSTANT_CONDITION */
487 VRRPADDR2STR(af
, &ip
->vip_addr
, abuf
, sizeof (abuf
), _B_FALSE
);
488 vrrp_log(VRRP_DBG0
, "vrrpd_delete_ip(%s, %s, %s) is %sprimary",
489 intf
->vvi_ifname
, ip
->vip_lifname
, abuf
,
490 intf
->vvi_pip
== ip
? "" : "not ");
492 if (intf
->vvi_pip
== ip
)
493 intf
->vvi_pip
= NULL
;
495 TAILQ_REMOVE(&intf
->vvi_iplist
, ip
, vip_next
);
500 rtm_event2str(uchar_t event
)
504 return ("RTM_NEWADDR");
506 return ("RTM_DELADDR");
508 return ("RTM_IFINFO");
512 return ("RTM_DELETE");
514 return ("RTM_CHANGE");
516 return ("RTM_OLDADD");
518 return ("RTM_OLDDEL");
520 return ("RTM_CHGADDR");
522 return ("RTM_FREEADDR");
524 return ("RTM_OTHER");
529 * This is called by the child process to inform the parent process to
530 * exit with the given return value. Note that the child process
531 * (the daemon process) informs the parent process to exit when anything
532 * goes wrong or when all the intialization is done.
535 vrrpd_inform_parent_exit(int rv
)
540 * If vrrp_debug_level is none-zero, vrrpd is not running as
541 * a daemon. Return directly.
543 if (vrrp_debug_level
!= 0)
546 if (write(pfds
[1], &rv
, sizeof (int)) != sizeof (int)) {
548 (void) close(pfds
[1]);
551 (void) close(pfds
[1]);
556 main(int argc
, char *argv
[])
563 (void) setlocale(LC_ALL
, "");
564 (void) textdomain(TEXT_DOMAIN
);
567 * We need PRIV_SYS_CONFIG to post VRRP sysevent, PRIV_NET_RAWACESS
568 * and PRIV_NET_ICMPACCESS to open the raw socket, PRIV_SYS_IP_CONFIG
569 * to bring up/down the virtual IP addresses, and PRIV_SYS_RESOURCE to
572 * Note that sysevent is not supported in non-global zones.
574 if (getzoneid() == GLOBAL_ZONEID
) {
575 err
= __init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
, 0, 0,
576 PRIV_SYS_CONFIG
, PRIV_NET_RAWACCESS
, PRIV_NET_ICMPACCESS
,
577 PRIV_SYS_IP_CONFIG
, PRIV_SYS_RESOURCE
, NULL
);
579 err
= __init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
, 0, 0,
580 PRIV_NET_RAWACCESS
, PRIV_NET_ICMPACCESS
,
581 PRIV_SYS_IP_CONFIG
, PRIV_SYS_RESOURCE
, NULL
);
585 vrrp_log(VRRP_ERR
, "main(): init_daemon_priv() failed");
586 return (EXIT_FAILURE
);
590 * If vrrpd is started by other process, it will inherit the
591 * signal block mask. We unblock all signals to make sure the
592 * signal handling will work normally.
594 (void) sigfillset(&mask
);
595 (void) thr_sigsetmask(SIG_UNBLOCK
, &mask
, NULL
);
596 sa
.sa_handler
= vrrpd_cleanup
;
598 (void) sigemptyset(&sa
.sa_mask
);
599 (void) sigaction(SIGINT
, &sa
, NULL
);
600 (void) sigaction(SIGQUIT
, &sa
, NULL
);
601 (void) sigaction(SIGTERM
, &sa
, NULL
);
603 vrrp_debug_level
= 0;
604 (void) strlcpy(vrrpd_conffile
, VRRPCONF
, sizeof (vrrpd_conffile
));
605 while ((c
= getopt(argc
, argv
, "d:f:")) != EOF
) {
608 vrrp_debug_level
= atoi(optarg
);
611 (void) strlcpy(vrrpd_conffile
, optarg
,
612 sizeof (vrrpd_conffile
));
620 if (vrrp_debug_level
== 0 && (daemon_init() != 0)) {
621 vrrp_log(VRRP_ERR
, "main(): daemon_init() failed");
622 return (EXIT_FAILURE
);
625 rl
.rlim_cur
= RLIM_INFINITY
;
626 rl
.rlim_max
= RLIM_INFINITY
;
627 if (setrlimit(RLIMIT_NOFILE
, &rl
) == -1) {
628 vrrp_log(VRRP_ERR
, "main(): setrlimit() failed");
632 if (vrrpd_init() != VRRP_SUCCESS
) {
633 vrrp_log(VRRP_ERR
, "main(): vrrpd_init() failed");
638 * Get rid of unneeded privileges.
640 __fini_daemon_priv(PRIV_PROC_FORK
, PRIV_PROC_EXEC
, PRIV_PROC_SESSION
,
641 PRIV_FILE_LINK_ANY
, PRIV_PROC_INFO
, PRIV_SYS_RESOURCE
, NULL
);
644 * Read the configuration and initialize the existing VRRP
650 * Inform the parent process that it can successfully exit.
652 if ((err
= vrrpd_inform_parent_exit(EXIT_SUCCESS
)) != 0) {
654 vrrp_log(VRRP_WARNING
, "vrrpd_inform_parent_exit() failed: %s",
656 return (EXIT_FAILURE
);
660 * Start the loop to handle the timer and the IO events.
662 switch (iu_handle_events(vrrpd_eh
, vrrpd_timerq
)) {
664 vrrp_log(VRRP_ERR
, "main(): iu_handle_events() failed "
672 return (EXIT_SUCCESS
);
675 (void) vrrpd_inform_parent_exit(EXIT_FAILURE
);
676 return (EXIT_FAILURE
);
685 vrrp_log(VRRP_DBG0
, "daemon_init()");
687 if (getenv("SMF_FMRI") == NULL
) {
688 vrrp_log(VRRP_ERR
, "daemon_init(): vrrpd is an smf(5) managed "
689 "service and should not be run from the command line.");
694 * Create the pipe used for the child process to inform the parent
695 * process to exit after all initialization is done.
697 if (pipe(pfds
) < 0) {
698 vrrp_log(VRRP_ERR
, "daemon_init(): pipe() failed: %s",
703 if ((pid
= fork()) < 0) {
704 vrrp_log(VRRP_ERR
, "daemon_init(): fork() failed: %s",
706 (void) close(pfds
[0]);
707 (void) close(pfds
[1]);
711 if (pid
!= 0) { /* Parent */
712 (void) close(pfds
[1]);
715 * Read the child process's return value from the pfds.
716 * If the child process exits unexpectedly, read() returns -1.
718 if (read(pfds
[0], &rv
, sizeof (int)) != sizeof (int)) {
719 vrrp_log(VRRP_ERR
, "daemon_init(): child process "
720 "exited unexpectedly %s", strerror(errno
));
721 (void) kill(pid
, SIGTERM
);
724 (void) close(pfds
[0]);
729 * in child process, became a daemon, and return to main() to continue.
731 (void) close(pfds
[0]);
737 (void) open("/dev/null", O_RDWR
, 0);
740 openlog("vrrpd", LOG_PID
, LOG_DAEMON
);
748 vrrp_err_t err
= VRRP_ESYS
;
750 vrrp_log(VRRP_DBG0
, "vrrpd_init()");
752 TAILQ_INIT(&vrrp_vr_list
);
753 TAILQ_INIT(&vrrp_intf_list
);
755 if (vrrp_open(&vrrpd_vh
) != VRRP_SUCCESS
) {
756 vrrp_log(VRRP_ERR
, "vrrpd_init(): vrrp_open() failed");
760 if ((vrrpd_timerq
= iu_tq_create()) == NULL
) {
761 vrrp_log(VRRP_ERR
, "vrrpd_init(): iu_tq_create() failed");
765 if ((vrrpd_eh
= iu_eh_create()) == NULL
) {
766 vrrp_log(VRRP_ERR
, "vrrpd_init(): iu_eh_create() failed");
771 * Create the AF_UNIX socket used to communicate with libvrrpadm.
773 * This socket is used to receive the administrative requests and
774 * send back the results.
776 if (vrrpd_cmdsock_create() != VRRP_SUCCESS
) {
777 vrrp_log(VRRP_ERR
, "vrrpd_init(): vrrpd_cmdsock_create() "
783 * Create the VRRP control socket used to bring up/down the virtual
784 * IP addresses. It is also used to set the IFF_NOACCEPT flag of
785 * the virtual IP addresses.
787 if (vrrpd_ctlsock_create() != VRRP_SUCCESS
) {
788 vrrp_log(VRRP_ERR
, "vrrpd_init(): vrrpd_ctlsock_create() "
794 * Create the PF_ROUTER socket used to listen to the routing socket
795 * messages and build the interface/IP address list.
797 if (vrrpd_rtsock_create() != VRRP_SUCCESS
) {
798 vrrp_log(VRRP_ERR
, "vrrpd_init(): vrrpd_rtsock_create() "
803 /* Open the libipadm handle */
804 if (ipadm_open(&vrrp_ipadm_handle
, 0) != IPADM_SUCCESS
) {
805 vrrp_log(VRRP_ERR
, "vrrpd_init(): ipadm_open() failed");
810 * Build the list of interfaces and IP addresses. Also, start the time
811 * to scan the interfaces/IP addresses periodically.
814 vrrpd_scan(AF_INET6
);
815 if ((vrrp_scan_timer_id
= iu_schedule_timer_ms(vrrpd_timerq
,
816 vrrpd_scan_interval
, vrrpd_scan_timer
, NULL
)) == -1) {
817 vrrp_log(VRRP_ERR
, "vrrpd_init(): start scan_timer failed");
822 * Initialize the VRRP multicast address.
824 bzero(&vrrp_muladdr4
, sizeof (vrrp_addr_t
));
825 vrrp_muladdr4
.in4
.sin_family
= AF_INET
;
826 (void) inet_pton(AF_INET
, "224.0.0.18", &vrrp_muladdr4
.in4
.sin_addr
);
828 bzero(&vrrp_muladdr6
, sizeof (vrrp_addr_t
));
829 vrrp_muladdr6
.in6
.sin6_family
= AF_INET6
;
830 (void) inet_pton(AF_INET6
, "ff02::12", &vrrp_muladdr6
.in6
.sin6_addr
);
832 return (VRRP_SUCCESS
);
842 vrrp_log(VRRP_DBG0
, "vrrpd_fini()");
844 (void) iu_cancel_timer(vrrpd_timerq
, vrrp_scan_timer_id
, NULL
);
845 vrrp_scan_timer_id
= -1;
847 vrrpd_rtsock_destroy();
848 vrrpd_ctlsock_destroy();
849 vrrpd_cmdsock_destroy();
851 if (vrrpd_eh
!= NULL
) {
852 iu_eh_destroy(vrrpd_eh
);
856 if (vrrpd_timerq
!= NULL
) {
857 iu_tq_destroy(vrrpd_timerq
);
861 vrrp_close(vrrpd_vh
);
863 assert(TAILQ_EMPTY(&vrrp_vr_list
));
864 assert(TAILQ_EMPTY(&vrrp_intf_list
));
866 ipadm_close(vrrp_ipadm_handle
);
875 vrrp_log(VRRP_DBG0
, "vrrpd_cleanup()");
877 while (!TAILQ_EMPTY(&vrrp_vr_list
)) {
878 vr
= TAILQ_FIRST(&vrrp_vr_list
);
882 while (!TAILQ_EMPTY(&vrrp_intf_list
)) {
883 intf
= TAILQ_FIRST(&vrrp_intf_list
);
884 vrrpd_delete_if(intf
, _B_FALSE
);
893 * Read the configuration file and initialize all the existing VRRP routers.
904 vrrp_log(VRRP_DBG0
, "vrrpd_initconf()");
906 if ((fp
= fopen(vrrpd_conffile
, "rF")) == NULL
) {
907 vrrp_log(VRRP_ERR
, "failed to open the configuration file %s",
912 while (fgets(line
, sizeof (line
), fp
) != NULL
) {
914 conf
.vvc_vrid
= VRRP_VRID_NONE
;
915 if ((err
= vrrpd_read_vrconf(line
, &conf
)) != VRRP_SUCCESS
) {
916 vrrp_log(VRRP_ERR
, "failed to parse %d line %s",
922 * Blank or comment line
924 if (conf
.vvc_vrid
== VRRP_VRID_NONE
)
928 * No need to update the configuration since the VRRP router
929 * created/enabled based on the existing configuration.
931 if ((err
= vrrpd_create(&conf
, _B_FALSE
)) != VRRP_SUCCESS
) {
932 vrrp_log(VRRP_ERR
, "VRRP router %s creation failed: "
933 "%s", conf
.vvc_name
, vrrp_err2str(err
));
937 if (conf
.vvc_enabled
&&
938 ((err
= vrrpd_enable(conf
.vvc_name
, _B_FALSE
)) !=
940 vrrp_log(VRRP_ERR
, "VRRP router %s enable failed: %s",
941 conf
.vvc_name
, vrrp_err2str(err
));
949 * Create the AF_UNIX socket used to communicate with libvrrpadm.
951 * This socket is used to receive the administrative request and
952 * send back the results.
955 vrrpd_cmdsock_create()
958 struct sockaddr_un laddr
;
961 vrrp_log(VRRP_DBG0
, "vrrpd_cmdsock_create()");
963 if ((sock
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
964 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_create(): socket(AF_UNIX) "
965 "failed: %s", strerror(errno
));
970 * Set it to be non-blocking.
972 flags
= fcntl(sock
, F_GETFL
, 0);
973 (void) fcntl(sock
, F_SETFL
, (flags
| O_NONBLOCK
));
976 * Unlink first in case a previous daemon instance exited ungracefully.
978 (void) unlink(VRRPD_SOCKET
);
980 bzero(&laddr
, sizeof (laddr
));
981 laddr
.sun_family
= AF_UNIX
;
982 (void) strlcpy(laddr
.sun_path
, VRRPD_SOCKET
, sizeof (laddr
.sun_path
));
983 if (bind(sock
, (struct sockaddr
*)&laddr
, sizeof (laddr
)) < 0) {
984 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_create(): bind() failed: %s",
990 if (listen(sock
, 30) < 0) {
991 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_create(): listen() "
992 "failed: %s", strerror(errno
));
997 if ((eid
= iu_register_event(vrrpd_eh
, sock
, POLLIN
,
998 vrrpd_cmdsock_handler
, NULL
)) == -1) {
999 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_create(): iu_register_event()"
1005 vrrpd_cmdsock_fd
= sock
;
1006 vrrpd_cmdsock_eid
= eid
;
1007 return (VRRP_SUCCESS
);
1011 vrrpd_cmdsock_destroy()
1013 vrrp_log(VRRP_DBG0
, "vrrpd_cmdsock_destroy()");
1015 (void) iu_unregister_event(vrrpd_eh
, vrrpd_cmdsock_eid
, NULL
);
1016 (void) close(vrrpd_cmdsock_fd
);
1017 vrrpd_cmdsock_fd
= -1;
1018 vrrpd_cmdsock_eid
= -1;
1022 * Create the PF_ROUTER sockets used to listen to the routing socket
1023 * messages and build the interface/IP address list. Create one for
1024 * each address family (IPv4 and IPv6).
1027 vrrpd_rtsock_create()
1032 vrrp_log(VRRP_DBG0
, "vrrpd_rtsock_create()");
1034 for (i
= 0; i
< 2; i
++) {
1035 sock
= socket(PF_ROUTE
, SOCK_RAW
, vrrpd_rtsocks
[i
].vrt_af
);
1037 vrrp_log(VRRP_ERR
, "vrrpd_rtsock_create(): socket() "
1038 "failed: %s", strerror(errno
));
1043 * Set it to be non-blocking.
1045 if ((flags
= fcntl(sock
, F_GETFL
, 0)) < 0) {
1046 vrrp_log(VRRP_ERR
, "vrrpd_rtsock_create(): "
1047 "fcntl(F_GETFL) failed: %s", strerror(errno
));
1051 if ((fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
)) < 0) {
1052 vrrp_log(VRRP_ERR
, "vrrpd_rtsock_create(): "
1053 "fcntl(F_SETFL) failed: %s", strerror(errno
));
1057 if ((eid
= iu_register_event(vrrpd_eh
, sock
, POLLIN
,
1058 vrrpd_rtsock_handler
, &(vrrpd_rtsocks
[i
].vrt_af
))) == -1) {
1059 vrrp_log(VRRP_ERR
, "vrrpd_rtsock_create(): register "
1060 "rtsock %d(%s) failed", sock
,
1061 af_str(vrrpd_rtsocks
[i
].vrt_af
));
1065 vrrpd_rtsocks
[i
].vrt_fd
= sock
;
1066 vrrpd_rtsocks
[i
].vrt_eid
= eid
;
1071 vrrpd_rtsock_destroy();
1075 return (VRRP_SUCCESS
);
1079 vrrpd_rtsock_destroy()
1083 vrrp_log(VRRP_DBG0
, "vrrpd_rtsock_destroy()");
1084 for (i
= 0; i
< 2; i
++) {
1085 (void) iu_unregister_event(vrrpd_eh
, vrrpd_rtsocks
[i
].vrt_eid
,
1087 (void) close(vrrpd_rtsocks
[i
].vrt_fd
);
1088 vrrpd_rtsocks
[i
].vrt_eid
= -1;
1089 vrrpd_rtsocks
[i
].vrt_fd
= -1;
1094 * Create the VRRP control socket used to bring up/down the virtual
1095 * IP addresses. It is also used to set the IFF_NOACCEPT flag of
1096 * the virtual IP addresses.
1099 vrrpd_ctlsock_create()
1104 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
1105 vrrp_log(VRRP_ERR
, "vrrpd_ctlsock_create(): socket(INET) "
1106 "failed: %s", strerror(errno
));
1109 if (setsockopt(s
, SOL_SOCKET
, SO_VRRP
, &on
, sizeof (on
)) < 0) {
1110 vrrp_log(VRRP_ERR
, "vrrpd_ctlsock_create(): "
1111 "setsockopt(INET, SO_VRRP) failed: %s", strerror(errno
));
1116 if ((s6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
1117 vrrp_log(VRRP_ERR
, "vrrpd_ctlsock_create(): socket(INET6) "
1118 "failed: %s", strerror(errno
));
1122 if (setsockopt(s6
, SOL_SOCKET
, SO_VRRP
, &on
, sizeof (on
)) < 0) {
1123 vrrp_log(VRRP_ERR
, "vrrpd_ctlsock_create(): "
1124 "setsockopt(INET6, SO_VRRP) failed: %s", strerror(errno
));
1130 vrrpd_ctlsock_fd
= s
;
1131 vrrpd_ctlsock6_fd
= s6
;
1132 return (VRRP_SUCCESS
);
1136 vrrpd_ctlsock_destroy()
1138 (void) close(vrrpd_ctlsock_fd
);
1139 vrrpd_ctlsock_fd
= -1;
1140 (void) close(vrrpd_ctlsock6_fd
);
1141 vrrpd_ctlsock6_fd
= -1;
1146 vrrpd_cmd_create(void *arg1
, void *arg2
, size_t *arg2_sz
)
1148 vrrp_cmd_create_t
*cmd
= (vrrp_cmd_create_t
*)arg1
;
1149 vrrp_ret_create_t
*ret
= (vrrp_ret_create_t
*)arg2
;
1152 err
= vrrpd_create(&cmd
->vcc_conf
, _B_TRUE
);
1153 if (err
== VRRP_SUCCESS
&& cmd
->vcc_conf
.vvc_enabled
) {
1155 * No need to update the configuration since it is already
1156 * done in the above vrrpd_create() call
1158 err
= vrrpd_enable(cmd
->vcc_conf
.vvc_name
, _B_FALSE
);
1159 if (err
!= VRRP_SUCCESS
)
1160 (void) vrrpd_delete(cmd
->vcc_conf
.vvc_name
);
1167 vrrpd_cmd_delete(void *arg1
, void *arg2
, size_t *arg2_sz
)
1169 vrrp_cmd_delete_t
*cmd
= (vrrp_cmd_delete_t
*)arg1
;
1170 vrrp_ret_delete_t
*ret
= (vrrp_ret_delete_t
*)arg2
;
1172 ret
->vrd_err
= vrrpd_delete(cmd
->vcd_name
);
1177 vrrpd_cmd_enable(void *arg1
, void *arg2
, size_t *arg2_sz
)
1179 vrrp_cmd_enable_t
*cmd
= (vrrp_cmd_enable_t
*)arg1
;
1180 vrrp_ret_enable_t
*ret
= (vrrp_ret_enable_t
*)arg2
;
1182 ret
->vrs_err
= vrrpd_enable(cmd
->vcs_name
, _B_TRUE
);
1187 vrrpd_cmd_disable(void *arg1
, void *arg2
, size_t *arg2_sz
)
1189 vrrp_cmd_disable_t
*cmd
= (vrrp_cmd_disable_t
*)arg1
;
1190 vrrp_ret_disable_t
*ret
= (vrrp_ret_disable_t
*)arg2
;
1192 ret
->vrx_err
= vrrpd_disable(cmd
->vcx_name
);
1197 vrrpd_cmd_modify(void *arg1
, void *arg2
, size_t *arg2_sz
)
1199 vrrp_cmd_modify_t
*cmd
= (vrrp_cmd_modify_t
*)arg1
;
1200 vrrp_ret_modify_t
*ret
= (vrrp_ret_modify_t
*)arg2
;
1202 ret
->vrm_err
= vrrpd_modify(&cmd
->vcm_conf
, cmd
->vcm_mask
);
1206 vrrpd_cmd_query(void *arg1
, void *arg2
, size_t *arg2_sz
)
1208 vrrp_cmd_query_t
*cmd
= (vrrp_cmd_query_t
*)arg1
;
1210 vrrpd_query(cmd
->vcq_name
, arg2
, arg2_sz
);
1214 vrrpd_cmd_list(void *arg1
, void *arg2
, size_t *arg2_sz
)
1216 vrrp_cmd_list_t
*cmd
= (vrrp_cmd_list_t
*)arg1
;
1218 vrrpd_list(cmd
->vcl_vrid
, cmd
->vcl_ifname
, cmd
->vcl_af
, arg2
, arg2_sz
);
1222 * Write-type requeset must have the solaris.network.vrrp authorization.
1225 vrrp_auth_check(int connfd
, vrrp_cmd_info_t
*cinfo
)
1227 ucred_t
*cred
= NULL
;
1230 boolean_t success
= _B_FALSE
;
1232 vrrp_log(VRRP_DBG0
, "vrrp_auth_check()");
1234 if (!cinfo
->vi_setop
)
1238 * Validate the credential
1240 if (getpeerucred(connfd
, &cred
) == (uid_t
)-1) {
1241 vrrp_log(VRRP_ERR
, "vrrp_auth_check(): getpeerucred() "
1242 "failed: %s", strerror(errno
));
1246 if ((uid
= ucred_getruid((const ucred_t
*)cred
)) == (uid_t
)-1) {
1247 vrrp_log(VRRP_ERR
, "vrrp_auth_check(): ucred_getruid() "
1248 "failed: %s", strerror(errno
));
1252 if ((pw
= getpwuid(uid
)) == NULL
) {
1253 vrrp_log(VRRP_ERR
, "vrrp_auth_check(): getpwuid() failed");
1257 success
= (chkauthattr("solaris.network.vrrp", pw
->pw_name
) == 1);
1265 * Process the administrative request from libvrrpadm
1269 vrrpd_cmdsock_handler(iu_eh_t
*eh
, int s
, short events
, iu_event_id_t id
,
1272 vrrp_cmd_info_t
*cinfo
= NULL
;
1273 vrrp_err_t err
= VRRP_SUCCESS
;
1274 uchar_t buf
[BUFFSIZE
], ackbuf
[BUFFSIZE
];
1275 size_t cursize
, acksize
, len
;
1278 struct sockaddr_in from
;
1281 vrrp_log(VRRP_DBG0
, "vrrpd_cmdsock_handler()");
1283 fromlen
= (socklen_t
)sizeof (from
);
1284 if ((connfd
= accept(s
, (struct sockaddr
*)&from
, &fromlen
)) < 0) {
1285 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_handler() accept(): %s",
1291 * First get the type of the request
1294 while (cursize
< sizeof (uint32_t)) {
1295 len
= read(connfd
, buf
+ cursize
,
1296 sizeof (uint32_t) - cursize
);
1297 if (len
== (size_t)-1 && (errno
== EAGAIN
|| errno
== EINTR
)) {
1299 } else if (len
> 0) {
1303 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_handler(): invalid message "
1305 (void) close(connfd
);
1309 /* LINTED E_BAD_PTR_CAST_ALIGN */
1310 cmd
= ((vrrp_cmd_t
*)buf
)->vc_cmd
;
1311 for (i
= 0; i
< VRRP_DOOR_INFO_TABLE_SIZE
; i
++) {
1312 if (vrrp_cmd_info_tbl
[i
].vi_cmd
== cmd
) {
1313 cinfo
= vrrp_cmd_info_tbl
+ i
;
1318 if (cinfo
== NULL
) {
1319 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_handler(): invalid request "
1326 * Get the rest of the request.
1328 assert(cursize
== sizeof (uint32_t));
1329 while (cursize
< cinfo
->vi_reqsize
) {
1330 len
= read(connfd
, buf
+ cursize
,
1331 cinfo
->vi_reqsize
- cursize
);
1332 if (len
== (size_t)-1 && (errno
== EAGAIN
|| errno
== EINTR
)) {
1334 } else if (len
> 0) {
1338 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_handler(): invalid message "
1345 * Validate the authorization
1347 if (!vrrp_auth_check(connfd
, cinfo
)) {
1348 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_handler(): "
1349 "not sufficient authorization");
1358 /* LINTED E_BAD_PTR_CAST_ALIGN */
1359 ((vrrp_ret_t
*)ackbuf
)->vr_err
= err
;
1360 acksize
= sizeof (vrrp_ret_t
);
1363 * If the size of ack is varied, the cmdfunc callback
1364 * will set the right size.
1366 if ((acksize
= cinfo
->vi_acksize
) == 0)
1367 acksize
= sizeof (ackbuf
);
1369 /* LINTED E_BAD_PTR_CAST_ALIGN */
1370 cinfo
->vi_cmdfunc((vrrp_cmd_t
*)buf
, ackbuf
, &acksize
);
1374 * Send the ack back.
1377 while (cursize
< acksize
) {
1378 len
= sendto(connfd
, ackbuf
+ cursize
, acksize
- cursize
,
1379 0, (struct sockaddr
*)&from
, fromlen
);
1380 if (len
== (size_t)-1 && errno
== EAGAIN
) {
1382 } else if (len
> 0) {
1386 vrrp_log(VRRP_ERR
, "vrrpd_cmdsock_handler() failed to "
1387 "ack: %s", strerror(errno
));
1392 (void) shutdown(connfd
, SHUT_RDWR
);
1393 (void) close(connfd
);
1397 * Process the routing socket messages and update the interfaces/IP addresses
1402 vrrpd_rtsock_handler(iu_eh_t
*eh
, int s
, short events
,
1403 iu_event_id_t id
, void *arg
)
1406 struct ifa_msghdr
*ifam
;
1408 int af
= *(int *)arg
;
1409 boolean_t scanif
= _B_FALSE
;
1412 nbytes
= read(s
, buf
, sizeof (buf
));
1414 /* No more messages */
1418 /* LINTED E_BAD_PTR_CAST_ALIGN */
1419 ifam
= (struct ifa_msghdr
*)buf
;
1420 if (ifam
->ifam_version
!= RTM_VERSION
) {
1421 vrrp_log(VRRP_ERR
, "vrrpd_rtsock_handler(): version %d "
1422 "not understood", ifam
->ifam_version
);
1426 vrrp_log(VRRP_DBG0
, "vrrpd_rtsock_handler(): recv %s event",
1427 rtm_event2str(ifam
->ifam_type
));
1429 switch (ifam
->ifam_type
) {
1435 * An IP address has been created/updated/deleted or
1436 * brought up/down, re-initilialize the interface/IP
1442 /* Not interesting */
1452 * Periodically scan the interface/IP addresses on the system.
1456 vrrpd_scan_timer(iu_tq_t
*tq
, void *arg
)
1458 vrrp_log(VRRP_DBG0
, "vrrpd_scan_timer()");
1459 vrrpd_scan(AF_INET
);
1460 vrrpd_scan(AF_INET6
);
1464 * Get the list of the interface/IP addresses of the specified address
1470 vrrp_log(VRRP_DBG0
, "vrrpd_scan(%s)", af_str(af
));
1473 vrrpd_init_ipcache(af
);
1475 /* If interface index changes, walk again. */
1476 if (vrrpd_walk_addr_info(af
) != IPADM_SUCCESS
)
1479 vrrpd_update_ipcache(af
);
1483 * First mark all IP addresses of the specific address family to be removed.
1484 * This flag will then be cleared when we walk up all the IP addresses.
1487 vrrpd_init_ipcache(int af
)
1489 vrrp_intf_t
*intf
, *next_intf
;
1490 vrrp_ip_t
*ip
, *nextip
;
1491 char abuf
[INET6_ADDRSTRLEN
];
1493 vrrp_log(VRRP_DBG0
, "vrrpd_init_ipcache(%s)", af_str(af
));
1495 next_intf
= TAILQ_FIRST(&vrrp_intf_list
);
1496 while ((intf
= next_intf
) != NULL
) {
1497 next_intf
= TAILQ_NEXT(intf
, vvi_next
);
1498 if (intf
->vvi_af
!= af
)
1502 * If the interface is still marked as new, it means that this
1503 * vrrpd_init_ipcache() call is a result of ifindex change,
1504 * which causes the re-walk of all the interfaces (see
1505 * vrrpd_add_ipaddr()), and some interfaces are still marked
1506 * as new during the last walk. In this case, delete this
1507 * interface with the "update_vr" argument to be _B_FALSE,
1508 * since no VRRP router has been assoicated with this
1509 * interface yet (the association is done in
1510 * vrrpd_update_ipcache()).
1512 * This interface will be re-added later if it still exists.
1514 if (intf
->vvi_state
== NODE_STATE_NEW
) {
1515 vrrp_log(VRRP_DBG0
, "vrrpd_init_ipcache(): remove %s "
1516 "(%d), may be added later", intf
->vvi_ifname
,
1518 vrrpd_delete_if(intf
, _B_FALSE
);
1522 for (ip
= TAILQ_FIRST(&intf
->vvi_iplist
); ip
!= NULL
;
1524 nextip
= TAILQ_NEXT(ip
, vip_next
);
1525 /* LINTED E_CONSTANT_CONDITION */
1526 VRRPADDR2STR(af
, &ip
->vip_addr
, abuf
,
1527 INET6_ADDRSTRLEN
, _B_FALSE
);
1529 if (ip
->vip_state
!= NODE_STATE_NEW
) {
1530 vrrp_log(VRRP_DBG0
, "vrrpd_init_ipcache(%s/%d, "
1531 "%s(%s/0x%x))", intf
->vvi_ifname
,
1532 intf
->vvi_ifindex
, ip
->vip_lifname
,
1533 abuf
, ip
->vip_flags
);
1534 ip
->vip_state
= NODE_STATE_STALE
;
1539 * If the IP is still marked as new, it means that
1540 * this vrrpd_init_ipcache() call is a result of
1541 * ifindex change, which causes the re-walk of all
1542 * the IP addresses (see vrrpd_add_ipaddr()).
1545 * This IP will be readded later if it still exists.
1547 vrrp_log(VRRP_DBG0
, "vrrpd_init_ipcache(): remove "
1548 "%s/%d , %s(%s)", intf
->vvi_ifname
,
1549 intf
->vvi_ifindex
, ip
->vip_lifname
, abuf
);
1550 vrrpd_delete_ip(intf
, ip
);
1556 * Walk all the IP addresses of the given family and update its
1557 * addresses list. Return IPADM_FAILURE if it is required to walk
1558 * all the interfaces again (one of the interface index changes in between).
1560 static ipadm_status_t
1561 vrrpd_walk_addr_info(int af
)
1563 ipadm_addr_info_t
*ainfo
, *ainfop
;
1564 ipadm_status_t ipstatus
;
1566 struct sockaddr_storage stor
;
1571 vrrp_log(VRRP_DBG0
, "vrrpd_walk_addr_info(%s)", af_str(af
));
1573 ipstatus
= ipadm_addr_info(vrrp_ipadm_handle
, NULL
, &ainfo
, 0, 0);
1574 if (ipstatus
!= IPADM_SUCCESS
) {
1575 vrrp_log(VRRP_ERR
, "vrrpd_walk_addr_info(%s): "
1576 "ipadm_addr_info() failed: %s",
1577 af_str(af
), ipadm_status2str(ipstatus
));
1578 return (IPADM_SUCCESS
);
1581 for (ainfop
= ainfo
; ainfop
!= NULL
; ainfop
= IA_NEXT(ainfop
)) {
1582 if (ainfop
->ia_ifa
.ifa_addr
->sa_family
!= af
)
1585 lifname
= ainfop
->ia_ifa
.ifa_name
;
1586 flags
= ainfop
->ia_ifa
.ifa_flags
;
1587 (void) memcpy(&stor
, ainfop
->ia_ifa
.ifa_addr
, sizeof (stor
));
1588 addr
= (vrrp_addr_t
*)&stor
;
1590 vrrp_log(VRRP_DBG0
, "vrrpd_walk_addr_info(%s): %s",
1591 af_str(af
), lifname
);
1593 /* Skip virtual/IPMP/P2P interfaces */
1594 if (flags
& (IFF_VIRTUAL
|IFF_IPMP
|IFF_POINTOPOINT
)) {
1595 vrrp_log(VRRP_DBG0
, "vrrpd_walk_addr_info(%s): "
1596 "skipped %s", af_str(af
), lifname
);
1600 /* Filter out the all-zero IP address */
1601 if (VRRPADDR_UNSPECIFIED(af
, addr
))
1604 if ((ifindex
= if_nametoindex(lifname
)) == 0) {
1605 if (errno
!= ENXIO
&& errno
!= ENOENT
) {
1606 vrrp_log(VRRP_ERR
, "vrrpd_walk_addr_info(%s): "
1607 "if_nametoindex() failed for %s: %s",
1608 af_str(af
), lifname
, strerror(errno
));
1614 * The interface is unplumbed/replumbed during the walk. Try
1615 * to walk the IP addresses one more time.
1617 if (vrrpd_add_ipaddr(lifname
, af
, addr
, ifindex
, flags
)
1619 ipstatus
= IPADM_FAILURE
;
1624 ipadm_free_addr_info(ainfo
);
1629 * Given the information of each IP address, update the interface and
1633 vrrpd_add_ipaddr(char *lifname
, int af
, vrrp_addr_t
*addr
, int ifindex
,
1636 char ifname
[LIFNAMSIZ
], *c
;
1639 char abuf
[INET6_ADDRSTRLEN
];
1642 /* LINTED E_CONSTANT_CONDITION */
1643 VRRPADDR2STR(af
, addr
, abuf
, INET6_ADDRSTRLEN
, _B_FALSE
);
1644 vrrp_log(VRRP_DBG0
, "vrrpd_add_ipaddr(%s, %s, %d, 0x%x)", lifname
,
1645 abuf
, ifindex
, flags
);
1648 * Get the physical interface name from the logical interface name.
1650 (void) strlcpy(ifname
, lifname
, sizeof (ifname
));
1651 if ((c
= strchr(ifname
, ':')) != NULL
)
1654 if ((intf
= vrrpd_lookup_if(ifname
, af
)) == NULL
) {
1655 vrrp_log(VRRP_DBG0
, "vrrpd_add_ipaddr(): %s is new", ifname
);
1656 err
= vrrpd_create_if(ifname
, af
, ifindex
, &intf
);
1657 if (err
!= VRRP_SUCCESS
)
1659 } else if (intf
->vvi_ifindex
!= ifindex
) {
1661 * If index changes, it means that this interface is
1662 * unplumbed/replumbed since we last checked. If this
1663 * interface is not used by any VRRP router, just
1664 * update its ifindex, and the IP addresses list will
1665 * be updated later. Otherwise, return EAGAIN to rewalk
1666 * all the IP addresses from the beginning.
1668 vrrp_log(VRRP_DBG0
, "vrrpd_add_ipaddr(%s) ifindex changed ",
1669 "from %d to %d", ifname
, intf
->vvi_ifindex
, ifindex
);
1670 if (!IS_PRIMARY_INTF(intf
) && !IS_VIRTUAL_INTF(intf
)) {
1671 intf
->vvi_ifindex
= ifindex
;
1674 * delete this interface from the list if this
1675 * interface has already been assoicated with
1678 vrrpd_delete_if(intf
, _B_TRUE
);
1679 return (VRRP_EAGAIN
);
1684 * Does this IP address already exist?
1686 TAILQ_FOREACH(ip
, &intf
->vvi_iplist
, vip_next
) {
1687 if (strcmp(ip
->vip_lifname
, lifname
) == 0)
1692 vrrp_log(VRRP_DBG0
, "vrrpd_add_ipaddr(%s, %s) IP exists",
1694 ip
->vip_state
= NODE_STATE_NONE
;
1695 ip
->vip_flags
= flags
;
1696 if (ipaddr_cmp(af
, addr
, &ip
->vip_addr
) != 0) {
1698 * Address has been changed, mark it as new
1699 * If this address is already selected as the
1700 * primary IP address, the new IP will be checked
1701 * to see whether it is still qualified as the
1702 * primary IP address. If not, the primary IP
1703 * address will be reselected.
1705 (void) memcpy(&ip
->vip_addr
, addr
,
1706 sizeof (vrrp_addr_t
));
1708 ip
->vip_state
= NODE_STATE_NEW
;
1711 vrrp_log(VRRP_DBG0
, "vrrpd_add_ipaddr(%s, %s) IP is new",
1714 err
= vrrpd_create_ip(intf
, lifname
, addr
, flags
);
1715 if (err
!= VRRP_SUCCESS
)
1718 return (VRRP_SUCCESS
);
1722 * Update the interface and IP addresses list. Remove the ones that have been
1723 * staled since last time we walk the IP addresses and updated the ones that
1724 * have been changed.
1727 vrrpd_update_ipcache(int af
)
1729 vrrp_intf_t
*intf
, *nextif
;
1730 vrrp_ip_t
*ip
, *nextip
;
1731 char abuf
[INET6_ADDRSTRLEN
];
1732 boolean_t primary_selected
;
1733 boolean_t primary_now_selected
;
1734 boolean_t need_reenable
= _B_FALSE
;
1736 vrrp_log(VRRP_DBG0
, "vrrpd_update_ipcache(%s)", af_str(af
));
1738 nextif
= TAILQ_FIRST(&vrrp_intf_list
);
1739 while ((intf
= nextif
) != NULL
) {
1740 nextif
= TAILQ_NEXT(intf
, vvi_next
);
1741 if (intf
->vvi_af
!= af
)
1745 * Does the interface already select its primary IP address?
1747 primary_selected
= (intf
->vvi_pip
!= NULL
);
1748 assert(!primary_selected
|| IS_PRIMARY_INTF(intf
));
1751 * Removed the IP addresses that have been unconfigured.
1753 for (ip
= TAILQ_FIRST(&intf
->vvi_iplist
); ip
!= NULL
;
1755 nextip
= TAILQ_NEXT(ip
, vip_next
);
1756 if (ip
->vip_state
!= NODE_STATE_STALE
)
1759 /* LINTED E_CONSTANT_CONDITION */
1760 VRRPADDR2STR(af
, &ip
->vip_addr
, abuf
, INET6_ADDRSTRLEN
,
1762 vrrp_log(VRRP_DBG0
, "vrrpd_update_ipcache(): IP %s "
1763 "is removed over %s", abuf
, intf
->vvi_ifname
);
1764 vrrpd_delete_ip(intf
, ip
);
1768 * No IP addresses left, delete this interface.
1770 if (TAILQ_EMPTY(&intf
->vvi_iplist
)) {
1771 vrrp_log(VRRP_DBG0
, "vrrpd_update_ipcache(): "
1772 "no IP left over %s", intf
->vvi_ifname
);
1773 vrrpd_delete_if(intf
, _B_TRUE
);
1778 * If this is selected ss the physical interface for any
1779 * VRRP router, reselect the primary address if needed.
1781 if (IS_PRIMARY_INTF(intf
)) {
1782 vrrpd_reselect_primary(intf
);
1783 primary_now_selected
= (intf
->vvi_pip
!= NULL
);
1786 * Cannot find the new primary IP address.
1788 if (primary_selected
&& !primary_now_selected
) {
1789 vrrp_log(VRRP_DBG0
, "vrrpd_update_ipcache() "
1790 "reselect primary IP on %s failed",
1792 vrrpd_remove_if(intf
, _B_TRUE
);
1793 } else if (!primary_selected
&& primary_now_selected
) {
1795 * The primary IP address is successfully
1796 * selected on the physical interfacew we
1797 * need to walk through all the VRRP routers
1798 * that is created on this physical interface
1799 * and see whether they can now be enabled.
1801 need_reenable
= _B_TRUE
;
1806 * For every new virtual IP address, bring up/down it based
1807 * on the state of VRRP router.
1809 * Note that it is fine to not update the IP's vip_flags field
1810 * even if vrrpd_virtualip_updateone() changed the address's
1811 * up/down state, since the vip_flags field is only used for
1812 * select primary IP address over a physical interface, and
1813 * vrrpd_virtualip_updateone() only affects the virtual IP
1816 for (ip
= TAILQ_FIRST(&intf
->vvi_iplist
); ip
!= NULL
;
1818 nextip
= TAILQ_NEXT(ip
, vip_next
);
1819 /* LINTED E_CONSTANT_CONDITION */
1820 VRRPADDR2STR(af
, &ip
->vip_addr
, abuf
, INET6_ADDRSTRLEN
,
1822 vrrp_log(VRRP_DBG0
, "vrrpd_update_ipcache(): "
1823 "IP %s over %s%s", abuf
, intf
->vvi_ifname
,
1824 ip
->vip_state
== NODE_STATE_NEW
? " is new" : "");
1826 if (IS_VIRTUAL_INTF(intf
)) {
1828 * If this IP is new, update its up/down state
1829 * based on the virtual interface's state
1830 * (which is determined by the VRRP router's
1831 * state). Otherwise, check only and prompt
1832 * warnings if its up/down state has been
1835 if (vrrpd_virtualip_updateone(intf
, ip
,
1836 ip
->vip_state
== NODE_STATE_NONE
) !=
1839 "vrrpd_update_ipcache(): "
1840 "IP %s over %s update failed", abuf
,
1842 vrrpd_delete_ip(intf
, ip
);
1846 ip
->vip_state
= NODE_STATE_NONE
;
1850 * The IP address is deleted when it is failed to be brought
1851 * up. If no IP addresses are left, delete this interface.
1853 if (TAILQ_EMPTY(&intf
->vvi_iplist
)) {
1854 vrrp_log(VRRP_DBG0
, "vrrpd_update_ipcache(): "
1855 "no IP left over %s", intf
->vvi_ifname
);
1856 vrrpd_delete_if(intf
, _B_TRUE
);
1860 if (intf
->vvi_state
== NODE_STATE_NEW
) {
1862 * A new interface is found. This interface can be
1863 * the primary interface or the virtual VNIC
1864 * interface. Again, we need to walk throught all
1865 * the VRRP routers to see whether some of them can
1866 * now be enabled because of the new primary IP
1867 * address or the new virtual IP addresses.
1869 intf
->vvi_state
= NODE_STATE_NONE
;
1870 need_reenable
= _B_TRUE
;
1875 vrrpd_reenable_all_vr();
1879 * Reselect primary IP if:
1880 * - The existing primary IP is no longer qualified (removed or it is down or
1881 * not a link-local IP for IPv6 VRRP router);
1882 * - This is a physical interface but no primary IP is chosen;
1885 vrrpd_reselect_primary(vrrp_intf_t
*intf
)
1888 char abuf
[INET6_ADDRSTRLEN
];
1890 assert(IS_PRIMARY_INTF(intf
));
1893 * If the interface's old primary IP address is still valid, return
1895 if (((ip
= intf
->vvi_pip
) != NULL
) && (QUALIFY_PRIMARY_ADDR(intf
, ip
)))
1899 /* LINTED E_CONSTANT_CONDITION */
1900 VRRPADDR2STR(intf
->vvi_af
, &ip
->vip_addr
, abuf
,
1901 sizeof (abuf
), _B_FALSE
);
1902 vrrp_log(VRRP_DBG0
, "vrrpd_reselect_primary(%s): primary IP %s "
1903 "is no longer qualified", intf
->vvi_ifname
, abuf
);
1906 ip
= vrrpd_select_primary(intf
);
1910 /* LINTED E_CONSTANT_CONDITION */
1911 VRRPADDR2STR(intf
->vvi_af
, &ip
->vip_addr
, abuf
,
1912 sizeof (abuf
), _B_FALSE
);
1913 vrrp_log(VRRP_DBG0
, "vrrpd_reselect_primary(%s): primary IP %s "
1914 "is selected", intf
->vvi_ifname
, abuf
);
1919 * Select the primary IP address. Since the link-local IP address is always
1920 * at the head of the IP address list, try to find the first UP IP address
1921 * and see whether it qualify.
1924 vrrpd_select_primary(vrrp_intf_t
*pif
)
1927 char abuf
[INET6_ADDRSTRLEN
];
1929 vrrp_log(VRRP_DBG1
, "vrrpd_select_primary(%s)", pif
->vvi_ifname
);
1931 TAILQ_FOREACH(pip
, &pif
->vvi_iplist
, vip_next
) {
1932 assert(pip
->vip_state
!= NODE_STATE_STALE
);
1934 /* LINTED E_CONSTANT_CONDITION */
1935 VRRPADDR2STR(pif
->vvi_af
, &pip
->vip_addr
, abuf
,
1936 INET6_ADDRSTRLEN
, _B_FALSE
);
1937 vrrp_log(VRRP_DBG0
, "vrrpd_select_primary(%s): %s is %s",
1938 pif
->vvi_ifname
, abuf
,
1939 (pip
->vip_flags
& IFF_UP
) ? "up" : "down");
1941 if (pip
->vip_flags
& IFF_UP
)
1946 * Is this valid primary IP address?
1948 if (pip
== NULL
|| !QUALIFY_PRIMARY_ADDR(pif
, pip
)) {
1949 vrrp_log(VRRP_DBG0
, "vrrpd_select_primary(%s/%s) failed",
1950 pif
->vvi_ifname
, af_str(pif
->vvi_af
));
1957 * This is a new interface. Check whether any VRRP router is waiting for it
1960 vrrpd_reenable_all_vr()
1964 vrrp_log(VRRP_DBG0
, "vrrpd_reenable_all_vr()");
1966 TAILQ_FOREACH(vr
, &vrrp_vr_list
, vvr_next
) {
1967 if (vr
->vvr_conf
.vvc_enabled
)
1968 (void) vrrpd_enable_vr(vr
);
1973 * If primary_addr_gone is _B_TRUE, it means that we failed to select
1974 * the primary IP address on this (physical) interface; otherwise,
1975 * it means the interface is no longer available.
1978 vrrpd_remove_if(vrrp_intf_t
*intf
, boolean_t primary_addr_gone
)
1982 vrrp_log(VRRP_DBG0
, "vrrpd_remove_if(%s): %s", intf
->vvi_ifname
,
1983 primary_addr_gone
? "primary address gone" : "interface deleted");
1985 TAILQ_FOREACH(vr
, &vrrp_vr_list
, vvr_next
) {
1986 if (vr
->vvr_conf
.vvc_enabled
)
1987 vrrpd_disable_vr(vr
, intf
, primary_addr_gone
);
1992 * Update the VRRP configuration file based on the given configuration.
1993 * op is either VRRP_CONF_UPDATE or VRRP_CONF_DELETE
1996 vrrpd_updateconf(vrrp_vr_conf_t
*newconf
, uint_t op
)
1998 vrrp_vr_conf_t conf
;
2001 char line
[LINE_MAX
];
2002 char newfile
[MAXPATHLEN
];
2003 boolean_t found
= _B_FALSE
;
2004 vrrp_err_t err
= VRRP_SUCCESS
;
2006 vrrp_log(VRRP_DBG0
, "vrrpd_updateconf(%s, %s)", newconf
->vvc_name
,
2007 op
== VRRP_CONF_UPDATE
? "update" : "delete");
2009 if ((fp
= fopen(vrrpd_conffile
, "r+F")) == NULL
) {
2010 if (errno
!= ENOENT
) {
2011 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): open %s for "
2012 "update failed: %s", vrrpd_conffile
,
2017 if ((fp
= fopen(vrrpd_conffile
, "w+F")) == NULL
) {
2018 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): open %s for "
2019 "write failed: %s", vrrpd_conffile
,
2025 (void) snprintf(newfile
, MAXPATHLEN
, "%s.new", vrrpd_conffile
);
2026 if ((nfd
= open(newfile
, O_WRONLY
| O_CREAT
| O_TRUNC
,
2027 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) < 0) {
2028 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): open %s failed: %s",
2029 newfile
, strerror(errno
));
2034 if ((nfp
= fdopen(nfd
, "wF")) == NULL
) {
2035 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): fdopen(%s) failed: %s",
2036 newfile
, strerror(errno
));
2040 while (fgets(line
, sizeof (line
), fp
) != NULL
) {
2041 conf
.vvc_vrid
= VRRP_VRID_NONE
;
2042 if (!found
&& (err
= vrrpd_read_vrconf(line
, &conf
)) !=
2044 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): invalid "
2045 "configuration format: %s", line
);
2050 * Write this line out if:
2051 * - this is a comment line; or
2052 * - we've done updating/deleting the the given VR; or
2053 * - if the name of the VR read from this line does not match
2054 * the VR name that we are about to update/delete;
2056 if (found
|| conf
.vvc_vrid
== VRRP_VRID_NONE
||
2057 strcmp(conf
.vvc_name
, newconf
->vvc_name
) != 0) {
2058 if (fputs(line
, nfp
) != EOF
)
2061 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): failed to "
2062 "write line %s", line
);
2068 * Otherwise, update/skip the line.
2071 if (op
== VRRP_CONF_DELETE
)
2074 assert(op
== VRRP_CONF_UPDATE
);
2075 if ((err
= vrrpd_write_vrconf(line
, sizeof (line
),
2076 newconf
)) != VRRP_SUCCESS
) {
2077 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): failed to "
2078 "update configuration for %s", newconf
->vvc_name
);
2081 if (fputs(line
, nfp
) == EOF
) {
2082 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): failed to "
2083 "write line %s", line
);
2090 * If we get to the end of the file and have not seen the router that
2091 * we are about to update, write it out.
2093 if (!found
&& op
== VRRP_CONF_UPDATE
) {
2094 if ((err
= vrrpd_write_vrconf(line
, sizeof (line
),
2095 newconf
)) == VRRP_SUCCESS
&& fputs(line
, nfp
) == EOF
) {
2096 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): failed to "
2097 "write line %s", line
);
2100 } else if (!found
&& op
== VRRP_CONF_DELETE
) {
2101 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): failed to find "
2102 "configuation for %s", newconf
->vvc_name
);
2103 err
= VRRP_ENOTFOUND
;
2106 if (err
!= VRRP_SUCCESS
)
2109 if (fflush(nfp
) == EOF
|| rename(newfile
, vrrpd_conffile
) < 0) {
2110 vrrp_log(VRRP_ERR
, "vrrpd_updateconf(): failed to "
2111 "rename file %s", newfile
);
2118 (void) unlink(newfile
);
2123 vrrpd_write_vrconf(char *line
, size_t len
, vrrp_vr_conf_t
*conf
)
2128 vrrp_log(VRRP_DBG0
, "vrrpd_write_vrconf(%s)", conf
->vvc_name
);
2130 for (i
= 0; i
< VRRP_PROP_INFO_TABSIZE
; i
++) {
2131 prop
= &vrrp_prop_info_tbl
[i
];
2132 n
= snprintf(line
, len
, i
== 0 ? "%s=" : " %s=",
2134 if (n
< 0 || n
>= len
)
2138 n
= prop
->vs_propwrite(conf
, line
, len
);
2139 if (n
< 0 || n
>= len
)
2144 if (i
!= VRRP_PROP_INFO_TABSIZE
) {
2145 vrrp_log(VRRP_ERR
, "vrrpd_write_vrconf(%s): buffer size too"
2146 "small", conf
->vvc_name
);
2149 n
= snprintf(line
, len
, "\n");
2150 if (n
< 0 || n
>= len
) {
2151 vrrp_log(VRRP_ERR
, "vrrpd_write_vrconf(%s): buffer size too"
2152 "small", conf
->vvc_name
);
2155 return (VRRP_SUCCESS
);
2159 vrrpd_read_vrconf(char *line
, vrrp_vr_conf_t
*conf
)
2163 vrrp_err_t err
= VRRP_SUCCESS
;
2164 char tmpbuf
[MAXLINELEN
];
2167 (void) strlcpy(tmpbuf
, line
, MAXLINELEN
);
2170 * Skip leading spaces, blank lines, and comments.
2172 skip_whitespace(str
);
2173 if ((str
- tmpbuf
== strlen(tmpbuf
)) || (*str
== '#')) {
2174 conf
->vvc_vrid
= VRRP_VRID_NONE
;
2175 return (VRRP_SUCCESS
);
2179 * Read each VR properties.
2181 for (token
= strtok_r(str
, " \n\t", &next
); token
!= NULL
;
2182 token
= strtok_r(NULL
, " \n\t", &next
)) {
2183 if ((err
= vrrpd_readprop(token
, conf
)) != VRRP_SUCCESS
)
2187 /* All properties read but no VRID defined */
2188 if (err
== VRRP_SUCCESS
&& conf
->vvc_vrid
== VRRP_VRID_NONE
)
2195 vrrpd_readprop(const char *str
, vrrp_vr_conf_t
*conf
)
2201 if ((pstr
= strchr(str
, '=')) == NULL
) {
2202 vrrp_log(VRRP_ERR
, "vrrpd_readprop(%s): invalid property", str
);
2203 return (VRRP_EINVAL
);
2207 for (i
= 0; i
< VRRP_PROP_INFO_TABSIZE
; i
++) {
2208 prop
= &vrrp_prop_info_tbl
[i
];
2209 if (strcasecmp(str
, prop
->vs_propname
) == 0) {
2210 if (prop
->vs_propread(conf
, pstr
))
2215 if (i
== VRRP_PROP_INFO_TABSIZE
) {
2216 vrrp_log(VRRP_ERR
, "vrrpd_readprop(%s): invalid property", str
);
2217 return (VRRP_EINVAL
);
2220 return (VRRP_SUCCESS
);
2224 vrrp_rd_prop_name(vrrp_vr_conf_t
*conf
, const char *str
)
2226 size_t size
= sizeof (conf
->vvc_name
);
2227 return (strlcpy(conf
->vvc_name
, str
, size
) < size
);
2231 vrrp_rd_prop_vrid(vrrp_vr_conf_t
*conf
, const char *str
)
2233 conf
->vvc_vrid
= strtol(str
, NULL
, 0);
2234 return (!(conf
->vvc_vrid
< VRRP_VRID_MIN
||
2235 conf
->vvc_vrid
> VRRP_VRID_MAX
||
2236 (conf
->vvc_vrid
== 0 && errno
!= 0)));
2240 vrrp_rd_prop_af(vrrp_vr_conf_t
*conf
, const char *str
)
2242 if (strcasecmp(str
, "AF_INET") == 0)
2243 conf
->vvc_af
= AF_INET
;
2244 else if (strcasecmp(str
, "AF_INET6") == 0)
2245 conf
->vvc_af
= AF_INET6
;
2252 vrrp_rd_prop_pri(vrrp_vr_conf_t
*conf
, const char *str
)
2254 conf
->vvc_pri
= strtol(str
, NULL
, 0);
2255 return (!(conf
->vvc_pri
< VRRP_PRI_MIN
||
2256 conf
->vvc_pri
> VRRP_PRI_OWNER
||
2257 (conf
->vvc_pri
== 0 && errno
!= 0)));
2261 vrrp_rd_prop_adver_int(vrrp_vr_conf_t
*conf
, const char *str
)
2263 conf
->vvc_adver_int
= strtol(str
, NULL
, 0);
2264 return (!(conf
->vvc_adver_int
< VRRP_MAX_ADVER_INT_MIN
||
2265 conf
->vvc_adver_int
> VRRP_MAX_ADVER_INT_MAX
||
2266 (conf
->vvc_adver_int
== 0 && errno
!= 0)));
2270 vrrp_rd_prop_preempt(vrrp_vr_conf_t
*conf
, const char *str
)
2272 if (strcasecmp(str
, "true") == 0)
2273 conf
->vvc_preempt
= _B_TRUE
;
2274 else if (strcasecmp(str
, "false") == 0)
2275 conf
->vvc_preempt
= _B_FALSE
;
2282 vrrp_rd_prop_accept(vrrp_vr_conf_t
*conf
, const char *str
)
2284 if (strcasecmp(str
, "true") == 0)
2285 conf
->vvc_accept
= _B_TRUE
;
2286 else if (strcasecmp(str
, "false") == 0)
2287 conf
->vvc_accept
= _B_FALSE
;
2294 vrrp_rd_prop_enabled(vrrp_vr_conf_t
*conf
, const char *str
)
2296 if (strcasecmp(str
, "enabled") == 0)
2297 conf
->vvc_enabled
= _B_TRUE
;
2298 else if (strcasecmp(str
, "disabled") == 0)
2299 conf
->vvc_enabled
= _B_FALSE
;
2306 vrrp_rd_prop_ifname(vrrp_vr_conf_t
*conf
, const char *str
)
2308 size_t size
= sizeof (conf
->vvc_link
);
2309 return (strlcpy(conf
->vvc_link
, str
, size
) < size
);
2313 vrrp_wt_prop_name(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2315 return (snprintf(str
, size
, "%s", conf
->vvc_name
));
2319 vrrp_wt_prop_pri(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2321 return (snprintf(str
, size
, "%d", conf
->vvc_pri
));
2325 vrrp_wt_prop_adver_int(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2327 return (snprintf(str
, size
, "%d", conf
->vvc_adver_int
));
2331 vrrp_wt_prop_preempt(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2333 return (snprintf(str
, size
, "%s",
2334 conf
->vvc_preempt
? "true" : "false"));
2338 vrrp_wt_prop_accept(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2340 return (snprintf(str
, size
, "%s",
2341 conf
->vvc_accept
? "true" : "false"));
2345 vrrp_wt_prop_enabled(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2347 return (snprintf(str
, size
, "%s",
2348 conf
->vvc_enabled
? "enabled" : "disabled"));
2352 vrrp_wt_prop_vrid(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2354 return (snprintf(str
, size
, "%d", conf
->vvc_vrid
));
2358 vrrp_wt_prop_af(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2360 return (snprintf(str
, size
, "%s",
2361 conf
->vvc_af
== AF_INET
? "AF_INET" : "AF_INET6"));
2365 vrrp_wt_prop_ifname(vrrp_vr_conf_t
*conf
, char *str
, size_t size
)
2367 return (snprintf(str
, size
, "%s", conf
->vvc_link
));
2373 if (af
== 4 || af
== AF_INET
)
2375 else if (af
== 6 || af
== AF_INET6
)
2376 return ("AF_INET6");
2377 else if (af
== AF_UNSPEC
)
2378 return ("AF_UNSPEC");
2380 return ("AF_error");
2384 vrrpd_create_vr(vrrp_vr_conf_t
*conf
)
2388 vrrp_log(VRRP_DBG0
, "vrrpd_create_vr(%s)", conf
->vvc_name
);
2390 if ((vr
= malloc(sizeof (vrrp_vr_t
))) == NULL
) {
2391 vrrp_log(VRRP_ERR
, "vrrpd_create_vr(): memory allocation for %s"
2392 " failed", conf
->vvc_name
);
2393 return (VRRP_ENOMEM
);
2396 bzero(vr
, sizeof (vrrp_vr_t
));
2397 vr
->vvr_state
= VRRP_STATE_NONE
;
2398 vr
->vvr_timer_id
= -1;
2399 vrrpd_state_trans(VRRP_STATE_NONE
, VRRP_STATE_INIT
, vr
);
2400 (void) memcpy(&vr
->vvr_conf
, conf
, sizeof (vrrp_vr_conf_t
));
2401 vr
->vvr_conf
.vvc_enabled
= _B_FALSE
;
2402 TAILQ_INSERT_HEAD(&vrrp_vr_list
, vr
, vvr_next
);
2403 return (VRRP_SUCCESS
);
2407 vrrpd_delete_vr(vrrp_vr_t
*vr
)
2409 vrrp_log(VRRP_DBG0
, "vrrpd_delete_vr(%s)", vr
->vvr_conf
.vvc_name
);
2410 if (vr
->vvr_conf
.vvc_enabled
)
2411 vrrpd_disable_vr(vr
, NULL
, _B_FALSE
);
2412 assert(vr
->vvr_state
== VRRP_STATE_INIT
);
2413 vrrpd_state_trans(VRRP_STATE_INIT
, VRRP_STATE_NONE
, vr
);
2414 TAILQ_REMOVE(&vrrp_vr_list
, vr
, vvr_next
);
2419 vrrpd_enable_vr(vrrp_vr_t
*vr
)
2421 vrrp_err_t rx_err
, tx_err
, err
= VRRP_EINVAL
;
2423 vrrp_log(VRRP_DBG0
, "vrrpd_enable_vr(%s)", vr
->vvr_conf
.vvc_name
);
2425 assert(vr
->vvr_conf
.vvc_enabled
);
2428 * This VRRP router has been successfully enabled and start
2431 if (vr
->vvr_state
!= VRRP_STATE_INIT
)
2432 return (VRRP_SUCCESS
);
2434 if ((rx_err
= vrrpd_init_rxsock(vr
)) == VRRP_SUCCESS
) {
2436 * Select the primary IP address. Even if this time
2437 * primary IP selection failed, we will reselect the
2438 * primary IP address when new IP address comes up.
2440 vrrpd_reselect_primary(vr
->vvr_pif
);
2441 if (vr
->vvr_pif
->vvi_pip
== NULL
) {
2442 vrrp_log(VRRP_DBG0
, "vrrpd_enable_vr(%s): "
2443 "select_primary over %s failed",
2444 vr
->vvr_conf
.vvc_name
, vr
->vvr_pif
->vvi_ifname
);
2445 rx_err
= VRRP_ENOPRIM
;
2450 * Initialize the TX socket used for this vrrp_vr_t to send the
2451 * multicast packets.
2453 tx_err
= vrrpd_init_txsock(vr
);
2456 * Only start the state transition if sockets for both RX and TX are
2457 * initialized correctly.
2459 if (rx_err
!= VRRP_SUCCESS
|| tx_err
!= VRRP_SUCCESS
) {
2461 * Record the error information for diagnose purpose.
2463 vr
->vvr_err
= (rx_err
== VRRP_SUCCESS
) ? tx_err
: rx_err
;
2467 if (vr
->vvr_conf
.vvc_pri
== 255)
2468 err
= vrrpd_state_i2m(vr
);
2470 err
= vrrpd_state_i2b(vr
);
2472 if (err
!= VRRP_SUCCESS
) {
2474 vr
->vvr_pif
->vvi_pip
= NULL
;
2475 vrrpd_fini_txsock(vr
);
2476 vrrpd_fini_rxsock(vr
);
2482 * Given the removed interface, see whether the given VRRP router would
2483 * be affected and stop participating the VRRP protocol.
2485 * If intf is NULL, VR disabling request is coming from the admin.
2488 vrrpd_disable_vr(vrrp_vr_t
*vr
, vrrp_intf_t
*intf
, boolean_t primary_addr_gone
)
2490 vrrp_log(VRRP_DBG0
, "vrrpd_disable_vr(%s): %s%s", vr
->vvr_conf
.vvc_name
,
2491 intf
== NULL
? "requested by admin" : intf
->vvi_ifname
,
2492 intf
== NULL
? "" : (primary_addr_gone
? "primary address gone" :
2493 "interface deleted"));
2496 * An interface is deleted, see whether this interface is the
2497 * physical interface or the VNIC of the given VRRP router.
2498 * If so, continue to disable the VRRP router.
2500 if (!primary_addr_gone
&& (intf
!= NULL
) && (intf
!= vr
->vvr_pif
) &&
2501 (intf
!= vr
->vvr_vif
)) {
2506 * If this is the case that the primary IP address is gone,
2507 * and we failed to reselect another primary IP address,
2508 * continue to disable the VRRP router.
2510 if (primary_addr_gone
&& intf
!= vr
->vvr_pif
)
2513 vrrp_log(VRRP_DBG1
, "vrrpd_disable_vr(%s): disabling",
2514 vr
->vvr_conf
.vvc_name
);
2516 if (vr
->vvr_state
== VRRP_STATE_MASTER
) {
2518 * If this router is disabled by the administrator, send
2519 * the zero-priority advertisement to indicate the Master
2520 * stops participating VRRP.
2523 (void) vrrpd_send_adv(vr
, _B_TRUE
);
2525 vrrpd_state_m2i(vr
);
2526 } else if (vr
->vvr_state
== VRRP_STATE_BACKUP
) {
2527 vrrpd_state_b2i(vr
);
2531 * If no primary IP address can be selected, the VRRP router
2532 * stays at the INIT state and will become BACKUP and MASTER when
2533 * a primary IP address is reselected.
2535 if (primary_addr_gone
) {
2536 vrrp_log(VRRP_DBG1
, "vrrpd_disable_vr(%s): primary IP "
2537 "is removed", vr
->vvr_conf
.vvc_name
);
2538 vr
->vvr_err
= VRRP_ENOPRIM
;
2539 } else if (intf
== NULL
) {
2541 * The VRRP router is disable by the administrator
2543 vrrp_log(VRRP_DBG1
, "vrrpd_disable_vr(%s): disabled by admin",
2544 vr
->vvr_conf
.vvc_name
);
2545 vr
->vvr_err
= VRRP_SUCCESS
;
2546 vrrpd_fini_txsock(vr
);
2547 vrrpd_fini_rxsock(vr
);
2548 } else if (intf
== vr
->vvr_pif
) {
2549 vrrp_log(VRRP_DBG1
, "vrrpd_disable_vr(%s): physical interface "
2550 "%s removed", vr
->vvr_conf
.vvc_name
, intf
->vvi_ifname
);
2551 vr
->vvr_err
= VRRP_ENOPRIM
;
2552 vrrpd_fini_rxsock(vr
);
2553 } else if (intf
== vr
->vvr_vif
) {
2554 vrrp_log(VRRP_DBG1
, "vrrpd_disable_vr(%s): VNIC interface %s"
2555 " removed", vr
->vvr_conf
.vvc_name
, intf
->vvi_ifname
);
2556 vr
->vvr_err
= VRRP_ENOVIRT
;
2557 vrrpd_fini_txsock(vr
);
2562 vrrpd_create(vrrp_vr_conf_t
*conf
, boolean_t updateconf
)
2564 vrrp_err_t err
= VRRP_SUCCESS
;
2566 vrrp_log(VRRP_DBG0
, "vrrpd_create(%s, %s, %d)", conf
->vvc_name
,
2567 conf
->vvc_link
, conf
->vvc_vrid
);
2569 assert(conf
!= NULL
);
2574 if ((strlen(conf
->vvc_name
) == 0) ||
2575 (strlen(conf
->vvc_link
) == 0) ||
2576 (conf
->vvc_vrid
< VRRP_VRID_MIN
||
2577 conf
->vvc_vrid
> VRRP_VRID_MAX
) ||
2578 (conf
->vvc_pri
< VRRP_PRI_MIN
||
2579 conf
->vvc_pri
> VRRP_PRI_OWNER
) ||
2580 (conf
->vvc_adver_int
< VRRP_MAX_ADVER_INT_MIN
||
2581 conf
->vvc_adver_int
> VRRP_MAX_ADVER_INT_MAX
) ||
2582 (conf
->vvc_af
!= AF_INET
&& conf
->vvc_af
!= AF_INET6
) ||
2583 (conf
->vvc_pri
== VRRP_PRI_OWNER
&& !conf
->vvc_accept
)) {
2584 vrrp_log(VRRP_DBG1
, "vrrpd_create(%s): invalid argument",
2586 return (VRRP_EINVAL
);
2589 if (!vrrp_valid_name(conf
->vvc_name
)) {
2590 vrrp_log(VRRP_DBG1
, "vrrpd_create(): %s is not a valid router "
2591 "name", conf
->vvc_name
);
2592 return (VRRP_EINVALVRNAME
);
2595 if (vrrpd_lookup_vr_by_name(conf
->vvc_name
) != NULL
) {
2596 vrrp_log(VRRP_DBG1
, "vrrpd_create(): %s already exists",
2598 return (VRRP_EINSTEXIST
);
2601 if (vrrpd_lookup_vr_by_vrid(conf
->vvc_link
, conf
->vvc_vrid
,
2602 conf
->vvc_af
) != NULL
) {
2603 vrrp_log(VRRP_DBG1
, "vrrpd_create(): VRID %d/%s over %s "
2604 "already exists", conf
->vvc_vrid
, af_str(conf
->vvc_af
),
2606 return (VRRP_EVREXIST
);
2609 if (updateconf
&& (err
= vrrpd_updateconf(conf
,
2610 VRRP_CONF_UPDATE
)) != VRRP_SUCCESS
) {
2611 vrrp_log(VRRP_ERR
, "vrrpd_create(): failed to update "
2612 "configuration for %s", conf
->vvc_name
);
2616 err
= vrrpd_create_vr(conf
);
2617 if (err
!= VRRP_SUCCESS
&& updateconf
)
2618 (void) vrrpd_updateconf(conf
, VRRP_CONF_DELETE
);
2624 vrrpd_delete(const char *vn
)
2629 vrrp_log(VRRP_DBG0
, "vrrpd_delete(%s)", vn
);
2631 if ((vr
= vrrpd_lookup_vr_by_name(vn
)) == NULL
) {
2632 vrrp_log(VRRP_DBG1
, "vrrpd_delete(): %s not exists", vn
);
2633 return (VRRP_ENOTFOUND
);
2636 err
= vrrpd_updateconf(&vr
->vvr_conf
, VRRP_CONF_DELETE
);
2637 if (err
!= VRRP_SUCCESS
) {
2638 vrrp_log(VRRP_ERR
, "vrrpd_delete(): failed to delete "
2639 "configuration for %s", vr
->vvr_conf
.vvc_name
);
2643 vrrpd_delete_vr(vr
);
2644 return (VRRP_SUCCESS
);
2648 vrrpd_enable(const char *vn
, boolean_t updateconf
)
2651 vrrp_vr_conf_t
*conf
;
2653 datalink_class_t
class;
2654 vrrp_err_t err
= VRRP_SUCCESS
;
2656 vrrp_log(VRRP_DBG0
, "vrrpd_enable(%s)", vn
);
2658 if ((vr
= vrrpd_lookup_vr_by_name(vn
)) == NULL
) {
2659 vrrp_log(VRRP_DBG1
, "vrrpd_enable(): %s does not exist", vn
);
2660 return (VRRP_ENOTFOUND
);
2664 * The VR is already enabled.
2666 conf
= &vr
->vvr_conf
;
2667 if (conf
->vvc_enabled
) {
2668 vrrp_log(VRRP_DBG1
, "vrrpd_enable(): %s is already "
2670 return (VRRP_EALREADY
);
2674 * Check whether the link exists.
2676 if ((strlen(conf
->vvc_link
) == 0) || dladm_name2info(vrrpd_vh
->vh_dh
,
2677 conf
->vvc_link
, NULL
, &flags
, &class, NULL
) != DLADM_STATUS_OK
||
2678 !(flags
& DLADM_OPT_ACTIVE
) || ((class != DATALINK_CLASS_PHYS
) &&
2679 (class != DATALINK_CLASS_VLAN
) && (class != DATALINK_CLASS_AGGR
) &&
2680 (class != DATALINK_CLASS_VNIC
))) {
2681 vrrp_log(VRRP_DBG1
, "vrrpd_enable(%s): invalid link %s",
2682 vn
, conf
->vvc_link
);
2683 return (VRRP_EINVALLINK
);
2687 * Get the associated VNIC name by the given interface/vrid/
2690 err
= vrrp_get_vnicname(vrrpd_vh
, conf
->vvc_vrid
,
2691 conf
->vvc_af
, conf
->vvc_link
, NULL
, NULL
, vr
->vvr_vnic
,
2692 sizeof (vr
->vvr_vnic
));
2693 if (err
!= VRRP_SUCCESS
) {
2694 vrrp_log(VRRP_DBG1
, "vrrpd_enable(%s): no VNIC for VRID %d/%s "
2695 "over %s", vn
, conf
->vvc_vrid
, af_str(conf
->vvc_af
),
2702 * Find the right VNIC, primary interface and get the list of the
2703 * protected IP adressses and primary IP address. Note that if
2704 * either interface is NULL (no IP addresses configured over the
2705 * interface), we will still continue and mark this VRRP router
2708 vr
->vvr_conf
.vvc_enabled
= _B_TRUE
;
2709 if (updateconf
&& (err
= vrrpd_updateconf(&vr
->vvr_conf
,
2710 VRRP_CONF_UPDATE
)) != VRRP_SUCCESS
) {
2711 vrrp_log(VRRP_ERR
, "vrrpd_enable(): failed to update "
2712 "configuration for %s", vr
->vvr_conf
.vvc_name
);
2717 * If vrrpd_setup_vr() fails, it is possible that there is no IP
2718 * addresses over ether the primary interface or the VNIC yet,
2719 * return success in this case, the VRRP router will stay in
2720 * the initialized state and start to work when the IP address is
2723 (void) vrrpd_enable_vr(vr
);
2724 return (VRRP_SUCCESS
);
2727 vr
->vvr_conf
.vvc_enabled
= _B_FALSE
;
2728 vr
->vvr_vnic
[0] = '\0';
2733 vrrpd_disable(const char *vn
)
2738 vrrp_log(VRRP_DBG0
, "vrrpd_disable(%s)", vn
);
2740 if ((vr
= vrrpd_lookup_vr_by_name(vn
)) == NULL
) {
2741 vrrp_log(VRRP_DBG1
, "vrrpd_disable(): %s does not exist", vn
);
2742 return (VRRP_ENOTFOUND
);
2746 * The VR is already disable.
2748 if (!vr
->vvr_conf
.vvc_enabled
) {
2749 vrrp_log(VRRP_DBG1
, "vrrpd_disable(): %s was not enabled", vn
);
2750 return (VRRP_EALREADY
);
2753 vr
->vvr_conf
.vvc_enabled
= _B_FALSE
;
2754 err
= vrrpd_updateconf(&vr
->vvr_conf
, VRRP_CONF_UPDATE
);
2755 if (err
!= VRRP_SUCCESS
) {
2756 vr
->vvr_conf
.vvc_enabled
= _B_TRUE
;
2757 vrrp_log(VRRP_ERR
, "vrrpd_disable(): failed to update "
2758 "configuration for %s", vr
->vvr_conf
.vvc_name
);
2762 vrrpd_disable_vr(vr
, NULL
, _B_FALSE
);
2763 vr
->vvr_vnic
[0] = '\0';
2764 return (VRRP_SUCCESS
);
2768 vrrpd_modify(vrrp_vr_conf_t
*conf
, uint32_t mask
)
2771 vrrp_vr_conf_t savconf
;
2773 boolean_t accept
, set_accept
= _B_FALSE
;
2776 vrrp_log(VRRP_DBG0
, "vrrpd_modify(%s)", conf
->vvc_name
);
2779 return (VRRP_SUCCESS
);
2781 if ((vr
= vrrpd_lookup_vr_by_name(conf
->vvc_name
)) == NULL
) {
2782 vrrp_log(VRRP_DBG1
, "vrrpd_modify(): cannot find the given "
2783 "VR instance: %s", conf
->vvc_name
);
2784 return (VRRP_ENOTFOUND
);
2787 if (mask
& VRRP_CONF_INTERVAL
) {
2788 if (conf
->vvc_adver_int
< VRRP_MAX_ADVER_INT_MIN
||
2789 conf
->vvc_adver_int
> VRRP_MAX_ADVER_INT_MAX
) {
2790 vrrp_log(VRRP_DBG1
, "vrrpd_modify(%s): invalid "
2791 "adver_interval %d", conf
->vvc_name
,
2792 conf
->vvc_adver_int
);
2793 return (VRRP_EINVAL
);
2797 pri
= vr
->vvr_conf
.vvc_pri
;
2798 if (mask
& VRRP_CONF_PRIORITY
) {
2799 if (conf
->vvc_pri
< VRRP_PRI_MIN
||
2800 conf
->vvc_pri
> VRRP_PRI_OWNER
) {
2801 vrrp_log(VRRP_DBG1
, "vrrpd_modify(%s): invalid "
2802 "priority %d", conf
->vvc_name
, conf
->vvc_pri
);
2803 return (VRRP_EINVAL
);
2805 pri
= conf
->vvc_pri
;
2808 accept
= vr
->vvr_conf
.vvc_accept
;
2809 if (mask
& VRRP_CONF_ACCEPT
)
2810 accept
= conf
->vvc_accept
;
2812 if (pri
== VRRP_PRI_OWNER
&& !accept
) {
2813 vrrp_log(VRRP_DBG1
, "vrrpd_modify(%s): accept mode must be "
2814 "true for VRRP address owner", conf
->vvc_name
);
2815 return (VRRP_EINVAL
);
2818 if ((mask
& VRRP_CONF_ACCEPT
) && (vr
->vvr_conf
.vvc_accept
!= accept
)) {
2819 err
= vrrpd_set_noaccept(vr
, !accept
);
2820 if (err
!= VRRP_SUCCESS
) {
2821 vrrp_log(VRRP_ERR
, "vrrpd_modify(%s): access mode "
2822 "updating failed: %s", conf
->vvc_name
,
2826 set_accept
= _B_TRUE
;
2830 * Save the current configuration, so it can be restored if the
2833 (void) memcpy(&savconf
, &vr
->vvr_conf
, sizeof (vrrp_vr_conf_t
));
2834 if (mask
& VRRP_CONF_PREEMPT
)
2835 vr
->vvr_conf
.vvc_preempt
= conf
->vvc_preempt
;
2837 if (mask
& VRRP_CONF_ACCEPT
)
2838 vr
->vvr_conf
.vvc_accept
= accept
;
2840 if (mask
& VRRP_CONF_PRIORITY
)
2841 vr
->vvr_conf
.vvc_pri
= pri
;
2843 if (mask
& VRRP_CONF_INTERVAL
)
2844 vr
->vvr_conf
.vvc_adver_int
= conf
->vvc_adver_int
;
2846 err
= vrrpd_updateconf(&vr
->vvr_conf
, VRRP_CONF_UPDATE
);
2847 if (err
!= VRRP_SUCCESS
) {
2848 vrrp_log(VRRP_ERR
, "vrrpd_modify(%s): configuration update "
2849 "failed: %s", conf
->vvc_name
, vrrp_err2str(err
));
2851 (void) vrrpd_set_noaccept(vr
, accept
);
2852 (void) memcpy(&vr
->vvr_conf
, &savconf
, sizeof (vrrp_vr_conf_t
));
2856 if ((mask
& VRRP_CONF_PRIORITY
) && (vr
->vvr_state
== VRRP_STATE_BACKUP
))
2857 vr
->vvr_timeout
= MASTER_DOWN_INTERVAL_VR(vr
);
2859 if ((mask
& VRRP_CONF_INTERVAL
) && (vr
->vvr_state
== VRRP_STATE_MASTER
))
2860 vr
->vvr_timeout
= conf
->vvc_adver_int
;
2862 return (VRRP_SUCCESS
);
2866 vrrpd_list(vrid_t vrid
, char *ifname
, int af
, vrrp_ret_list_t
*ret
,
2870 char *p
= (char *)ret
+ sizeof (vrrp_ret_list_t
);
2871 size_t size
= (*sizep
) - sizeof (vrrp_ret_list_t
);
2873 vrrp_log(VRRP_DBG0
, "vrrpd_list(%d_%s_%s)", vrid
, ifname
, af_str(af
));
2876 TAILQ_FOREACH(vr
, &vrrp_vr_list
, vvr_next
) {
2877 if (vrid
!= VRRP_VRID_NONE
&& vr
->vvr_conf
.vvc_vrid
!= vrid
)
2880 if (strlen(ifname
) != 0 && strcmp(ifname
,
2881 vr
->vvr_conf
.vvc_link
) == 0) {
2885 if ((af
== AF_INET
|| af
== AF_INET6
) &&
2886 vr
->vvr_conf
.vvc_af
!= af
)
2889 if (size
< VRRP_NAME_MAX
) {
2890 vrrp_log(VRRP_DBG1
, "vrrpd_list(): buffer size too "
2891 "small to hold %d router names", ret
->vrl_cnt
);
2892 *sizep
= sizeof (vrrp_ret_list_t
);
2893 ret
->vrl_err
= VRRP_ETOOSMALL
;
2896 (void) strlcpy(p
, vr
->vvr_conf
.vvc_name
, VRRP_NAME_MAX
);
2897 p
+= (strlen(vr
->vvr_conf
.vvc_name
) + 1);
2899 size
-= VRRP_NAME_MAX
;
2902 *sizep
= sizeof (vrrp_ret_list_t
) + ret
->vrl_cnt
* VRRP_NAME_MAX
;
2903 vrrp_log(VRRP_DBG1
, "vrrpd_list() return %d", ret
->vrl_cnt
);
2904 ret
->vrl_err
= VRRP_SUCCESS
;
2908 vrrpd_query(const char *vn
, vrrp_ret_query_t
*ret
, size_t *sizep
)
2910 vrrp_queryinfo_t
*infop
;
2915 uint32_t vipcnt
= 0;
2916 size_t size
= *sizep
;
2918 vrrp_log(VRRP_DBG1
, "vrrpd_query(%s)", vn
);
2920 if ((vr
= vrrpd_lookup_vr_by_name(vn
)) == NULL
) {
2921 vrrp_log(VRRP_DBG1
, "vrrpd_query(): %s does not exist", vn
);
2922 *sizep
= sizeof (vrrp_ret_query_t
);
2923 ret
->vrq_err
= VRRP_ENOTFOUND
;
2928 * Get the virtual IP list if the router is not in the INIT state.
2930 if (vr
->vvr_state
!= VRRP_STATE_INIT
) {
2932 TAILQ_FOREACH(ip
, &vif
->vvi_iplist
, vip_next
) {
2937 *sizep
= sizeof (vrrp_ret_query_t
);
2938 *sizep
+= (vipcnt
== 0) ? 0 : (vipcnt
- 1) * sizeof (vrrp_addr_t
);
2939 if (*sizep
> size
) {
2940 vrrp_log(VRRP_ERR
, "vrrpd_query(): not enough space to hold "
2941 "%d virtual IPs", vipcnt
);
2942 *sizep
= sizeof (vrrp_ret_query_t
);
2943 ret
->vrq_err
= VRRP_ETOOSMALL
;
2947 (void) gettimeofday(&now
, NULL
);
2950 infop
= &ret
->vrq_qinfo
;
2951 (void) memcpy(&infop
->show_vi
,
2952 &(vr
->vvr_conf
), sizeof (vrrp_vr_conf_t
));
2953 (void) memcpy(&infop
->show_vs
,
2954 &(vr
->vvr_sinfo
), sizeof (vrrp_stateinfo_t
));
2955 (void) strlcpy(infop
->show_va
.va_vnic
, vr
->vvr_vnic
, MAXLINKNAMELEN
);
2956 infop
->show_vt
.vt_since_last_tran
= timeval_to_milli(
2957 timeval_delta(now
, vr
->vvr_sinfo
.vs_st_time
));
2959 if (vr
->vvr_state
== VRRP_STATE_INIT
) {
2960 ret
->vrq_err
= VRRP_SUCCESS
;
2965 TAILQ_FOREACH(ip
, &vif
->vvi_iplist
, vip_next
) {
2966 (void) memcpy(&infop
->show_va
.va_vips
[vipcnt
++],
2967 &ip
->vip_addr
, sizeof (vrrp_addr_t
));
2969 infop
->show_va
.va_vipcnt
= vipcnt
;
2971 (void) memcpy(&infop
->show_va
.va_primary
,
2972 &vr
->vvr_pif
->vvi_pip
->vip_addr
, sizeof (vrrp_addr_t
));
2974 (void) memcpy(&infop
->show_vp
, &(vr
->vvr_peer
), sizeof (vrrp_peer_t
));
2977 * Check whether there is a peer.
2979 if (!VRRPADDR_UNSPECIFIED(vr
->vvr_conf
.vvc_af
,
2980 &(vr
->vvr_peer
.vp_addr
))) {
2981 infop
->show_vt
.vt_since_last_adv
= timeval_to_milli(
2982 timeval_delta(now
, vr
->vvr_peer
.vp_time
));
2985 if (vr
->vvr_state
== VRRP_STATE_BACKUP
) {
2986 infop
->show_vt
.vt_master_down_intv
=
2987 MASTER_DOWN_INTERVAL_VR(vr
);
2990 ret
->vrq_err
= VRRP_SUCCESS
;
2994 * Build the VRRP packet (not including the IP header). Return the
2997 * If zero_pri is set to be B_TRUE, then this is the specical zero-priority
2998 * advertisement which is sent by the Master to indicate that it has been
2999 * stopped participating in VRRP.
3002 vrrpd_build_vrrp(vrrp_vr_t
*vr
, uchar_t
*buf
, int buflen
, boolean_t zero_pri
)
3004 /* LINTED E_BAD_PTR_CAST_ALIGN */
3005 vrrp_pkt_t
*vp
= (vrrp_pkt_t
*)buf
;
3006 /* LINTED E_BAD_PTR_CAST_ALIGN */
3007 struct in_addr
*a4
= (struct in_addr
*)(vp
+ 1);
3008 /* LINTED E_BAD_PTR_CAST_ALIGN */
3009 struct in6_addr
*a6
= (struct in6_addr
*)(vp
+ 1);
3010 vrrp_intf_t
*vif
= vr
->vvr_vif
;
3012 int af
= vif
->vvi_af
;
3013 size_t size
= sizeof (vrrp_pkt_t
);
3014 uint16_t rsvd_adver_int
;
3017 vrrp_log(VRRP_DBG1
, "vrrpd_build_vrrp(%s, %s_priority): intv %d",
3018 vr
->vvr_conf
.vvc_name
, zero_pri
? "zero" : "non-zero",
3019 vr
->vvr_conf
.vvc_adver_int
);
3021 TAILQ_FOREACH(vip
, &vif
->vvi_iplist
, vip_next
) {
3022 if ((size
+= ((af
== AF_INET
) ? sizeof (struct in_addr
) :
3023 sizeof (struct in6_addr
))) > buflen
) {
3024 vrrp_log(VRRP_ERR
, "vrrpd_build_vrrp(%s): buffer size "
3025 "not big enough %d", vr
->vvr_conf
.vvc_name
, size
);
3030 a4
[nip
++] = vip
->vip_addr
.in4
.sin_addr
;
3032 a6
[nip
++] = vip
->vip_addr
.in6
.sin6_addr
;
3036 vrrp_log(VRRP_ERR
, "vrrpd_build_vrrp(%s): no virtual IP "
3037 "address", vr
->vvr_conf
.vvc_name
);
3041 vp
->vp_vers_type
= (VRRP_VERSION
<< 4) | VRRP_PKT_ADVERT
;
3042 vp
->vp_vrid
= vr
->vvr_conf
.vvc_vrid
;
3043 vp
->vp_prio
= zero_pri
? VRRP_PRIO_ZERO
: vr
->vvr_conf
.vvc_pri
;
3045 rsvd_adver_int
= MSEC2CENTISEC(vr
->vvr_conf
.vvc_adver_int
) & 0x0fff;
3046 vp
->vp_rsvd_adver_int
= htons(rsvd_adver_int
);
3050 * Set the checksum to 0 first, then caculate it.
3053 if (af
== AF_INET
) {
3054 vp
->vp_chksum
= vrrp_cksum4(
3055 &vr
->vvr_pif
->vvi_pip
->vip_addr
.in4
.sin_addr
,
3056 &vrrp_muladdr4
.in4
.sin_addr
, size
, vp
);
3058 vp
->vp_chksum
= vrrp_cksum6(
3059 &vr
->vvr_pif
->vvi_pip
->vip_addr
.in6
.sin6_addr
,
3060 &vrrp_muladdr6
.in6
.sin6_addr
, size
, vp
);
3067 * We need to build the IPv4 header on our own.
3070 vrrpd_send_adv_v4(vrrp_vr_t
*vr
, uchar_t
*buf
, size_t len
, boolean_t zero_pri
)
3072 /* LINTED E_BAD_PTR_CAST_ALIGN */
3073 struct ip
*ip
= (struct ip
*)buf
;
3076 vrrp_log(VRRP_DBG1
, "vrrpd_send_adv_v4(%s)", vr
->vvr_conf
.vvc_name
);
3078 if ((plen
= vrrpd_build_vrrp(vr
, buf
+ sizeof (struct ip
),
3079 len
- sizeof (struct ip
), zero_pri
)) == 0) {
3080 return (VRRP_ETOOSMALL
);
3083 ip
->ip_hl
= sizeof (struct ip
) >> 2;
3084 ip
->ip_v
= IPV4_VERSION
;
3086 plen
+= sizeof (struct ip
);
3087 ip
->ip_len
= htons(plen
);
3089 ip
->ip_ttl
= VRRP_IP_TTL
;
3090 ip
->ip_p
= IPPROTO_VRRP
;
3091 ip
->ip_src
= vr
->vvr_pif
->vvi_pip
->vip_addr
.in4
.sin_addr
;
3092 ip
->ip_dst
= vrrp_muladdr4
.in4
.sin_addr
;
3095 * The kernel will set the IP cksum and the IPv4 identification.
3100 if ((len
= sendto(vr
->vvr_vif
->vvi_sockfd
, buf
, plen
, 0,
3101 (const struct sockaddr
*)&vrrp_muladdr4
,
3102 sizeof (struct sockaddr_in
))) != plen
) {
3103 vrrp_log(VRRP_ERR
, "vrrpd_send_adv_v4(): sendto() on "
3104 "(vrid:%d, %s, %s) failed: %s sent:%d expect:%d",
3105 vr
->vvr_conf
.vvc_vrid
, vr
->vvr_vif
->vvi_ifname
,
3106 af_str(vr
->vvr_conf
.vvc_af
), strerror(errno
), len
, plen
);
3110 vrrp_log(VRRP_DBG1
, "vrrpd_send_adv_v4(%s) succeed",
3111 vr
->vvr_conf
.vvc_name
);
3112 return (VRRP_SUCCESS
);
3116 vrrpd_send_adv_v6(vrrp_vr_t
*vr
, uchar_t
*buf
, size_t len
, boolean_t zero_pri
)
3119 size_t hoplimit_space
= 0;
3120 size_t pktinfo_space
= 0;
3121 size_t bufspace
= 0;
3122 struct in6_pktinfo
*pktinfop
;
3123 struct cmsghdr
*cmsgp
;
3124 uchar_t
*cmsg_datap
;
3128 vrrp_log(VRRP_DBG1
, "vrrpd_send_adv_v6(%s)", vr
->vvr_conf
.vvc_name
);
3130 if ((plen
= vrrpd_build_vrrp(vr
, buf
, len
, zero_pri
)) == 0)
3131 return (VRRP_ETOOSMALL
);
3133 msg6
.msg_control
= NULL
;
3134 msg6
.msg_controllen
= 0;
3136 hoplimit_space
= sizeof (int);
3137 bufspace
+= sizeof (struct cmsghdr
) + _MAX_ALIGNMENT
+
3138 hoplimit_space
+ _MAX_ALIGNMENT
;
3140 pktinfo_space
= sizeof (struct in6_pktinfo
);
3141 bufspace
+= sizeof (struct cmsghdr
) + _MAX_ALIGNMENT
+
3142 pktinfo_space
+ _MAX_ALIGNMENT
;
3145 * We need to temporarily set the msg6.msg_controllen to bufspace
3146 * (we will later trim it to actual length used). This is needed because
3147 * CMSG_NXTHDR() uses it to check we have not exceeded the bounds.
3149 bufspace
+= sizeof (struct cmsghdr
);
3150 msg6
.msg_controllen
= bufspace
;
3152 msg6
.msg_control
= (struct cmsghdr
*)malloc(bufspace
);
3153 if (msg6
.msg_control
== NULL
) {
3154 vrrp_log(VRRP_ERR
, "vrrpd_send_adv_v6(%s): memory allocation "
3155 "failed: %s", vr
->vvr_conf
.vvc_name
, strerror(errno
));
3156 return (VRRP_ENOMEM
);
3159 cmsgp
= CMSG_FIRSTHDR(&msg6
);
3161 cmsgp
->cmsg_level
= IPPROTO_IPV6
;
3162 cmsgp
->cmsg_type
= IPV6_HOPLIMIT
;
3163 cmsg_datap
= CMSG_DATA(cmsgp
);
3165 *(int *)cmsg_datap
= VRRP_IP_TTL
;
3166 cmsgp
->cmsg_len
= cmsg_datap
+ hoplimit_space
- (uchar_t
*)cmsgp
;
3167 cmsgp
= CMSG_NXTHDR(&msg6
, cmsgp
);
3169 cmsgp
->cmsg_level
= IPPROTO_IPV6
;
3170 cmsgp
->cmsg_type
= IPV6_PKTINFO
;
3171 cmsg_datap
= CMSG_DATA(cmsgp
);
3174 pktinfop
= (struct in6_pktinfo
*)cmsg_datap
;
3176 * We don't know if pktinfop->ipi6_addr is aligned properly,
3177 * therefore let's use bcopy, instead of assignment.
3179 (void) bcopy(&vr
->vvr_pif
->vvi_pip
->vip_addr
.in6
.sin6_addr
,
3180 &pktinfop
->ipi6_addr
, sizeof (struct in6_addr
));
3183 * We can assume pktinfop->ipi6_ifindex is 32 bit aligned.
3185 pktinfop
->ipi6_ifindex
= vr
->vvr_vif
->vvi_ifindex
;
3186 cmsgp
->cmsg_len
= cmsg_datap
+ pktinfo_space
- (uchar_t
*)cmsgp
;
3187 cmsgp
= CMSG_NXTHDR(&msg6
, cmsgp
);
3188 msg6
.msg_controllen
= (char *)cmsgp
- (char *)msg6
.msg_control
;
3190 msg6
.msg_name
= &vrrp_muladdr6
;
3191 msg6
.msg_namelen
= sizeof (struct sockaddr_in6
);
3195 msg6
.msg_iov
= &iov
;
3196 msg6
.msg_iovlen
= 1;
3198 if ((len
= sendmsg(vr
->vvr_vif
->vvi_sockfd
,
3199 (const struct msghdr
*)&msg6
, 0)) != plen
) {
3200 vrrp_log(VRRP_ERR
, "vrrpd_send_adv_v6(%s): sendmsg() failed: "
3201 "%s expect %d sent %d", vr
->vvr_conf
.vvc_name
,
3202 strerror(errno
), plen
, len
);
3203 (void) free(msg6
.msg_control
);
3207 vrrp_log(VRRP_DBG1
, "vrrpd_send_adv_v6(%s) succeed",
3208 vr
->vvr_conf
.vvc_name
);
3209 (void) free(msg6
.msg_control
);
3210 return (VRRP_SUCCESS
);
3214 * Send the VRRP advertisement packets.
3217 vrrpd_send_adv(vrrp_vr_t
*vr
, boolean_t zero_pri
)
3219 uint64_t buf
[(IP_MAXPACKET
+ 1)/8];
3221 vrrp_log(VRRP_DBG1
, "vrrpd_send_adv(%s, %s_priority)",
3222 vr
->vvr_conf
.vvc_name
, zero_pri
? "zero" : "non_zero");
3224 assert(vr
->vvr_pif
->vvi_pip
!= NULL
);
3226 if (vr
->vvr_pif
->vvi_pip
== NULL
) {
3227 vrrp_log(VRRP_DBG0
, "vrrpd_send_adv(%s): no primary IP "
3228 "address", vr
->vvr_conf
.vvc_name
);
3229 return (VRRP_EINVAL
);
3232 if (vr
->vvr_conf
.vvc_af
== AF_INET
) {
3233 return (vrrpd_send_adv_v4(vr
, (uchar_t
*)buf
,
3234 sizeof (buf
), zero_pri
));
3236 return (vrrpd_send_adv_v6(vr
, (uchar_t
*)buf
,
3237 sizeof (buf
), zero_pri
));
3242 vrrpd_process_adv(vrrp_vr_t
*vr
, vrrp_addr_t
*from
, vrrp_pkt_t
*vp
)
3244 vrrp_vr_conf_t
*conf
= &vr
->vvr_conf
;
3245 char peer
[INET6_ADDRSTRLEN
];
3246 char local
[INET6_ADDRSTRLEN
];
3248 uint16_t peer_adver_int
;
3250 /* LINTED E_CONSTANT_CONDITION */
3251 VRRPADDR2STR(vr
->vvr_conf
.vvc_af
, from
, peer
, INET6_ADDRSTRLEN
,
3253 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s) from %s", conf
->vvc_name
,
3256 if (vr
->vvr_state
<= VRRP_STATE_INIT
) {
3257 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s): state: %s, not "
3258 "ready", conf
->vvc_name
, vrrp_state2str(vr
->vvr_state
));
3262 peer_adver_int
= CENTISEC2MSEC(ntohs(vp
->vp_rsvd_adver_int
) & 0x0fff);
3264 /* LINTED E_CONSTANT_CONDITION */
3265 VRRPADDR2STR(vr
->vvr_pif
->vvi_af
, &vr
->vvr_pif
->vvi_pip
->vip_addr
,
3266 local
, INET6_ADDRSTRLEN
, _B_FALSE
);
3267 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s): local/state/pri"
3268 "(%s/%s/%d) peer/pri/intv(%s/%d/%d)", conf
->vvc_name
, local
,
3269 vrrp_state2str(vr
->vvr_state
), conf
->vvc_pri
, peer
,
3270 vp
->vp_prio
, peer_adver_int
);
3272 addr_cmp
= ipaddr_cmp(vr
->vvr_pif
->vvi_af
, from
,
3273 &vr
->vvr_pif
->vvi_pip
->vip_addr
);
3274 if (addr_cmp
== 0) {
3275 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s): local message",
3278 } else if (conf
->vvc_pri
== vp
->vp_prio
) {
3279 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s): peer IP %s is %s"
3280 " than the local IP %s", conf
->vvc_name
, peer
,
3281 addr_cmp
> 0 ? "greater" : "less", local
);
3284 if (conf
->vvc_pri
== 255) {
3285 vrrp_log(VRRP_ERR
, "vrrpd_process_adv(%s): virtual address "
3286 "owner received advertisement from %s", conf
->vvc_name
,
3291 (void) gettimeofday(&vr
->vvr_peer_time
, NULL
);
3292 (void) memcpy(&vr
->vvr_peer_addr
, from
, sizeof (vrrp_addr_t
));
3293 vr
->vvr_peer_prio
= vp
->vp_prio
;
3294 vr
->vvr_peer_adver_int
= peer_adver_int
;
3296 if (vr
->vvr_state
== VRRP_STATE_BACKUP
) {
3297 vr
->vvr_master_adver_int
= vr
->vvr_peer_adver_int
;
3298 if ((vp
->vp_prio
== VRRP_PRIO_ZERO
) ||
3299 (conf
->vvc_preempt
== _B_FALSE
||
3300 vp
->vp_prio
>= conf
->vvc_pri
)) {
3301 (void) iu_cancel_timer(vrrpd_timerq
,
3302 vr
->vvr_timer_id
, NULL
);
3303 if (vp
->vp_prio
== VRRP_PRIO_ZERO
) {
3304 /* the master stops participating in VRRP */
3305 vr
->vvr_timeout
= SKEW_TIME_VR(vr
);
3307 vr
->vvr_timeout
= MASTER_DOWN_INTERVAL_VR(vr
);
3309 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(
3310 vrrpd_timerq
, vr
->vvr_timeout
, vrrp_b2m_timeout
,
3312 vrrp_log(VRRP_ERR
, "vrrpd_process_adv(%s): "
3313 "start vrrp_b2m_timeout(%d) failed",
3314 conf
->vvc_name
, vr
->vvr_timeout
);
3316 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s): "
3317 "start vrrp_b2m_timeout(%d)",
3318 conf
->vvc_name
, vr
->vvr_timeout
);
3321 } else if (vr
->vvr_state
== VRRP_STATE_MASTER
) {
3322 if (vp
->vp_prio
== VRRP_PRIO_ZERO
) {
3323 (void) vrrpd_send_adv(vr
, _B_FALSE
);
3324 (void) iu_cancel_timer(vrrpd_timerq
,
3325 vr
->vvr_timer_id
, NULL
);
3326 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(
3327 vrrpd_timerq
, vr
->vvr_timeout
, vrrp_adv_timeout
,
3329 vrrp_log(VRRP_ERR
, "vrrpd_process_adv(%s): "
3330 "start vrrp_adv_timeout(%d) failed",
3331 conf
->vvc_name
, vr
->vvr_timeout
);
3333 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv(%s): "
3334 "start vrrp_adv_timeout(%d)",
3335 conf
->vvc_name
, vr
->vvr_timeout
);
3337 } else if (vp
->vp_prio
> conf
->vvc_pri
||
3338 (vp
->vp_prio
== conf
->vvc_pri
&& addr_cmp
> 0)) {
3339 (void) vrrpd_state_m2b(vr
);
3347 vrrpd_process_vrrp(vrrp_intf_t
*pif
, vrrp_pkt_t
*vp
, size_t len
,
3352 uint16_t saved_cksum
, cksum
;
3353 char peer
[INET6_ADDRSTRLEN
];
3355 /* LINTED E_CONSTANT_CONDITION */
3356 VRRPADDR2STR(pif
->vvi_af
, from
, peer
, INET6_ADDRSTRLEN
, _B_FALSE
);
3357 vrrp_log(VRRP_DBG0
, "vrrpd_process_vrrp(%s) from %s", pif
->vvi_ifname
,
3360 if (len
< sizeof (vrrp_pkt_t
)) {
3361 vrrp_log(VRRP_ERR
, "vrrpd_process_vrrp(%s): invalid message "
3363 return (VRRP_EINVAL
);
3367 * Verify: VRRP version number and packet type.
3369 vers_type
= ((vp
->vp_vers_type
& VRRP_VER_MASK
) >> 4);
3370 if (vers_type
!= VRRP_VERSION
) {
3371 vrrp_log(VRRP_ERR
, "vrrpd_process_vrrp(%s) unsupported "
3372 "version %d", pif
->vvi_ifname
, vers_type
);
3373 return (VRRP_EINVAL
);
3376 if (vp
->vp_ipnum
== 0) {
3377 vrrp_log(VRRP_ERR
, "vrrpd_process_vrrp(%s): zero IPvX count",
3379 return (VRRP_EINVAL
);
3382 if (len
- sizeof (vrrp_pkt_t
) !=
3383 vp
->vp_ipnum
* (pif
->vvi_af
== AF_INET
? sizeof (struct in_addr
) :
3384 sizeof (struct in6_addr
))) {
3385 vrrp_log(VRRP_ERR
, "vrrpd_process_vrrp(%s): invalid IPvX count"
3386 " %d", pif
->vvi_ifname
, vp
->vp_ipnum
);
3387 return (VRRP_EINVAL
);
3390 vers_type
= (vp
->vp_vers_type
& VRRP_TYPE_MASK
);
3393 * verify: VRRP checksum. Note that vrrp_cksum returns network byte
3394 * order checksum value;
3396 saved_cksum
= vp
->vp_chksum
;
3398 if (pif
->vvi_af
== AF_INET
) {
3399 cksum
= vrrp_cksum4(&from
->in4
.sin_addr
,
3400 &vrrp_muladdr4
.in4
.sin_addr
, len
, vp
);
3402 cksum
= vrrp_cksum6(&from
->in6
.sin6_addr
,
3403 &vrrp_muladdr6
.in6
.sin6_addr
, len
, vp
);
3406 if (cksum
!= saved_cksum
) {
3407 vrrp_log(VRRP_ERR
, "vrrpd_process_vrrp(%s) invalid "
3408 "checksum: expected/real(0x%x/0x%x)", pif
->vvi_ifname
,
3409 cksum
, saved_cksum
);
3410 return (VRRP_EINVAL
);
3413 if ((vr
= vrrpd_lookup_vr_by_vrid(pif
->vvi_ifname
, vp
->vp_vrid
,
3414 pif
->vvi_af
)) != NULL
&& vers_type
== VRRP_PKT_ADVERT
) {
3415 vrrpd_process_adv(vr
, from
, vp
);
3417 vrrp_log(VRRP_DBG1
, "vrrpd_process_vrrp(%s) VRID(%d/%s) "
3418 "not configured", pif
->vvi_ifname
, vp
->vp_vrid
,
3419 af_str(pif
->vvi_af
));
3421 return (VRRP_SUCCESS
);
3425 * IPv4 socket, the IPv4 header is included.
3428 vrrpd_process_adv_v4(vrrp_intf_t
*pif
, struct msghdr
*msgp
, size_t len
)
3430 char abuf
[INET6_ADDRSTRLEN
];
3433 vrrp_log(VRRP_DBG0
, "vrrpd_process_adv_v4(%s, %d)",
3434 pif
->vvi_ifname
, len
);
3436 ip
= (struct ip
*)msgp
->msg_iov
->iov_base
;
3439 if (len
< sizeof (struct ip
) || len
< ntohs(ip
->ip_len
)) {
3440 vrrp_log(VRRP_ERR
, "vrrpd_process_adv_v4(%s): invalid length "
3441 "%d", pif
->vvi_ifname
, len
);
3442 return (VRRP_EINVAL
);
3445 assert(ip
->ip_v
== IPV4_VERSION
);
3446 assert(ip
->ip_p
== IPPROTO_VRRP
);
3447 assert(msgp
->msg_namelen
== sizeof (struct sockaddr_in
));
3449 if (vrrp_muladdr4
.in4
.sin_addr
.s_addr
!= ip
->ip_dst
.s_addr
) {
3450 vrrp_log(VRRP_ERR
, "vrrpd_process_adv_v4(%s): invalid "
3451 "destination %s", pif
->vvi_ifname
,
3452 inet_ntop(pif
->vvi_af
, &(ip
->ip_dst
), abuf
, sizeof (abuf
)));
3453 return (VRRP_EINVAL
);
3456 if (ip
->ip_ttl
!= VRRP_IP_TTL
) {
3457 vrrp_log(VRRP_ERR
, "vrrpd_process_adv_v4(%s): invalid "
3458 "ttl %d", pif
->vvi_ifname
, ip
->ip_ttl
);
3459 return (VRRP_EINVAL
);
3463 * Note that the ip_len contains only the IP payload length.
3465 return (vrrpd_process_vrrp(pif
,
3466 /* LINTED E_BAD_PTR_CAST_ALIGN */
3467 (vrrp_pkt_t
*)((char *)ip
+ ip
->ip_hl
* 4), ntohs(ip
->ip_len
),
3468 (vrrp_addr_t
*)msgp
->msg_name
));
3472 * IPv6 socket, check the ancillary_data.
3475 vrrpd_process_adv_v6(vrrp_intf_t
*pif
, struct msghdr
*msgp
, size_t len
)
3477 struct cmsghdr
*cmsgp
;
3478 uchar_t
*cmsg_datap
;
3479 struct in6_pktinfo
*pktinfop
;
3480 char abuf
[INET6_ADDRSTRLEN
];
3483 vrrp_log(VRRP_DBG1
, "vrrpd_process_adv_v6(%s, %d)",
3484 pif
->vvi_ifname
, len
);
3487 if (len
< sizeof (vrrp_pkt_t
)) {
3488 vrrp_log(VRRP_ERR
, "vrrpd_process_adv_v6(%s): invalid length "
3489 "%d", pif
->vvi_ifname
, len
);
3490 return (VRRP_EINVAL
);
3493 assert(msgp
->msg_namelen
== sizeof (struct sockaddr_in6
));
3495 for (cmsgp
= CMSG_FIRSTHDR(msgp
); cmsgp
!= NULL
;
3496 cmsgp
= CMSG_NXTHDR(msgp
, cmsgp
)) {
3497 assert(cmsgp
->cmsg_level
== IPPROTO_IPV6
);
3498 cmsg_datap
= CMSG_DATA(cmsgp
);
3500 switch (cmsgp
->cmsg_type
) {
3502 /* LINTED E_BAD_PTR_CAST_ALIGN */
3503 if ((ttl
= *(int *)cmsg_datap
) == VRRP_IP_TTL
)
3506 vrrp_log(VRRP_ERR
, "vrrpd_process_adv_v4(%s): invalid "
3507 "ttl %d", pif
->vvi_ifname
, ttl
);
3508 return (VRRP_EINVAL
);
3510 /* LINTED E_BAD_PTR_CAST_ALIGN */
3511 pktinfop
= (struct in6_pktinfo
*)cmsg_datap
;
3512 if (IN6_ARE_ADDR_EQUAL(&pktinfop
->ipi6_addr
,
3513 &vrrp_muladdr6
.in6
.sin6_addr
)) {
3517 vrrp_log(VRRP_ERR
, "vrrpd_process_adv_v4(%s): invalid "
3518 "destination %s", pif
->vvi_ifname
,
3519 inet_ntop(pif
->vvi_af
, &pktinfop
->ipi6_addr
, abuf
,
3521 return (VRRP_EINVAL
);
3525 return (vrrpd_process_vrrp(pif
, msgp
->msg_iov
->iov_base
, len
,
3531 vrrpd_sock_handler(iu_eh_t
*eh
, int s
, short events
, iu_event_id_t id
,
3536 uint64_t buf
[(IP_MAXPACKET
+ 1)/8];
3537 uint64_t ancillary_data
[(IP_MAXPACKET
+ 1)/8];
3538 vrrp_intf_t
*pif
= arg
;
3539 int af
= pif
->vvi_af
;
3543 vrrp_log(VRRP_DBG1
, "vrrpd_sock_handler(%s)", pif
->vvi_ifname
);
3545 msg
.msg_name
= (struct sockaddr
*)&from
;
3546 msg
.msg_namelen
= (af
== AF_INET
) ? sizeof (struct sockaddr_in
) :
3547 sizeof (struct sockaddr_in6
);
3548 iov
.iov_base
= (char *)buf
;
3549 iov
.iov_len
= sizeof (buf
);
3552 msg
.msg_control
= ancillary_data
;
3553 msg
.msg_controllen
= sizeof (ancillary_data
);
3555 if ((len
= recvmsg(s
, &msg
, 0)) == -1) {
3556 vrrp_log(VRRP_ERR
, "vrrpd_sock_handler() recvmsg(%s) "
3557 "failed: %s", pif
->vvi_ifname
, strerror(errno
));
3562 * Ignore packets whose control buffers that don't fit
3564 if (msg
.msg_flags
& (MSG_TRUNC
|MSG_CTRUNC
)) {
3565 vrrp_log(VRRP_ERR
, "vrrpd_sock_handler() %s buffer not "
3566 "big enough", pif
->vvi_ifname
);
3571 (void) vrrpd_process_adv_v4(pif
, &msg
, len
);
3573 (void) vrrpd_process_adv_v6(pif
, &msg
, len
);
3577 * Create the socket which is used to receive VRRP packets. Virtual routers
3578 * that configured on the same physical interface share the same socket.
3581 vrrpd_init_rxsock(vrrp_vr_t
*vr
)
3583 vrrp_intf_t
*pif
; /* Physical interface used to recv packets */
3584 struct group_req greq
;
3585 struct sockaddr_storage
*muladdr
;
3588 vrrp_err_t err
= VRRP_SUCCESS
;
3590 vrrp_log(VRRP_DBG1
, "vrrpd_init_rxsock(%s)", vr
->vvr_conf
.vvc_name
);
3593 * The RX sockets may already been initialized.
3595 if ((pif
= vr
->vvr_pif
) != NULL
) {
3596 vrrp_log(VRRP_DBG1
, "vrrpd_init_rxsock(%s) already done on %s",
3597 vr
->vvr_conf
.vvc_name
, pif
->vvi_ifname
);
3598 assert(pif
->vvi_sockfd
!= -1);
3599 return (VRRP_SUCCESS
);
3603 * If no IP addresses configured on the primary interface,
3606 af
= vr
->vvr_conf
.vvc_af
;
3607 pif
= vrrpd_lookup_if(vr
->vvr_conf
.vvc_link
, af
);
3609 vrrp_log(VRRP_DBG1
, "vrrpd_init_rxsock(%s): no IP address "
3610 "over %s/%s", vr
->vvr_conf
.vvc_name
,
3611 vr
->vvr_conf
.vvc_link
, af_str(af
));
3612 return (VRRP_ENOPRIM
);
3615 proto
= (af
== AF_INET
? IPPROTO_IP
: IPPROTO_IPV6
);
3616 if (pif
->vvi_nvr
++ == 0) {
3617 assert(pif
->vvi_sockfd
< 0);
3618 pif
->vvi_sockfd
= socket(af
, SOCK_RAW
, IPPROTO_VRRP
);
3619 if (pif
->vvi_sockfd
< 0) {
3620 vrrp_log(VRRP_ERR
, "vrrpd_init_rxsock(%s): socket() "
3621 "failed %s", vr
->vvr_conf
.vvc_name
,
3628 * Join the multicast group to receive VRRP packets.
3630 if (af
== AF_INET
) {
3631 muladdr
= (struct sockaddr_storage
*)
3632 (void *)&vrrp_muladdr4
;
3634 muladdr
= (struct sockaddr_storage
*)
3635 (void *)&vrrp_muladdr6
;
3638 greq
.gr_interface
= pif
->vvi_ifindex
;
3639 (void) memcpy(&greq
.gr_group
, muladdr
,
3640 sizeof (struct sockaddr_storage
));
3641 if (setsockopt(pif
->vvi_sockfd
, proto
, MCAST_JOIN_GROUP
, &greq
,
3642 sizeof (struct group_req
)) < 0) {
3643 vrrp_log(VRRP_ERR
, "vrrpd_init_rxsock(%s): "
3644 "join_group(%d) failed: %s", vr
->vvr_conf
.vvc_name
,
3645 pif
->vvi_ifindex
, strerror(errno
));
3649 vrrp_log(VRRP_DBG1
, "vrrpd_init_rxsock(%s): "
3650 "join_group(%d) succeeded", vr
->vvr_conf
.vvc_name
,
3655 * Unlike IPv4, the IPv6 raw socket does not pass the IP header
3656 * when a packet is received. Call setsockopt() to receive such
3659 if (af
== AF_INET6
) {
3661 * Enable receipt of destination address info
3663 if (setsockopt(pif
->vvi_sockfd
, proto
, IPV6_RECVPKTINFO
,
3664 (char *)&on
, sizeof (on
)) < 0) {
3665 vrrp_log(VRRP_ERR
, "vrrpd_init_rxsock(%s): "
3666 "enable recvpktinfo failed: %s",
3667 vr
->vvr_conf
.vvc_name
, strerror(errno
));
3673 * Enable receipt of hoplimit info
3675 if (setsockopt(pif
->vvi_sockfd
, proto
,
3676 IPV6_RECVHOPLIMIT
, (char *)&on
, sizeof (on
)) < 0) {
3677 vrrp_log(VRRP_ERR
, "vrrpd_init_rxsock(%s): "
3678 "enable recvhoplimit failed: %s",
3679 vr
->vvr_conf
.vvc_name
, strerror(errno
));
3685 if ((pif
->vvi_eid
= iu_register_event(vrrpd_eh
,
3686 pif
->vvi_sockfd
, POLLIN
, vrrpd_sock_handler
, pif
)) == -1) {
3687 vrrp_log(VRRP_ERR
, "vrrpd_init_rxsock(%s): "
3688 "iu_register_event() failed",
3689 vr
->vvr_conf
.vvc_name
);
3694 vrrp_log(VRRP_DBG1
, "vrrpd_init_rxsock(%s) over %s already "
3695 "done %d", vr
->vvr_conf
.vvc_name
, pif
->vvi_ifname
,
3697 assert(IS_PRIMARY_INTF(pif
));
3702 if (err
!= VRRP_SUCCESS
)
3703 vrrpd_fini_rxsock(vr
);
3709 * Delete the socket which is used to receive VRRP packets for the given
3710 * VRRP router. Since all virtual routers that configured on the same
3711 * physical interface share the same socket, the socket is only closed
3712 * when the last VRRP router share this socket is deleted.
3715 vrrpd_fini_rxsock(vrrp_vr_t
*vr
)
3717 vrrp_intf_t
*pif
= vr
->vvr_pif
;
3719 vrrp_log(VRRP_DBG1
, "vrrpd_fini_rxsock(%s)", vr
->vvr_conf
.vvc_name
);
3724 if (--pif
->vvi_nvr
== 0) {
3725 vrrp_log(VRRP_DBG1
, "vrrpd_fini_rxsock(%s) over %s",
3726 vr
->vvr_conf
.vvc_name
, pif
->vvi_ifname
);
3727 (void) iu_unregister_event(vrrpd_eh
, pif
->vvi_eid
, NULL
);
3728 (void) close(pif
->vvi_sockfd
);
3729 pif
->vvi_pip
= NULL
;
3730 pif
->vvi_sockfd
= -1;
3733 vrrp_log(VRRP_DBG1
, "vrrpd_fini_rxsock(%s) over %s %d",
3734 vr
->vvr_conf
.vvc_name
, pif
->vvi_ifname
, pif
->vvi_nvr
);
3740 * Create the socket which is used to send VRRP packets. Further, set
3741 * the IFF_NOACCEPT flag based on the VRRP router's accept mode.
3744 vrrpd_init_txsock(vrrp_vr_t
*vr
)
3750 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock(%s)", vr
->vvr_conf
.vvc_name
);
3752 if (vr
->vvr_vif
!= NULL
) {
3753 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock(%s) already done on %s",
3754 vr
->vvr_conf
.vvc_name
, vr
->vvr_vif
->vvi_ifname
);
3755 return (VRRP_SUCCESS
);
3758 af
= vr
->vvr_conf
.vvc_af
;
3759 if ((vif
= vrrpd_lookup_if(vr
->vvr_vnic
, af
)) == NULL
) {
3760 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock(%s) no IP address over "
3761 "%s/%s", vr
->vvr_conf
.vvc_name
, vr
->vvr_vnic
, af_str(af
));
3762 return (VRRP_ENOVIRT
);
3766 if (vr
->vvr_conf
.vvc_af
== AF_INET
)
3767 err
= vrrpd_init_txsock_v4(vr
);
3769 err
= vrrpd_init_txsock_v6(vr
);
3771 if (err
!= VRRP_SUCCESS
)
3775 * The interface should start with IFF_NOACCEPT flag not set, only
3776 * call this function when the VRRP router requires IFF_NOACCEPT.
3778 if (!vr
->vvr_conf
.vvc_accept
)
3779 err
= vrrpd_set_noaccept(vr
, _B_TRUE
);
3782 if (err
!= VRRP_SUCCESS
) {
3783 (void) close(vif
->vvi_sockfd
);
3784 vif
->vvi_sockfd
= -1;
3792 * Create the IPv4 socket which is used to send VRRP packets. Note that
3793 * the destination MAC address of VRRP advertisement must be the virtual
3794 * MAC address, so we specify the output interface to be the specific VNIC.
3797 vrrpd_init_txsock_v4(vrrp_vr_t
*vr
)
3799 vrrp_intf_t
*vif
; /* VNIC interface used to send packets */
3800 vrrp_ip_t
*vip
; /* The first IP over the VNIC */
3803 vrrp_err_t err
= VRRP_SUCCESS
;
3804 char abuf
[INET6_ADDRSTRLEN
];
3807 assert(vr
->vvr_conf
.vvc_af
== AF_INET
);
3808 assert(vif
!= NULL
);
3810 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock_v4(%s) over %s",
3811 vr
->vvr_conf
.vvc_name
, vif
->vvi_ifname
);
3813 if (vif
->vvi_sockfd
!= -1) {
3814 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock_v4(%s) already done "
3815 "over %s", vr
->vvr_conf
.vvc_name
, vif
->vvi_ifname
);
3816 return (VRRP_SUCCESS
);
3819 vif
->vvi_sockfd
= socket(vif
->vvi_af
, SOCK_RAW
, IPPROTO_VRRP
);
3820 if (vif
->vvi_sockfd
< 0) {
3821 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v4(%s): socket() "
3822 "failed: %s", vr
->vvr_conf
.vvc_name
, strerror(errno
));
3828 * Include the IP header, so that we can specify the IP address/ttl.
3830 if (setsockopt(vif
->vvi_sockfd
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
3832 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v4(%s): ip_hdrincl "
3833 "failed: %s", vr
->vvr_conf
.vvc_name
, strerror(errno
));
3839 * Disable multicast loopback.
3841 if (setsockopt(vif
->vvi_sockfd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &off
,
3842 sizeof (char)) == -1) {
3843 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v4(%s): disable "
3844 "multicast_loop failed: %s", vr
->vvr_conf
.vvc_name
,
3850 vip
= TAILQ_FIRST(&vif
->vvi_iplist
);
3851 /* LINTED E_CONSTANT_CONDITION */
3852 VRRPADDR2STR(vif
->vvi_af
, &vip
->vip_addr
, abuf
, INET6_ADDRSTRLEN
,
3856 * Set the output interface to send the VRRP packet.
3858 if (setsockopt(vif
->vvi_sockfd
, IPPROTO_IP
, IP_MULTICAST_IF
,
3859 &vip
->vip_addr
.in4
.sin_addr
, sizeof (struct in_addr
)) < 0) {
3860 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v4(%s): multcast_if(%s) "
3861 "failed: %s", vr
->vvr_conf
.vvc_name
, abuf
, strerror(errno
));
3864 vrrp_log(VRRP_DBG0
, "vrrpd_init_txsock_v4(%s): multcast_if(%s) "
3865 "succeed", vr
->vvr_conf
.vvc_name
, abuf
);
3869 if (err
!= VRRP_SUCCESS
) {
3870 (void) close(vif
->vvi_sockfd
);
3871 vif
->vvi_sockfd
= -1;
3878 * Create the IPv6 socket which is used to send VRRP packets. Note that
3879 * the destination must be the virtual MAC address, so we specify the output
3880 * interface to be the specific VNIC.
3883 vrrpd_init_txsock_v6(vrrp_vr_t
*vr
)
3885 vrrp_intf_t
*vif
; /* VNIC interface used to send packets */
3886 int off
= 0, ttl
= VRRP_IP_TTL
;
3887 vrrp_err_t err
= VRRP_SUCCESS
;
3890 assert(vr
->vvr_conf
.vvc_af
== AF_INET6
);
3891 assert(vif
!= NULL
);
3893 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock_v6(%s) over %s",
3894 vr
->vvr_conf
.vvc_name
, vif
->vvi_ifname
);
3896 if (vif
->vvi_sockfd
!= -1) {
3897 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock_v6(%s) already done "
3898 "over %s", vr
->vvr_conf
.vvc_name
, vif
->vvi_ifname
);
3899 return (VRRP_SUCCESS
);
3902 vif
->vvi_sockfd
= socket(vif
->vvi_af
, SOCK_RAW
, IPPROTO_VRRP
);
3903 if (vif
->vvi_sockfd
< 0) {
3904 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v6(%s): socket() "
3905 "failed: %s", vr
->vvr_conf
.vvc_name
, strerror(errno
));
3911 * Disable multicast loopback.
3913 if (setsockopt(vif
->vvi_sockfd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
3914 &off
, sizeof (int)) == -1) {
3915 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v6(%s): disable "
3916 "multicast_loop failed: %s", vr
->vvr_conf
.vvc_name
,
3923 * Set the multicast TTL.
3925 if (setsockopt(vif
->vvi_sockfd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
3926 &ttl
, sizeof (int)) == -1) {
3927 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v6(%s): enable "
3928 "multicast_hops %d failed: %s", vr
->vvr_conf
.vvc_name
,
3929 ttl
, strerror(errno
));
3935 * Set the output interface to send the VRRP packet.
3937 if (setsockopt(vif
->vvi_sockfd
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
3938 &vif
->vvi_ifindex
, sizeof (uint32_t)) < 0) {
3939 vrrp_log(VRRP_ERR
, "vrrpd_init_txsock_v6(%s): multicast_if(%d) "
3940 "failed: %s", vr
->vvr_conf
.vvc_name
, vif
->vvi_ifindex
,
3944 vrrp_log(VRRP_DBG1
, "vrrpd_init_txsock_v6(%s): multicast_if(%d)"
3945 " succeed", vr
->vvr_conf
.vvc_name
, vif
->vvi_ifindex
);
3949 if (err
!= VRRP_SUCCESS
) {
3950 (void) close(vif
->vvi_sockfd
);
3951 vif
->vvi_sockfd
= -1;
3958 * Delete the socket which is used to send VRRP packets. Further, clear
3959 * the IFF_NOACCEPT flag based on the VRRP router's accept mode.
3962 vrrpd_fini_txsock(vrrp_vr_t
*vr
)
3964 vrrp_intf_t
*vif
= vr
->vvr_vif
;
3966 vrrp_log(VRRP_DBG1
, "vrrpd_fini_txsock(%s)", vr
->vvr_conf
.vvc_name
);
3969 if (!vr
->vvr_conf
.vvc_accept
)
3970 (void) vrrpd_set_noaccept(vr
, _B_FALSE
);
3971 (void) close(vif
->vvi_sockfd
);
3972 vif
->vvi_sockfd
= -1;
3978 * Given the the pseudo header cksum value (sum), caculate the cksum with
3979 * the rest of VRRP packet.
3982 in_cksum(int sum
, uint16_t plen
, void *p
)
3987 uint16_t odd_byte
= 0;
3996 /* mop up an odd byte, if necessary */
3998 *(uchar_t
*)(&odd_byte
) = *(uchar_t
*)w
;
4003 * add back carry outs from top 16 bits to low 16 bits
4005 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
4006 sum
+= (sum
>> 16); /* add carry */
4007 answer
= ~sum
; /* truncate to 16 bits */
4008 return (answer
== 0 ? ~0 : answer
);
4011 /* Pseudo header for v4 */
4013 struct in_addr ph4_src
;
4014 struct in_addr ph4_dst
;
4015 uint8_t ph4_zero
; /* always zero */
4016 uint8_t ph4_protocol
; /* protocol used, IPPROTO_VRRP */
4017 uint16_t ph4_len
; /* VRRP payload len */
4021 * Checksum routine for VRRP checksum. Note that plen is the upper-layer
4022 * packet length (in the host byte order), and both IP source and destination
4023 * addresses are in the network byte order.
4026 vrrp_cksum4(struct in_addr
*src
, struct in_addr
*dst
, uint16_t plen
,
4037 ph4
.ph4_protocol
= IPPROTO_VRRP
;
4038 ph4
.ph4_len
= htons(plen
);
4041 * Our algorithm is simple, using a 32 bit accumulator (sum),
4042 * we add sequential 16 bit words to it, and at the end, fold
4043 * back all the carry bits from the top 16 bits into the lower
4046 nleft
= sizeof (struct pshv4
);
4047 w
= (uint16_t *)&ph4
;
4053 return (in_cksum(sum
, plen
, vp
));
4056 /* Pseudo header for v6 */
4058 struct in6_addr ph6_src
;
4059 struct in6_addr ph6_dst
;
4060 uint32_t ph6_len
; /* VRRP payload len */
4061 uint32_t ph6_zero
: 24,
4062 ph6_protocol
: 8; /* protocol used, IPPROTO_VRRP */
4066 * Checksum routine for VRRP checksum. Note that plen is the upper-layer
4067 * packet length (in the host byte order), and both IP source and destination
4068 * addresses are in the network byte order.
4071 vrrp_cksum6(struct in6_addr
*src
, struct in6_addr
*dst
, uint16_t plen
,
4082 ph6
.ph6_protocol
= IPPROTO_VRRP
;
4083 ph6
.ph6_len
= htonl((uint32_t)plen
);
4086 * Our algorithm is simple, using a 32 bit accumulator (sum),
4087 * we add sequential 16 bit words to it, and at the end, fold
4088 * back all the carry bits from the top 16 bits into the lower
4091 nleft
= sizeof (struct pshv6
);
4092 w
= (uint16_t *)&ph6
;
4098 return (in_cksum(sum
, plen
, vp
));
4102 vrrpd_state_i2m(vrrp_vr_t
*vr
)
4106 vrrp_log(VRRP_DBG1
, "vrrpd_state_i2m(%s)", vr
->vvr_conf
.vvc_name
);
4108 vrrpd_state_trans(VRRP_STATE_INIT
, VRRP_STATE_MASTER
, vr
);
4109 if ((err
= vrrpd_virtualip_update(vr
, _B_FALSE
)) != VRRP_SUCCESS
)
4112 (void) vrrpd_send_adv(vr
, _B_FALSE
);
4114 vr
->vvr_err
= VRRP_SUCCESS
;
4115 vr
->vvr_timeout
= vr
->vvr_conf
.vvc_adver_int
;
4116 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(vrrpd_timerq
,
4117 vr
->vvr_timeout
, vrrp_adv_timeout
, vr
)) == -1) {
4118 vrrp_log(VRRP_ERR
, "vrrpd_state_i2m(): unable to start timer");
4121 vrrp_log(VRRP_DBG1
, "vrrpd_state_i2m(%s): start "
4122 "vrrp_adv_timeout(%d)", vr
->vvr_conf
.vvc_name
,
4125 return (VRRP_SUCCESS
);
4129 vrrpd_state_i2b(vrrp_vr_t
*vr
)
4133 vrrp_log(VRRP_DBG1
, "vrrpd_state_i2b(%s)", vr
->vvr_conf
.vvc_name
);
4135 vrrpd_state_trans(VRRP_STATE_INIT
, VRRP_STATE_BACKUP
, vr
);
4136 if ((err
= vrrpd_virtualip_update(vr
, _B_FALSE
)) != VRRP_SUCCESS
)
4140 * Reinitialize the Master advertisement interval to be the configured
4143 vr
->vvr_err
= VRRP_SUCCESS
;
4144 vr
->vvr_master_adver_int
= vr
->vvr_conf
.vvc_adver_int
;
4145 vr
->vvr_timeout
= MASTER_DOWN_INTERVAL_VR(vr
);
4146 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(vrrpd_timerq
,
4147 vr
->vvr_timeout
, vrrp_b2m_timeout
, vr
)) == -1) {
4148 vrrp_log(VRRP_ERR
, "vrrpd_state_i2b(): unable to set timer");
4151 vrrp_log(VRRP_DBG1
, "vrrpd_state_i2b(%s): start "
4152 "vrrp_b2m_timeout(%d)", vr
->vvr_conf
.vvc_name
,
4155 return (VRRP_SUCCESS
);
4159 vrrpd_state_m2i(vrrp_vr_t
*vr
)
4161 vrrp_log(VRRP_DBG1
, "vrrpd_state_m2i(%s)", vr
->vvr_conf
.vvc_name
);
4163 vrrpd_state_trans(VRRP_STATE_MASTER
, VRRP_STATE_INIT
, vr
);
4164 (void) vrrpd_virtualip_update(vr
, _B_TRUE
);
4165 bzero(&vr
->vvr_peer
, sizeof (vrrp_peer_t
));
4166 (void) iu_cancel_timer(vrrpd_timerq
, vr
->vvr_timer_id
, NULL
);
4170 vrrpd_state_b2i(vrrp_vr_t
*vr
)
4172 vrrp_log(VRRP_DBG1
, "vrrpd_state_b2i(%s)", vr
->vvr_conf
.vvc_name
);
4174 bzero(&vr
->vvr_peer
, sizeof (vrrp_peer_t
));
4175 (void) iu_cancel_timer(vrrpd_timerq
, vr
->vvr_timer_id
, NULL
);
4176 vrrpd_state_trans(VRRP_STATE_BACKUP
, VRRP_STATE_INIT
, vr
);
4177 (void) vrrpd_virtualip_update(vr
, _B_TRUE
);
4182 vrrp_b2m_timeout(iu_tq_t
*tq
, void *arg
)
4184 vrrp_vr_t
*vr
= (vrrp_vr_t
*)arg
;
4186 vrrp_log(VRRP_DBG1
, "vrrp_b2m_timeout(%s)", vr
->vvr_conf
.vvc_name
);
4187 (void) vrrpd_state_b2m(vr
);
4192 vrrp_adv_timeout(iu_tq_t
*tq
, void *arg
)
4194 vrrp_vr_t
*vr
= (vrrp_vr_t
*)arg
;
4196 vrrp_log(VRRP_DBG1
, "vrrp_adv_timeout(%s)", vr
->vvr_conf
.vvc_name
);
4198 (void) vrrpd_send_adv(vr
, _B_FALSE
);
4199 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(vrrpd_timerq
,
4200 vr
->vvr_timeout
, vrrp_adv_timeout
, vr
)) == -1) {
4201 vrrp_log(VRRP_ERR
, "vrrp_adv_timeout(%s): start timer failed",
4202 vr
->vvr_conf
.vvc_name
);
4204 vrrp_log(VRRP_DBG1
, "vrrp_adv_timeout(%s): start "
4205 "vrrp_adv_timeout(%d)", vr
->vvr_conf
.vvc_name
,
4211 vrrpd_state_b2m(vrrp_vr_t
*vr
)
4215 vrrp_log(VRRP_DBG1
, "vrrpd_state_b2m(%s)", vr
->vvr_conf
.vvc_name
);
4217 vrrpd_state_trans(VRRP_STATE_BACKUP
, VRRP_STATE_MASTER
, vr
);
4218 if ((err
= vrrpd_virtualip_update(vr
, _B_FALSE
)) != VRRP_SUCCESS
)
4220 (void) vrrpd_send_adv(vr
, _B_FALSE
);
4222 vr
->vvr_timeout
= vr
->vvr_conf
.vvc_adver_int
;
4223 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(vrrpd_timerq
,
4224 vr
->vvr_timeout
, vrrp_adv_timeout
, vr
)) == -1) {
4225 vrrp_log(VRRP_ERR
, "vrrpd_state_b2m(%s): start timer failed",
4226 vr
->vvr_conf
.vvc_name
);
4229 vrrp_log(VRRP_DBG1
, "vrrpd_state_b2m(%s): start "
4230 "vrrp_adv_timeout(%d)", vr
->vvr_conf
.vvc_name
,
4233 return (VRRP_SUCCESS
);
4237 vrrpd_state_m2b(vrrp_vr_t
*vr
)
4241 vrrp_log(VRRP_DBG1
, "vrrpd_state_m2b(%s)", vr
->vvr_conf
.vvc_name
);
4243 vrrpd_state_trans(VRRP_STATE_MASTER
, VRRP_STATE_BACKUP
, vr
);
4244 if ((err
= vrrpd_virtualip_update(vr
, _B_FALSE
)) != VRRP_SUCCESS
)
4248 * Cancel the adver_timer.
4250 vr
->vvr_master_adver_int
= vr
->vvr_peer_adver_int
;
4251 (void) iu_cancel_timer(vrrpd_timerq
, vr
->vvr_timer_id
, NULL
);
4252 vr
->vvr_timeout
= MASTER_DOWN_INTERVAL_VR(vr
);
4253 if ((vr
->vvr_timer_id
= iu_schedule_timer_ms(vrrpd_timerq
,
4254 vr
->vvr_timeout
, vrrp_b2m_timeout
, vr
)) == -1) {
4255 vrrp_log(VRRP_ERR
, "vrrpd_state_m2b(%s): start timer failed",
4256 vr
->vvr_conf
.vvc_name
);
4258 vrrp_log(VRRP_DBG1
, "vrrpd_state_m2b(%s) start "
4259 "vrrp_b2m_timeout(%d)", vr
->vvr_conf
.vvc_name
,
4262 return (VRRP_SUCCESS
);
4266 * Set the IFF_NOACCESS flag on the VNIC interface of the VRRP router
4267 * based on its access mode.
4270 vrrpd_set_noaccept(vrrp_vr_t
*vr
, boolean_t on
)
4272 vrrp_intf_t
*vif
= vr
->vvr_vif
;
4273 uint64_t curr_flags
;
4277 vrrp_log(VRRP_DBG1
, "vrrpd_set_noaccept(%s, %s)",
4278 vr
->vvr_conf
.vvc_name
, on
? "on" : "off");
4281 * Possibly no virtual address exists on this VRRP router yet.
4284 return (VRRP_SUCCESS
);
4286 vrrp_log(VRRP_DBG1
, "vrrpd_set_noaccept(%s, %s)",
4287 vif
->vvi_ifname
, vrrp_state2str(vr
->vvr_state
));
4289 s
= (vif
->vvi_af
== AF_INET
) ? vrrpd_ctlsock_fd
: vrrpd_ctlsock6_fd
;
4290 (void) strncpy(lifr
.lifr_name
, vif
->vvi_ifname
,
4291 sizeof (lifr
.lifr_name
));
4292 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
4293 if (errno
!= ENXIO
&& errno
!= ENOENT
) {
4294 vrrp_log(VRRP_ERR
, "vrrpd_set_noaccept(): "
4295 "SIOCGLIFFLAGS on %s failed: %s",
4296 vif
->vvi_ifname
, strerror(errno
));
4301 curr_flags
= lifr
.lifr_flags
;
4303 lifr
.lifr_flags
|= IFF_NOACCEPT
;
4305 lifr
.lifr_flags
&= ~IFF_NOACCEPT
;
4307 if (lifr
.lifr_flags
!= curr_flags
) {
4308 if (ioctl(s
, SIOCSLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
4309 if (errno
!= ENXIO
&& errno
!= ENOENT
) {
4310 vrrp_log(VRRP_ERR
, "vrrpd_set_noaccept(%s): "
4311 "SIOCSLIFFLAGS 0x%llx on %s failed: %s",
4312 on
? "no_accept" : "accept",
4313 lifr
.lifr_flags
, vif
->vvi_ifname
,
4319 return (VRRP_SUCCESS
);
4323 vrrpd_virtualip_updateone(vrrp_intf_t
*vif
, vrrp_ip_t
*ip
, boolean_t checkonly
)
4325 vrrp_state_t state
= vif
->vvi_vr_state
;
4327 char abuf
[INET6_ADDRSTRLEN
];
4328 int af
= vif
->vvi_af
;
4329 uint64_t curr_flags
;
4332 assert(IS_VIRTUAL_INTF(vif
));
4334 /* LINTED E_CONSTANT_CONDITION */
4335 VRRPADDR2STR(af
, &ip
->vip_addr
, abuf
, INET6_ADDRSTRLEN
, _B_FALSE
);
4336 vrrp_log(VRRP_DBG1
, "vrrpd_virtualip_updateone(%s, %s%s)",
4337 vif
->vvi_ifname
, abuf
, checkonly
? ", checkonly" : "");
4339 s
= (af
== AF_INET
) ? vrrpd_ctlsock_fd
: vrrpd_ctlsock6_fd
;
4340 (void) strncpy(lifr
.lifr_name
, ip
->vip_lifname
,
4341 sizeof (lifr
.lifr_name
));
4342 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
4343 if (errno
!= ENXIO
&& errno
!= ENOENT
) {
4344 vrrp_log(VRRP_ERR
, "vrrpd_virtualip_updateone(%s): "
4345 "SIOCGLIFFLAGS on %s/%s failed: %s",
4346 vif
->vvi_ifname
, lifr
.lifr_name
, abuf
,
4352 curr_flags
= lifr
.lifr_flags
;
4353 if (state
== VRRP_STATE_MASTER
)
4354 lifr
.lifr_flags
|= IFF_UP
;
4356 lifr
.lifr_flags
&= ~IFF_UP
;
4358 if (lifr
.lifr_flags
== curr_flags
)
4359 return (VRRP_SUCCESS
);
4362 vrrp_log(VRRP_ERR
, "VRRP virtual IP %s/%s was brought %s",
4363 ip
->vip_lifname
, abuf
,
4364 state
== VRRP_STATE_MASTER
? "down" : "up");
4366 } else if (ioctl(s
, SIOCSLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
4367 if (errno
!= ENXIO
&& errno
!= ENOENT
) {
4368 vrrp_log(VRRP_ERR
, "vrrpd_virtualip_updateone(%s, %s): "
4369 "bring %s %s/%s failed: %s",
4370 vif
->vvi_ifname
, vrrp_state2str(state
),
4371 state
== VRRP_STATE_MASTER
? "up" : "down",
4372 ip
->vip_lifname
, abuf
, strerror(errno
));
4376 return (VRRP_SUCCESS
);
4380 vrrpd_virtualip_update(vrrp_vr_t
*vr
, boolean_t checkonly
)
4383 vrrp_intf_t
*vif
= vr
->vvr_vif
;
4384 vrrp_ip_t
*ip
, *nextip
;
4385 char abuf
[INET6_ADDRSTRLEN
];
4388 vrrp_log(VRRP_DBG1
, "vrrpd_virtualip_update(%s, %s, %s)%s",
4389 vr
->vvr_conf
.vvc_name
, vrrp_state2str(vr
->vvr_state
),
4390 vif
->vvi_ifname
, checkonly
? " checkonly" : "");
4392 state
= vr
->vvr_state
;
4393 assert(vif
!= NULL
);
4394 assert(IS_VIRTUAL_INTF(vif
));
4395 assert(vif
->vvi_vr_state
!= state
);
4396 vif
->vvi_vr_state
= state
;
4397 for (ip
= TAILQ_FIRST(&vif
->vvi_iplist
); ip
!= NULL
; ip
= nextip
) {
4398 nextip
= TAILQ_NEXT(ip
, vip_next
);
4399 err
= vrrpd_virtualip_updateone(vif
, ip
, _B_FALSE
);
4400 if (!checkonly
&& err
!= VRRP_SUCCESS
) {
4401 /* LINTED E_CONSTANT_CONDITION */
4402 VRRPADDR2STR(vif
->vvi_af
, &ip
->vip_addr
, abuf
,
4403 INET6_ADDRSTRLEN
, _B_FALSE
);
4404 vrrp_log(VRRP_DBG1
, "vrrpd_virtualip_update() update "
4405 "%s over %s failed", abuf
, vif
->vvi_ifname
);
4406 vrrpd_delete_ip(vif
, ip
);
4411 * The IP address is deleted when it is failed to be brought
4412 * up. If no IP addresses are left, delete this interface.
4414 if (!checkonly
&& TAILQ_EMPTY(&vif
->vvi_iplist
)) {
4415 vrrp_log(VRRP_DBG0
, "vrrpd_virtualip_update(): "
4416 "no IP left over %s", vif
->vvi_ifname
);
4417 vrrpd_delete_if(vif
, _B_TRUE
);
4418 return (VRRP_ENOVIRT
);
4420 return (VRRP_SUCCESS
);
4424 vrrpd_state_trans(vrrp_state_t prev_s
, vrrp_state_t s
, vrrp_vr_t
*vr
)
4426 vrrp_log(VRRP_DBG1
, "vrrpd_state_trans(%s): %s --> %s",
4427 vr
->vvr_conf
.vvc_name
, vrrp_state2str(prev_s
), vrrp_state2str(s
));
4429 assert(vr
->vvr_state
== prev_s
);
4431 vr
->vvr_prev_state
= prev_s
;
4432 (void) gettimeofday(&vr
->vvr_st_time
, NULL
);
4433 (void) vrrpd_post_event(vr
->vvr_conf
.vvc_name
, prev_s
, s
);
4437 vrrpd_post_event(const char *name
, vrrp_state_t prev_st
, vrrp_state_t st
)
4440 nvlist_t
*nvl
= NULL
;
4443 * sysevent is not supported in the non-global zone
4445 if (getzoneid() != GLOBAL_ZONEID
)
4448 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0)
4451 if (nvlist_add_uint8(nvl
, VRRP_EVENT_VERSION
,
4452 VRRP_EVENT_CUR_VERSION
) != 0)
4455 if (nvlist_add_string(nvl
, VRRP_EVENT_ROUTER_NAME
, name
) != 0)
4458 if (nvlist_add_uint8(nvl
, VRRP_EVENT_STATE
, st
) != 0)
4461 if (nvlist_add_uint8(nvl
, VRRP_EVENT_PREV_STATE
, prev_st
) != 0)
4464 if (sysevent_post_event(EC_VRRP
, ESC_VRRP_STATE_CHANGE
,
4465 SUNW_VENDOR
, VRRP_EVENT_PUBLISHER
, nvl
, &eid
) == 0) {
4471 vrrp_log(VRRP_ERR
, "vrrpd_post_event(): `state change (%s --> %s)' "
4472 "sysevent posting failed: %s", vrrp_state2str(prev_st
),
4473 vrrp_state2str(st
), strerror(errno
));
4480 * timeval processing functions
4483 timeval_to_milli(struct timeval tv
)
4485 return ((int)(tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000 + 0.5));
4488 static struct timeval
4489 timeval_delta(struct timeval t1
, struct timeval t2
)
4492 t
.tv_sec
= t1
.tv_sec
- t2
.tv_sec
;
4493 t
.tv_usec
= t1
.tv_usec
- t2
.tv_usec
;
4495 if (t
.tv_usec
< 0) {
4496 t
.tv_usec
+= 1000000;
4503 * print error messages to the terminal or to syslog
4506 vrrp_log(int level
, char *message
, ...)
4511 va_start(ap
, message
);
4513 if (vrrp_logflag
== 0) {
4514 if (level
<= vrrp_debug_level
) {
4516 * VRRP_ERR goes to stderr, others go to stdout
4518 FILE *out
= (level
<= VRRP_ERR
) ? stderr
: stdout
;
4519 (void) fprintf(out
, "vrrpd: ");
4520 /* LINTED: E_SEC_PRINTF_VAR_FMT */
4521 (void) vfprintf(out
, message
, ap
);
4522 (void) fprintf(out
, "\n");
4530 * translate VRRP_* to LOG_*
4534 log_level
= LOG_ERR
;
4537 log_level
= LOG_WARNING
;
4540 log_level
= LOG_NOTICE
;
4543 log_level
= LOG_INFO
;
4546 log_level
= LOG_DEBUG
;
4550 /* LINTED: E_SEC_PRINTF_VAR_FMT */
4551 (void) vsyslog(log_level
, message
, ap
);