carp.c revision 1.5 1 /* $NetBSD: carp.c,v 1.5 2008/05/06 04:33:42 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/param.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <sys/sockio.h>
33
34 #include <net/if.h>
35 #include <netinet/ip_carp.h>
36 #include <net/route.h>
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <util.h>
45
46 #include "env.h"
47 #include "parse.h"
48 #include "extern.h"
49 #include "carp.h"
50
51 static const char *carp_states[] = { CARP_STATES };
52
53 #ifndef INET_ONLY
54 struct kwinst carpstatekw[] = {
55 {.k_word = "INIT", .k_nextparser = &command_root.pb_parser}
56 , {.k_word = "BACKUP", .k_nextparser = &command_root.pb_parser}
57 , {.k_word = "MASTER", .k_nextparser = &command_root.pb_parser}
58 };
59
60 struct pinteger parse_advbase = PINTEGER_INITIALIZER1(&parse_advbase, "advbase",
61 0, 255, 10, setcarp_advbase, "advbase", &command_root.pb_parser);
62
63 struct pinteger parse_advskew = PINTEGER_INITIALIZER1(&parse_advskew, "advskew",
64 0, 254, 10, setcarp_advskew, "advskew", &command_root.pb_parser);
65
66 struct piface carpdev = PIFACE_INITIALIZER(&carpdev, "carpdev", setcarpdev,
67 "carpdev", &command_root.pb_parser);
68
69 struct pkw carpstate = PKW_INITIALIZER(&carpstate, "carp state", NULL,
70 "carp_state", carpstatekw, __arraycount(carpstatekw),
71 &command_root.pb_parser);
72
73 struct pstr pass = PSTR_INITIALIZER(&pass, "pass", setcarp_passwd,
74 "pass", &command_root.pb_parser);
75
76 struct pinteger parse_vhid = PINTEGER_INITIALIZER1(&vhid, "vhid",
77 0, 255, 10, setcarp_vhid, "vhid", &command_root.pb_parser);
78 #endif
79
80 void
81 carp_status(prop_dictionary_t env)
82 {
83 const char *state;
84 struct ifreq ifr;
85 struct carpreq carpr;
86 int s;
87 const char *ifname;
88
89 if ((s = getsock(AF_UNSPEC)) == -1)
90 err(EXIT_FAILURE, "%s: getsock", __func__);
91
92 memset(&ifr, 0, sizeof(ifr));
93 memset(&carpr, 0, sizeof(carpr));
94 ifr.ifr_data = &carpr;
95 if ((ifname = getifname(env)) == NULL)
96 err(EXIT_FAILURE, "%s: getifname", __func__);
97
98 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
99
100 if (ioctl(s, SIOCGVH, &ifr) == -1)
101 return;
102
103 if (carpr.carpr_vhid <= 0)
104 return;
105 if (carpr.carpr_state > CARP_MAXSTATE)
106 state = "<UNKNOWN>";
107 else
108 state = carp_states[carpr.carpr_state];
109
110 printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n",
111 state, carpr.carpr_carpdev[0] != '\0' ?
112 carpr.carpr_carpdev : "none", carpr.carpr_vhid,
113 carpr.carpr_advbase, carpr.carpr_advskew);
114 }
115
116 int
117 setcarp_passwd(prop_dictionary_t env, prop_dictionary_t xenv)
118 {
119 struct carpreq carpr;
120 struct ifreq ifr;
121 int s;
122 prop_data_t data;
123 const char *ifname;
124
125 if ((s = getsock(AF_UNSPEC)) == -1)
126 err(EXIT_FAILURE, "%s: getsock", __func__);
127
128 data = (prop_data_t)prop_dictionary_get(env, "pass");
129 if (data == NULL) {
130 errno = ENOENT;
131 return -1;
132 }
133
134 memset(&ifr, 0, sizeof(ifr));
135 memset(&carpr, 0, sizeof(carpr));
136 ifr.ifr_data = &carpr;
137
138 if ((ifname = getifname(env)) == NULL)
139 err(EXIT_FAILURE, "%s: getifname", __func__);
140
141 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
142
143 if (ioctl(s, SIOCGVH, &ifr) == -1)
144 err(EXIT_FAILURE, "SIOCGVH");
145
146 memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key));
147 /* XXX Should hash the password into the key here, perhaps? */
148 strlcpy((char *)carpr.carpr_key, prop_data_data_nocopy(data),
149 MIN(CARP_KEY_LEN, prop_data_size(data)));
150
151 if (ioctl(s, SIOCSVH, &ifr) == -1)
152 err(EXIT_FAILURE, "SIOCSVH");
153 return 0;
154 }
155
156 int
157 setcarp_vhid(prop_dictionary_t env, prop_dictionary_t xenv)
158 {
159 struct ifreq ifr;
160 struct carpreq carpr;
161 int vhid;
162 int s;
163 prop_number_t num;
164
165 if ((s = getsock(AF_UNSPEC)) == -1)
166 err(EXIT_FAILURE, "%s: getsock", __func__);
167
168 num = (prop_number_t)prop_dictionary_get(env, "vhid");
169 if (num == NULL) {
170 errno = ENOENT;
171 return -1;
172 }
173
174 vhid = (int)prop_number_integer_value(num);
175
176 memset(&carpr, 0, sizeof(struct carpreq));
177 ifr.ifr_data = &carpr;
178
179 if (ioctl(s, SIOCGVH, &ifr) == -1)
180 err(EXIT_FAILURE, "SIOCGVH");
181
182 carpr.carpr_vhid = vhid;
183
184 if (ioctl(s, SIOCSVH, &ifr) == -1)
185 err(EXIT_FAILURE, "SIOCSVH");
186 return 0;
187 }
188
189 int
190 setcarp_advskew(prop_dictionary_t env, prop_dictionary_t xenv)
191 {
192 struct ifreq ifr;
193 struct carpreq carpr;
194 int advskew;
195 int s;
196 prop_number_t num;
197 const char *ifname;
198
199 if ((s = getsock(AF_UNSPEC)) == -1)
200 err(EXIT_FAILURE, "%s: getsock", __func__);
201
202 num = (prop_number_t)prop_dictionary_get(env, "advskew");
203 if (num == NULL) {
204 errno = ENOENT;
205 return -1;
206 }
207
208 advskew = (int)prop_number_integer_value(num);
209
210 memset(&ifr, 0, sizeof(ifr));
211 memset(&carpr, 0, sizeof(carpr));
212 ifr.ifr_data = &carpr;
213 if ((ifname = getifname(env)) == NULL)
214 err(EXIT_FAILURE, "%s: getifname", __func__);
215
216 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
217
218 if (ioctl(s, SIOCGVH, &ifr) == -1)
219 err(EXIT_FAILURE, "SIOCGVH");
220
221 carpr.carpr_advskew = advskew;
222
223 if (ioctl(s, SIOCSVH, &ifr) == -1)
224 err(EXIT_FAILURE, "SIOCSVH");
225 return 0;
226 }
227
228 /* ARGSUSED */
229 int
230 setcarp_advbase(prop_dictionary_t env, prop_dictionary_t xenv)
231 {
232 struct carpreq carpr;
233 int advbase;
234 int s;
235 prop_number_t num;
236 struct ifreq ifr;
237 const char *ifname;
238
239 if ((s = getsock(AF_UNSPEC)) == -1)
240 err(EXIT_FAILURE, "%s: getsock", __func__);
241
242 num = (prop_number_t)prop_dictionary_get(env, "advbase");
243 if (num == NULL) {
244 errno = ENOENT;
245 return -1;
246 }
247
248 advbase = (int)prop_number_integer_value(num);
249
250 memset(&ifr, 0, sizeof(ifr));
251 memset(&carpr, 0, sizeof(carpr));
252 ifr.ifr_data = &carpr;
253 if ((ifname = getifname(env)) == NULL)
254 err(EXIT_FAILURE, "%s: getifname", __func__);
255
256 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
257
258 if (ioctl(s, SIOCGVH, &ifr) == -1)
259 err(EXIT_FAILURE, "SIOCGVH");
260
261 carpr.carpr_advbase = advbase;
262
263 if (ioctl(s, SIOCSVH, &ifr) == -1)
264 err(EXIT_FAILURE, "SIOCSVH");
265 return 0;
266 }
267
268 /* ARGSUSED */
269 int
270 setcarp_state(prop_dictionary_t env, prop_dictionary_t xenv)
271 {
272 struct carpreq carpr;
273 int s;
274 prop_number_t num;
275 struct ifreq ifr;
276 const char *ifname;
277
278 if ((s = getsock(AF_UNSPEC)) == -1)
279 err(EXIT_FAILURE, "%s: getsock", __func__);
280
281 num = (prop_number_t)prop_dictionary_get(env, "carp_state");
282 if (num == NULL) {
283 errno = ENOENT;
284 return -1;
285 }
286
287 memset(&ifr, 0, sizeof(ifr));
288 memset(&carpr, 0, sizeof(carpr));
289 ifr.ifr_data = &carpr;
290 if ((ifname = getifname(env)) == NULL)
291 err(EXIT_FAILURE, "%s: getifname", __func__);
292
293 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
294
295 if (ioctl(s, SIOCGVH, &ifr) == -1)
296 err(EXIT_FAILURE, "SIOCGVH");
297
298 carpr.carpr_state = (int)prop_number_integer_value(num);
299
300 if (ioctl(s, SIOCSVH, &ifr) == -1)
301 err(EXIT_FAILURE, "SIOCSVH");
302 return 0;
303 }
304
305 /* ARGSUSED */
306 int
307 setcarpdev(prop_dictionary_t env, prop_dictionary_t xenv)
308 {
309 struct carpreq carpr;
310 int s;
311 prop_data_t data;
312 struct ifreq ifr;
313 const char *ifname;
314
315 data = (prop_data_t)prop_dictionary_get(env, "carpdev");
316 if (data == NULL) {
317 errno = ENOENT;
318 return -1;
319 }
320
321 if ((s = getsock(AF_UNSPEC)) == -1)
322 err(EXIT_FAILURE, "%s: getsock", __func__);
323
324 memset(&ifr, 0, sizeof(ifr));
325 memset(&carpr, 0, sizeof(carpr));
326 ifr.ifr_data = &carpr;
327 if ((ifname = getifname(env)) == NULL)
328 err(EXIT_FAILURE, "%s: getifname", __func__);
329
330 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
331
332 if (ioctl(s, SIOCGVH, &ifr) == -1)
333 err(EXIT_FAILURE, "SIOCGVH");
334
335 strlcpy(carpr.carpr_carpdev, prop_data_data_nocopy(data),
336 MIN(sizeof(carpr.carpr_carpdev), prop_data_size(data)));
337
338 if (ioctl(s, SIOCSVH, &ifr) == -1)
339 err(EXIT_FAILURE, "SIOCSVH");
340 return 0;
341 }
342