Annotation of fwsync/driver/fwsync.c, revision 1.12.2.2
1.11 misho 1: /*-
2: * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3: *
4: * Copyright (c) 2022 Michael Pounov <misho@elwix.org>, CloudSigma AG
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
1.1 misho 27: #include "fwsync.h"
28:
29:
30: static void
31: fwsync_edge_proc(void *arg)
32: {
1.3 misho 33: int e, rcvflg = 0;
1.1 misho 34: struct uio uio;
35: struct mbuf *m = NULL;
1.3 misho 36: struct fws_proto *pkt;
1.1 misho 37:
38: DTRACE();
39:
1.7 misho 40: callout_schedule(&fws_co, hz);
41:
1.1 misho 42: memset(&uio, 0, sizeof uio);
43: uio.uio_resid = 1000000000;
44: uio.uio_td = curthread;
45:
1.7 misho 46: if ((fws_cfg.cfg.on & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
1.1 misho 47: rcvflg = MSG_DONTWAIT;
48: e = soreceive(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], NULL, &uio, &m, NULL, &rcvflg);
49: if (e) {
50: if (e != EAGAIN)
51: printf("error in edge handler #%d\n", e);
1.7 misho 52: return;
1.1 misho 53: }
1.3 misho 54: pkt = mtod(m, struct fws_proto*);
55: if (m_length(m, NULL) != sizeof(struct fws_proto)) {
56: printf("FWSync packet length=%d isn't match expected %lu\n",
57: m_length(m, NULL), sizeof(struct fws_proto));
1.8 misho 58: m_freem(m);
1.7 misho 59: return;
1.3 misho 60: }
1.1 misho 61:
1.4 misho 62: switch (pkt->fws_version) {
63: case FWS_PKTVER_STATE:
64: fwsync_add_state(pkt);
65: break;
1.5 misho 66: case FWS_PKTVER_ALIAS:
67: fwsync_add_alias(pkt);
1.4 misho 68: break;
69: default:
70: printf("FWSync packet was discarded due to wrong version\n");
1.8 misho 71: break;
1.4 misho 72: }
1.8 misho 73:
74: m_freem(m);
1.1 misho 75: }
76: }
77:
78: int
79: fwsync_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
80: {
81: ipfw_obj_header *oh;
82: struct ipfw_sync_cfg *ucfg;
83: size_t sz;
84: int e;
85:
86: DTRACE();
87:
88: sz = sizeof(*oh) + sizeof(*ucfg);
89: /* Check minimum header size */
90: if (sd->valsize < sz)
91: return (EINVAL);
92:
93: oh = (ipfw_obj_header*) sd->kbuf;
94:
95: /* Basic length checks for TLVs */
96: if (oh->ntlv.head.length != sizeof(oh->ntlv))
97: return (EINVAL);
98:
99: ucfg = (struct ipfw_sync_cfg*) (oh + 1);
100:
101: /* Check if name is properly terminated */
102: if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
103: return (EINVAL);
104:
105: if (ucfg->mode == CFG_SYNC_EDGE && !fws_cfg.cfg.edge && !(fws_ctx.config & CTX_CFG_EDGE) &&
106: !strcmp(ucfg->name, "edge") && ucfg->addrs == 1) {
107: fws_cfg.cfg.edge = 1;
108: memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE], &ucfg->addr[CFG_SYNC_ADDR_EDGE],
109: sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE]);
110: fws_ctx.config |= CTX_CFG_EDGE;
111:
112: e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE].addr.sa_family == AF_INET) ? AF_INET : AF_INET6,
113: &fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
114: if (e) {
115: printf("fwsync edge socreate failed #%d\n", e);
116: return e;
117: }
118:
119: e = sobind(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], &fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE].addr, curthread);
120: if (e) {
121: if (e != EADDRINUSE)
122: printf("fwsync edge sobind failed #%d\n", e);
123: else
124: printf("fwsync edge address in use!\n");
125: return e;
126: } else
127: fws_ctx.config |= CTX_EDGE_READY;
128: } else if (ucfg->mode == CFG_SYNC_COLLECTOR && !(fws_ctx.config & CTX_CFG_COLLECTOR_1) &&
129: !strcmp(ucfg->name, "collector") && ucfg->addrs > 0 && ucfg->addrs < 3) {
130: fws_cfg.cfg.collector = 1;
131: fws_cfg.cfg.addrs = ucfg->addrs;
132: memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1], &ucfg->addr[CFG_SYNC_ADDR_COLLECTOR_1],
133: sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1]);
134:
135: fws_ctx.config |= CTX_CFG_COLLECTOR_1;
136:
137: e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1].addr.sa_family == AF_INET) ? AF_INET : AF_INET6,
138: &fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_1], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
139: if (e) {
140: printf("fwsync collector %d socreate failed #%d\n", e, CFG_SYNC_ADDR_COLLECTOR_1);
141: return e;
142: } else
143: fws_ctx.config |= CTX_COLLECTOR_1_READY;
144:
145: if (fws_cfg.cfg.addrs > 1) {
146: memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2], &ucfg->addr[CFG_SYNC_ADDR_COLLECTOR_2],
147: sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2]);
148:
149: fws_ctx.config |= CTX_CFG_COLLECTOR_2;
150:
151: e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2].addr.sa_family == AF_INET) ? AF_INET : AF_INET6,
152: &fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_2], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
153: if (e) {
154: printf("fwsync collector %d socreate failed #%d\n", e, CFG_SYNC_ADDR_COLLECTOR_2);
155: return e;
156: } else
157: fws_ctx.config |= CTX_COLLECTOR_2_READY;
158: }
159: } else
160: return (EINVAL);
161:
162: return 0;
163: }
164:
165: int
166: fwsync_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
167: {
168: int *n;
169: ipfw_obj_header *oh;
170: size_t sz;
171:
172: DTRACE();
173:
174: sz = sizeof(*oh) + sizeof(int);
175: /* Check minimum header size */
176: if (sd->valsize < sz)
177: return (EINVAL);
178:
179: oh = (ipfw_obj_header*) sd->kbuf;
180:
181: /* Basic length checks for TLVs */
182: if (oh->ntlv.head.length != sizeof(oh->ntlv))
183: return (EINVAL);
184:
185: n = (int*) (oh + 1);
186: if (*n & CFG_SYNC_EDGE) {
1.12 misho 187: if (fws_ctx.config & CTX_EDGE_ONLINE) {
188: ipfw_unregister_state_sync();
189: ipfw_unregister_alias_sync();
190: }
191:
192: callout_drain(&fws_co);
193:
1.1 misho 194: fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
195: fws_cfg.cfg.edge = 0;
196: fws_cfg.cfg.addrs = 0;
197: memset(fws_cfg.cfg_addr, 0, sizeof fws_cfg.cfg_addr[0]);
198:
1.12 misho 199: soshutdown(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SHUT_RD);
200: soclose(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE]);
1.1 misho 201: }
202: if (*n & CFG_SYNC_COLLECTOR) {
203: if (fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE)) {
204: ipfw_unregister_state_hook();
205: ipfw_unregister_alias_hook();
206: }
207:
1.8 misho 208: taskqueue_drain(fws_tq, &fws_sndpkt_task);
209:
1.1 misho 210: fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
211: fws_cfg.cfg.collector = 0;
212: fws_cfg.cfg.addrs = 0;
213: memset(fws_cfg.cfg_addr + 1, 0, sizeof fws_cfg.cfg_addr[0] * 2);
214:
215: if (fws_ctx.config & CTX_COLLECTOR_2_READY)
216: soclose(fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_2]);
217: if (fws_ctx.config & CTX_COLLECTOR_1_READY)
218: soclose(fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_1]);
219: }
220:
221: fws_ctx.config ^= fws_ctx.config;
222:
1.12.2.1 misho 223: memset(&fws_acct, 0, sizeof fws_acct);
224:
1.1 misho 225: return 0;
226: }
227:
228: int
229: fwsync_get_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
230: {
231: ipfw_obj_header *oh;
232: struct ipfw_sync_cfg *ucfg;
233: size_t sz;
234:
235: DTRACE();
236:
237: sz = sizeof(*oh) + sizeof(*ucfg);
238: /* Check minimum header size */
239: if (sd->valsize < sz)
240: return (EINVAL);
241:
242: oh = (struct _ipfw_obj_header*) ipfw_get_sopt_header(sd, sz);
243:
244: /* Basic length checks for TLVs */
245: if (oh->ntlv.head.length != sizeof(oh->ntlv))
246: return (EINVAL);
247:
248: ucfg = (struct ipfw_sync_cfg*) (oh + 1);
249:
250: /* Check if name is properly terminated */
251: if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
252: return (EINVAL);
253:
254: snprintf(ucfg->name, sizeof ucfg->name, "%d", fws_cfg.cfg.on);
255: ucfg->mode = 0;
256: if (fws_cfg.cfg.edge)
257: ucfg->mode |= CFG_SYNC_EDGE;
258: if (fws_cfg.cfg.collector)
259: ucfg->mode |= CFG_SYNC_COLLECTOR;
260: ucfg->addrs = (fws_cfg.cfg.addrs != 1) ? fws_cfg.cfg.addrs : 1;
261: memcpy(ucfg->addr, fws_cfg.cfg_addr, sizeof ucfg->addr);
262:
263: return 0;
264: }
265:
266: int
267: fwsync_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
268: {
1.12.2.2! misho 269: ipfw_obj_header *oh;
! 270: struct ipfw_sync_cfg *ucfg;
! 271: size_t sz;
! 272:
1.1 misho 273: DTRACE();
274:
1.12.2.2! misho 275: sz = sizeof(*oh) + sizeof(*ucfg);
! 276: /* Check minimum header size */
! 277: if (sd->valsize < sz)
! 278: return (EINVAL);
! 279:
! 280: oh = (struct _ipfw_obj_header*) ipfw_get_sopt_header(sd, sz);
! 281:
! 282: /* Basic length checks for TLVs */
! 283: if (oh->ntlv.head.length != sizeof(oh->ntlv))
! 284: return (EINVAL);
! 285:
! 286: ucfg = (struct ipfw_sync_cfg*) (oh + 1);
! 287:
! 288: /* Check if name is properly terminated */
! 289: if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
! 290: return (EINVAL);
! 291:
! 292: ucfg->mode = 0;
! 293: if (fws_cfg.cfg.edge)
! 294: ucfg->mode |= CFG_SYNC_EDGE;
! 295: if (fws_cfg.cfg.collector)
! 296: ucfg->mode |= CFG_SYNC_COLLECTOR;
! 297: ucfg->addrs = 2;
! 298: memcpy(ucfg->addr[0].ip6.sin6_addr.s6_addr, &fws_acct.states[0], sizeof(uint64_t));
! 299: memcpy(ucfg->addr[0].ip6.sin6_addr.s6_addr + 8, &fws_acct.states[1], sizeof(uint64_t));
! 300: memcpy(ucfg->addr[1].ip6.sin6_addr.s6_addr, &fws_acct.aliases[0], sizeof(uint64_t));
! 301: memcpy(ucfg->addr[1].ip6.sin6_addr.s6_addr + 8, &fws_acct.aliases[1], sizeof(uint64_t));
! 302:
1.1 misho 303: return 0;
304: }
305:
306: int
307: fwsync_start(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
308: {
1.7 misho 309: int *n;
1.1 misho 310: ipfw_obj_header *oh;
311: size_t sz;
312:
313: DTRACE();
314:
315: sz = sizeof(*oh) + sizeof(int);
316: /* Check minimum header size */
317: if (sd->valsize < sz)
318: return (EINVAL);
319:
320: oh = (ipfw_obj_header*) sd->kbuf;
321:
322: /* Basic length checks for TLVs */
323: if (oh->ntlv.head.length != sizeof(oh->ntlv))
324: return (EINVAL);
325:
326: n = (int*) (oh + 1);
327:
328: if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
329: fws_cfg.cfg.on |= CFG_SYNC_EDGE;
330:
1.7 misho 331: callout_reset(&fws_co, hz, fwsync_edge_proc, NULL);
1.8 misho 332:
1.9 misho 333: if (!(fws_ctx.config & CTX_EDGE_ONLINE)) {
1.8 misho 334: ipfw_register_state_sync(fwsync_state_sync);
1.9 misho 335: ipfw_register_alias_sync(fwsync_alias_sync);
336: }
1.8 misho 337:
338: fws_ctx.config |= CTX_EDGE_ONLINE;
1.1 misho 339: }
340:
341: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_READY)) {
342: fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
343:
344: if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
345: ipfw_register_state_hook(fwsync_state_handler);
346: ipfw_register_alias_hook(fwsync_alias_handler);
347: }
348:
349: fws_ctx.config |= CTX_COLLECTOR_1_ONLINE;
350: }
351:
352: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_READY)) {
353: fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
354:
355: if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
356: ipfw_register_state_hook(fwsync_state_handler);
357: ipfw_register_alias_hook(fwsync_alias_handler);
358: }
359:
360: fws_ctx.config |= CTX_COLLECTOR_2_ONLINE;
361: }
362:
363: return 0;
364: }
365:
366: int
367: fwsync_stop(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
368: {
369: int *n;
370: ipfw_obj_header *oh;
371: size_t sz;
372:
373: DTRACE();
374:
375: sz = sizeof(*oh) + sizeof(int);
376: /* Check minimum header size */
377: if (sd->valsize < sz)
378: return (EINVAL);
379:
380: oh = (ipfw_obj_header*) sd->kbuf;
381:
382: /* Basic length checks for TLVs */
383: if (oh->ntlv.head.length != sizeof(oh->ntlv))
384: return (EINVAL);
385:
386: n = (int*) (oh + 1);
387:
1.7 misho 388: if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_CFG_EDGE)) {
1.1 misho 389: fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
1.7 misho 390: fws_ctx.config &= ~CTX_EDGE_ONLINE;
391:
392: callout_drain(&fws_co);
1.8 misho 393:
394: ipfw_unregister_state_sync();
1.9 misho 395: ipfw_unregister_alias_sync();
1.7 misho 396: }
1.1 misho 397:
398: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_ONLINE))
399: fws_ctx.config &= ~CTX_COLLECTOR_2_ONLINE;
400: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_ONLINE))
401: fws_ctx.config &= ~CTX_COLLECTOR_1_ONLINE;
402:
403: if ((*n & CFG_SYNC_COLLECTOR) &&
404: !(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
405: fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
406:
407: ipfw_unregister_state_hook();
408: ipfw_unregister_alias_hook();
1.8 misho 409:
410: taskqueue_drain(fws_tq, &fws_sndpkt_task);
1.1 misho 411: }
412:
413: return 0;
414: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>