File:  [ELWIX - Embedded LightWeight unIX -] / fwsync / driver / fwsync.c
Revision 1.12: download - view: text, annotated - select for diffs - revision graph
Tue Aug 23 14:34:42 2022 UTC (21 months, 1 week ago) by misho
Branches: MAIN
CVS tags: fwsync1_1, HEAD
fix bug with edge port cleaning on flush command

    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:  */
   27: #include "fwsync.h"
   28: 
   29: 
   30: static void
   31: fwsync_edge_proc(void *arg)
   32: {
   33: 	int e, rcvflg = 0;
   34: 	struct uio uio;
   35: 	struct mbuf *m = NULL;
   36: 	struct fws_proto *pkt;
   37: 
   38: 	DTRACE();
   39: 
   40: 	callout_schedule(&fws_co, hz);
   41: 
   42: 	memset(&uio, 0, sizeof uio);
   43: 	uio.uio_resid = 1000000000;
   44: 	uio.uio_td = curthread;
   45: 
   46: 	if ((fws_cfg.cfg.on & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
   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);
   52: 			return;
   53: 		}
   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));
   58: 			m_freem(m);
   59: 			return;
   60: 		}
   61: 
   62: 		switch (pkt->fws_version) {
   63: 			case FWS_PKTVER_STATE:
   64: 				fwsync_add_state(pkt);
   65: 				break;
   66: 			case FWS_PKTVER_ALIAS:
   67: 				fwsync_add_alias(pkt);
   68: 				break;
   69: 			default:
   70: 				printf("FWSync packet was discarded due to wrong version\n");
   71: 				break;
   72: 		}
   73: 
   74: 		m_freem(m);
   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) {
  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: 
  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: 
  199: 		soshutdown(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SHUT_RD);
  200: 		soclose(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE]);
  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: 
  208: 		taskqueue_drain(fws_tq, &fws_sndpkt_task);
  209: 
  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: {
  275: 	int *n;
  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: 
  297: 		callout_reset(&fws_co, hz, fwsync_edge_proc, NULL);
  298: 
  299: 		if (!(fws_ctx.config & CTX_EDGE_ONLINE)) {
  300: 			ipfw_register_state_sync(fwsync_state_sync);
  301: 			ipfw_register_alias_sync(fwsync_alias_sync);
  302: 		}
  303: 
  304: 		fws_ctx.config |= CTX_EDGE_ONLINE;
  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: 
  354: 	if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_CFG_EDGE)) {
  355: 		fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
  356: 		fws_ctx.config &= ~CTX_EDGE_ONLINE;
  357: 
  358: 		callout_drain(&fws_co);
  359: 
  360: 		ipfw_unregister_state_sync();
  361: 		ipfw_unregister_alias_sync();
  362: 	}
  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();
  375: 
  376: 		taskqueue_drain(fws_tq, &fws_sndpkt_task);
  377: 	}
  378: 
  379: 	return 0;
  380: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>