1/* $NetBSD: carp.c,v 1.12 2008/07/15 21:27:58 dyoung Exp $ */ 2 3/* 4 * Copyright (c) 2002 Michael Shalayeff. All rights reserved. 5 * Copyright (c) 2003 Ryan McBride. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30#ifndef lint 31__RCSID("$NetBSD: carp.c,v 1.12 2008/07/15 21:27:58 dyoung Exp $"); 32#endif /* not lint */ 33 34#include <sys/param.h> 35#include <sys/ioctl.h> 36#include <sys/socket.h> 37#include <sys/sockio.h> 38 39#include <net/if.h> 40#include <netinet/ip_carp.h> 41#include <net/route.h> 42 43#include <stdio.h> 44#include <string.h> 45#include <stdlib.h> 46#include <unistd.h> 47#include <err.h> 48#include <errno.h> 49#include <util.h> 50 51#include "env.h" 52#include "parse.h" 53#include "extern.h" 54 55static status_func_t status; 56static usage_func_t usage; 57static cmdloop_branch_t branch; 58 59static void carp_constructor(void) __attribute__((constructor)); 60static void carp_status(prop_dictionary_t, prop_dictionary_t); 61static int setcarp_advbase(prop_dictionary_t, prop_dictionary_t); 62static int setcarp_advskew(prop_dictionary_t, prop_dictionary_t); 63static int setcarp_passwd(prop_dictionary_t, prop_dictionary_t); 64static int setcarp_vhid(prop_dictionary_t, prop_dictionary_t); 65static int setcarp_state(prop_dictionary_t, prop_dictionary_t); 66static int setcarpdev(prop_dictionary_t, prop_dictionary_t); 67 68static const char *carp_states[] = { CARP_STATES }; 69 70struct kwinst carpstatekw[] = { 71 {.k_word = "INIT", .k_nextparser = &command_root.pb_parser} 72 , {.k_word = "BACKUP", .k_nextparser = &command_root.pb_parser} 73 , {.k_word = "MASTER", .k_nextparser = &command_root.pb_parser} 74}; 75 76struct pinteger parse_advbase = PINTEGER_INITIALIZER1(&parse_advbase, "advbase", 77 0, 255, 10, setcarp_advbase, "advbase", &command_root.pb_parser); 78 79struct pinteger parse_advskew = PINTEGER_INITIALIZER1(&parse_advskew, "advskew", 80 0, 254, 10, setcarp_advskew, "advskew", &command_root.pb_parser); 81 82struct piface carpdev = PIFACE_INITIALIZER(&carpdev, "carpdev", setcarpdev, 83 "carpdev", &command_root.pb_parser); 84 85struct pkw carpstate = PKW_INITIALIZER(&carpstate, "carp state", setcarp_state, 86 "carp_state", carpstatekw, __arraycount(carpstatekw), 87 &command_root.pb_parser); 88 89struct pstr pass = PSTR_INITIALIZER(&pass, "pass", setcarp_passwd, 90 "pass", &command_root.pb_parser); 91 92struct pinteger parse_vhid = PINTEGER_INITIALIZER1(&vhid, "vhid", 93 0, 255, 10, setcarp_vhid, "vhid", &command_root.pb_parser); 94 95static const struct kwinst carpkw[] = { 96 {.k_word = "advbase", .k_nextparser = &parse_advbase.pi_parser} 97 , {.k_word = "advskew", .k_nextparser = &parse_advskew.pi_parser} 98 , {.k_word = "carpdev", .k_nextparser = &carpdev.pif_parser} 99 , {.k_word = "-carpdev", .k_key = "carpdev", .k_type = KW_T_STR, 100 .k_str = "", .k_exec = setcarpdev, 101 .k_nextparser = &command_root.pb_parser} 102 , {.k_word = "pass", .k_nextparser = &pass.ps_parser} 103 , {.k_word = "state", .k_nextparser = &carpstate.pk_parser} 104 , {.k_word = "vhid", .k_nextparser = &parse_vhid.pi_parser} 105}; 106 107struct pkw carp = PKW_INITIALIZER(&carp, "CARP", NULL, NULL, 108 carpkw, __arraycount(carpkw), NULL); 109 110static void 111carp_set(prop_dictionary_t env, struct carpreq *carpr) 112{ 113 if (indirect_ioctl(env, SIOCSVH, carpr) == -1) 114 err(EXIT_FAILURE, "SIOCSVH"); 115} 116 117static int 118carp_get1(prop_dictionary_t env, struct carpreq *carpr) 119{ 120 memset(carpr, 0, sizeof(*carpr)); 121 122 return indirect_ioctl(env, SIOCGVH, carpr); 123} 124 125static void 126carp_get(prop_dictionary_t env, struct carpreq *carpr) 127{ 128 if (carp_get1(env, carpr) == -1) 129 err(EXIT_FAILURE, "SIOCGVH"); 130} 131 132static void 133carp_status(prop_dictionary_t env, prop_dictionary_t oenv) 134{ 135 const char *state; 136 struct carpreq carpr; 137 138 if (carp_get1(env, &carpr) == -1) 139 return; 140 141 if (carpr.carpr_vhid <= 0) 142 return; 143 if (carpr.carpr_state > CARP_MAXSTATE) 144 state = "<UNKNOWN>"; 145 else 146 state = carp_states[carpr.carpr_state]; 147 148 printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n", 149 state, carpr.carpr_carpdev[0] != '\0' ? 150 carpr.carpr_carpdev : "none", carpr.carpr_vhid, 151 carpr.carpr_advbase, carpr.carpr_advskew); 152} 153 154int 155setcarp_passwd(prop_dictionary_t env, prop_dictionary_t oenv) 156{ 157 struct carpreq carpr; 158 prop_data_t data; 159 160 data = (prop_data_t)prop_dictionary_get(env, "pass"); 161 if (data == NULL) { 162 errno = ENOENT; 163 return -1; 164 } 165 166 carp_get(env, &carpr); 167 168 memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key)); 169 /* XXX Should hash the password into the key here, perhaps? */ 170 strlcpy((char *)carpr.carpr_key, prop_data_data_nocopy(data), 171 MIN(CARP_KEY_LEN, prop_data_size(data))); 172 173 carp_set(env, &carpr); 174 return 0; 175} 176 177int 178setcarp_vhid(prop_dictionary_t env, prop_dictionary_t oenv) 179{ 180 struct carpreq carpr; 181 int64_t vhid; 182 183 if (!prop_dictionary_get_int64(env, "vhid", &vhid)) { 184 errno = ENOENT; 185 return -1; 186 } 187 188 carp_get(env, &carpr); 189 190 carpr.carpr_vhid = vhid; 191 192 carp_set(env, &carpr); 193 return 0; 194} 195 196int 197setcarp_advskew(prop_dictionary_t env, prop_dictionary_t oenv) 198{ 199 struct carpreq carpr; 200 int64_t advskew; 201 202 if (!prop_dictionary_get_int64(env, "advskew", &advskew)) { 203 errno = ENOENT; 204 return -1; 205 } 206 207 carp_get(env, &carpr); 208 209 carpr.carpr_advskew = advskew; 210 211 carp_set(env, &carpr); 212 return 0; 213} 214 215/* ARGSUSED */ 216int 217setcarp_advbase(prop_dictionary_t env, prop_dictionary_t oenv) 218{ 219 struct carpreq carpr; 220 int64_t advbase; 221 222 if (!prop_dictionary_get_int64(env, "advbase", &advbase)) { 223 errno = ENOENT; 224 return -1; 225 } 226 227 carp_get(env, &carpr); 228 229 carpr.carpr_advbase = advbase; 230 231 carp_set(env, &carpr); 232 return 0; 233} 234 235/* ARGSUSED */ 236static int 237setcarp_state(prop_dictionary_t env, prop_dictionary_t oenv) 238{ 239 struct carpreq carpr; 240 int64_t carp_state; 241 242 if (!prop_dictionary_get_int64(env, "carp_state", &carp_state)) { 243 errno = ENOENT; 244 return -1; 245 } 246 247 carp_get(env, &carpr); 248 249 carpr.carpr_state = carp_state; 250 251 carp_set(env, &carpr); 252 return 0; 253} 254 255/* ARGSUSED */ 256int 257setcarpdev(prop_dictionary_t env, prop_dictionary_t oenv) 258{ 259 struct carpreq carpr; 260 prop_string_t s; 261 262 s = (prop_string_t)prop_dictionary_get(env, "carpdev"); 263 if (s == NULL) { 264 errno = ENOENT; 265 return -1; 266 } 267 268 carp_get(env, &carpr); 269 270 strlcpy(carpr.carpr_carpdev, prop_string_cstring_nocopy(s), 271 sizeof(carpr.carpr_carpdev)); 272 273 carp_set(env, &carpr); 274 return 0; 275} 276 277static void 278carp_usage(prop_dictionary_t env) 279{ 280 fprintf(stderr, 281 "\t[ advbase n ] [ advskew n ] [ carpdev iface ] " 282 "[ pass passphrase ] [ state state ] [ vhid n ]\n"); 283 284} 285 286static void 287carp_constructor(void) 288{ 289 cmdloop_branch_init(&branch, &carp.pk_parser); 290 register_cmdloop_branch(&branch); 291 status_func_init(&status, carp_status); 292 usage_func_init(&usage, carp_usage); 293 register_status(&status); 294 register_usage(&usage); 295} 296