Annotation of fwsync/driver/fwsync.c, revision 1.12
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:
223: return 0;
224: }
225:
226: int
227: fwsync_get_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
228: {
229: ipfw_obj_header *oh;
230: struct ipfw_sync_cfg *ucfg;
231: size_t sz;
232:
233: DTRACE();
234:
235: sz = sizeof(*oh) + sizeof(*ucfg);
236: /* Check minimum header size */
237: if (sd->valsize < sz)
238: return (EINVAL);
239:
240: oh = (struct _ipfw_obj_header*) ipfw_get_sopt_header(sd, sz);
241:
242: /* Basic length checks for TLVs */
243: if (oh->ntlv.head.length != sizeof(oh->ntlv))
244: return (EINVAL);
245:
246: ucfg = (struct ipfw_sync_cfg*) (oh + 1);
247:
248: /* Check if name is properly terminated */
249: if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
250: return (EINVAL);
251:
252: snprintf(ucfg->name, sizeof ucfg->name, "%d", fws_cfg.cfg.on);
253: ucfg->mode = 0;
254: if (fws_cfg.cfg.edge)
255: ucfg->mode |= CFG_SYNC_EDGE;
256: if (fws_cfg.cfg.collector)
257: ucfg->mode |= CFG_SYNC_COLLECTOR;
258: ucfg->addrs = (fws_cfg.cfg.addrs != 1) ? fws_cfg.cfg.addrs : 1;
259: memcpy(ucfg->addr, fws_cfg.cfg_addr, sizeof ucfg->addr);
260:
261: return 0;
262: }
263:
264: int
265: fwsync_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
266: {
267: DTRACE();
268:
269: return 0;
270: }
271:
272: int
273: fwsync_start(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
274: {
1.7 misho 275: int *n;
1.1 misho 276: ipfw_obj_header *oh;
277: size_t sz;
278:
279: DTRACE();
280:
281: sz = sizeof(*oh) + sizeof(int);
282: /* Check minimum header size */
283: if (sd->valsize < sz)
284: return (EINVAL);
285:
286: oh = (ipfw_obj_header*) sd->kbuf;
287:
288: /* Basic length checks for TLVs */
289: if (oh->ntlv.head.length != sizeof(oh->ntlv))
290: return (EINVAL);
291:
292: n = (int*) (oh + 1);
293:
294: if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
295: fws_cfg.cfg.on |= CFG_SYNC_EDGE;
296:
1.7 misho 297: callout_reset(&fws_co, hz, fwsync_edge_proc, NULL);
1.8 misho 298:
1.9 misho 299: if (!(fws_ctx.config & CTX_EDGE_ONLINE)) {
1.8 misho 300: ipfw_register_state_sync(fwsync_state_sync);
1.9 misho 301: ipfw_register_alias_sync(fwsync_alias_sync);
302: }
1.8 misho 303:
304: fws_ctx.config |= CTX_EDGE_ONLINE;
1.1 misho 305: }
306:
307: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_READY)) {
308: fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
309:
310: if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
311: ipfw_register_state_hook(fwsync_state_handler);
312: ipfw_register_alias_hook(fwsync_alias_handler);
313: }
314:
315: fws_ctx.config |= CTX_COLLECTOR_1_ONLINE;
316: }
317:
318: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_READY)) {
319: fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
320:
321: if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
322: ipfw_register_state_hook(fwsync_state_handler);
323: ipfw_register_alias_hook(fwsync_alias_handler);
324: }
325:
326: fws_ctx.config |= CTX_COLLECTOR_2_ONLINE;
327: }
328:
329: return 0;
330: }
331:
332: int
333: fwsync_stop(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
334: {
335: int *n;
336: ipfw_obj_header *oh;
337: size_t sz;
338:
339: DTRACE();
340:
341: sz = sizeof(*oh) + sizeof(int);
342: /* Check minimum header size */
343: if (sd->valsize < sz)
344: return (EINVAL);
345:
346: oh = (ipfw_obj_header*) sd->kbuf;
347:
348: /* Basic length checks for TLVs */
349: if (oh->ntlv.head.length != sizeof(oh->ntlv))
350: return (EINVAL);
351:
352: n = (int*) (oh + 1);
353:
1.7 misho 354: if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_CFG_EDGE)) {
1.1 misho 355: fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
1.7 misho 356: fws_ctx.config &= ~CTX_EDGE_ONLINE;
357:
358: callout_drain(&fws_co);
1.8 misho 359:
360: ipfw_unregister_state_sync();
1.9 misho 361: ipfw_unregister_alias_sync();
1.7 misho 362: }
1.1 misho 363:
364: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_ONLINE))
365: fws_ctx.config &= ~CTX_COLLECTOR_2_ONLINE;
366: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_ONLINE))
367: fws_ctx.config &= ~CTX_COLLECTOR_1_ONLINE;
368:
369: if ((*n & CFG_SYNC_COLLECTOR) &&
370: !(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
371: fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
372:
373: ipfw_unregister_state_hook();
374: ipfw_unregister_alias_hook();
1.8 misho 375:
376: taskqueue_drain(fws_tq, &fws_sndpkt_task);
1.1 misho 377: }
378:
379: return 0;
380: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>