carp.c revision 1.7 1 /* $NetBSD: carp.c,v 1.7 2008/05/06 21:16:52 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, prop_dictionary_t oenv)
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 int64_t vhid;
162 int s;
163
164 if ((s = getsock(AF_UNSPEC)) == -1)
165 err(EXIT_FAILURE, "%s: getsock", __func__);
166
167 if (!prop_dictionary_get_int64(env, "vhid", &vhid)) {
168 errno = ENOENT;
169 return -1;
170 }
171
172 memset(&carpr, 0, sizeof(struct carpreq));
173 ifr.ifr_data = &carpr;
174
175 if (ioctl(s, SIOCGVH, &ifr) == -1)
176 err(EXIT_FAILURE, "SIOCGVH");
177
178 carpr.carpr_vhid = vhid;
179
180 if (ioctl(s, SIOCSVH, &ifr) == -1)
181 err(EXIT_FAILURE, "SIOCSVH");
182 return 0;
183 }
184
185 int
186 setcarp_advskew(prop_dictionary_t env, prop_dictionary_t xenv)
187 {
188 struct ifreq ifr;
189 struct carpreq carpr;
190 int64_t advskew;
191 int s;
192 const char *ifname;
193
194 if ((s = getsock(AF_UNSPEC)) == -1)
195 err(EXIT_FAILURE, "%s: getsock", __func__);
196
197 if (!prop_dictionary_get_int64(env, "advskew", &advskew)) {
198 errno = ENOENT;
199 return -1;
200 }
201
202 memset(&ifr, 0, sizeof(ifr));
203 memset(&carpr, 0, sizeof(carpr));
204 ifr.ifr_data = &carpr;
205 if ((ifname = getifname(env)) == NULL)
206 err(EXIT_FAILURE, "%s: getifname", __func__);
207
208 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
209
210 if (ioctl(s, SIOCGVH, &ifr) == -1)
211 err(EXIT_FAILURE, "SIOCGVH");
212
213 carpr.carpr_advskew = advskew;
214
215 if (ioctl(s, SIOCSVH, &ifr) == -1)
216 err(EXIT_FAILURE, "SIOCSVH");
217 return 0;
218 }
219
220 /* ARGSUSED */
221 int
222 setcarp_advbase(prop_dictionary_t env, prop_dictionary_t xenv)
223 {
224 struct carpreq carpr;
225 int64_t advbase;
226 int s;
227 struct ifreq ifr;
228 const char *ifname;
229
230 if ((s = getsock(AF_UNSPEC)) == -1)
231 err(EXIT_FAILURE, "%s: getsock", __func__);
232
233 if (!prop_dictionary_get_int64(env, "advbase", &advbase)) {
234 errno = ENOENT;
235 return -1;
236 }
237
238 memset(&ifr, 0, sizeof(ifr));
239 memset(&carpr, 0, sizeof(carpr));
240 ifr.ifr_data = &carpr;
241 if ((ifname = getifname(env)) == NULL)
242 err(EXIT_FAILURE, "%s: getifname", __func__);
243
244 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
245
246 if (ioctl(s, SIOCGVH, &ifr) == -1)
247 err(EXIT_FAILURE, "SIOCGVH");
248
249 carpr.carpr_advbase = advbase;
250
251 if (ioctl(s, SIOCSVH, &ifr) == -1)
252 err(EXIT_FAILURE, "SIOCSVH");
253 return 0;
254 }
255
256 /* ARGSUSED */
257 int
258 setcarp_state(prop_dictionary_t env, prop_dictionary_t xenv)
259 {
260 struct carpreq carpr;
261 int s;
262 struct ifreq ifr;
263 int64_t carp_state;
264 const char *ifname;
265
266 if ((s = getsock(AF_UNSPEC)) == -1)
267 err(EXIT_FAILURE, "%s: getsock", __func__);
268
269 if (!prop_dictionary_get_int64(env, "carp_state", &carp_state)) {
270 errno = ENOENT;
271 return -1;
272 }
273
274 memset(&ifr, 0, sizeof(ifr));
275 memset(&carpr, 0, sizeof(carpr));
276 ifr.ifr_data = &carpr;
277 if ((ifname = getifname(env)) == NULL)
278 err(EXIT_FAILURE, "%s: getifname", __func__);
279
280 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
281
282 if (ioctl(s, SIOCGVH, &ifr) == -1)
283 err(EXIT_FAILURE, "SIOCGVH");
284
285 carpr.carpr_state = carp_state;
286
287 if (ioctl(s, SIOCSVH, &ifr) == -1)
288 err(EXIT_FAILURE, "SIOCSVH");
289 return 0;
290 }
291
292 /* ARGSUSED */
293 int
294 setcarpdev(prop_dictionary_t env, prop_dictionary_t xenv)
295 {
296 struct carpreq carpr;
297 int s;
298 prop_data_t data;
299 struct ifreq ifr;
300 const char *ifname;
301
302 data = (prop_data_t)prop_dictionary_get(env, "carpdev");
303 if (data == NULL) {
304 errno = ENOENT;
305 return -1;
306 }
307
308 if ((s = getsock(AF_UNSPEC)) == -1)
309 err(EXIT_FAILURE, "%s: getsock", __func__);
310
311 memset(&ifr, 0, sizeof(ifr));
312 memset(&carpr, 0, sizeof(carpr));
313 ifr.ifr_data = &carpr;
314 if ((ifname = getifname(env)) == NULL)
315 err(EXIT_FAILURE, "%s: getifname", __func__);
316
317 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
318
319 if (ioctl(s, SIOCGVH, &ifr) == -1)
320 err(EXIT_FAILURE, "SIOCGVH");
321
322 strlcpy(carpr.carpr_carpdev, prop_data_data_nocopy(data),
323 MIN(sizeof(carpr.carpr_carpdev), prop_data_size(data)));
324
325 if (ioctl(s, SIOCSVH, &ifr) == -1)
326 err(EXIT_FAILURE, "SIOCSVH");
327 return 0;
328 }
329