File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / ngfunc.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    1: 
    2: /*
    3:  * ngfunc.c
    4:  *
    5:  * Written by Archie Cobbs <archie@freebsd.org>
    6:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
    7:  * See ``COPYRIGHT.whistle''
    8:  *
    9:  * TCP MSSFIX contributed by Sergey Korolew <dsATbittu.org.ru>
   10:  *
   11:  * Routines for doing netgraph stuff
   12:  *
   13:  */
   14: 
   15: #include "defs.h"
   16: #include "ppp.h"
   17: #include "bund.h"
   18: #include "ngfunc.h"
   19: #include "input.h"
   20: #include "ccp.h"
   21: #include "netgraph.h"
   22: #include "command.h"
   23: #include "util.h"
   24: 
   25: #ifdef USE_NG_BPF
   26: #include <net/bpf.h>
   27: #endif
   28: #include <arpa/inet.h>
   29: 
   30: #include <netgraph/ng_message.h>
   31: 
   32: #include <netgraph/ng_socket.h>
   33: #include <netgraph/ng_ksocket.h>
   34: #include <netgraph/ng_iface.h>
   35: #ifdef USE_NG_VJC
   36: #include <netgraph/ng_vjc.h>
   37: #endif
   38: #ifdef USE_NG_BPF
   39: #include <netgraph/ng_bpf.h>
   40: #endif
   41: #include <netgraph/ng_tee.h>
   42: #ifdef USE_NG_TCPMSS
   43: #include <netgraph/ng_tcpmss.h>
   44: #endif
   45: #ifdef USE_NG_NETFLOW
   46: #include <netgraph/netflow/ng_netflow.h>
   47: #include <netgraph/netflow/netflow.h>
   48: #if NGM_NETFLOW_COOKIE >= 1309868867
   49: #include <netgraph/netflow/netflow_v9.h>
   50: #endif
   51: #endif
   52: #ifdef USE_NG_PRED1
   53: #include <netgraph/ng_pred1.h>
   54: #endif
   55: 
   56: #include <netinet/ip_icmp.h>
   57: #include <netinet/tcp.h>
   58: 
   59: /*
   60:  * DEFINITIONS
   61:  */
   62: 
   63:   #define TEMPHOOK		"temphook"
   64:   #define MAX_IFACE_CREATE	128
   65: 
   66:   /* Set menu options */
   67:   enum {
   68:     SET_PEER,
   69:     SET_SELF,
   70:     SET_TIMEOUTS,
   71: #if NGM_NETFLOW_COOKIE >= 1309868867
   72:     SET_TEMPLATE,
   73:     SET_MTU,
   74:     SET_VERSION,
   75: #endif
   76:     SET_NODE,
   77:     SET_HOOK
   78:   };
   79: 
   80: /*
   81:  * INTERNAL FUNCTIONS
   82:  */
   83: 
   84: #ifdef USE_NG_NETFLOW
   85:   static int	NetflowSetCommand(Context ctx, int ac, char *av[], void *arg);
   86: #endif
   87: 
   88: /*
   89:  * GLOBAL VARIABLES
   90:  */
   91: 
   92: #ifdef USE_NG_NETFLOW
   93:   const struct cmdtab NetflowSetCmds[] = {
   94:     { "peer {ip} {port}",	"Set export destination" ,
   95:         NetflowSetCommand, NULL, 2, (void *) SET_PEER },
   96:     { "self {ip} [{port}]",	"Set export source" ,
   97:         NetflowSetCommand, NULL, 2, (void *) SET_SELF },
   98:     { "timeouts {inactive} {active}", "Set NetFlow timeouts" ,
   99:         NetflowSetCommand, NULL, 2, (void *) SET_TIMEOUTS },
  100: #if NGM_NETFLOW_COOKIE >= 1309868867
  101:     { "template {time} {packets}", "Set NetFlow v9 template" ,
  102:         NetflowSetCommand, NULL, 2, (void *) SET_TEMPLATE },
  103:     { "mtu {mtu}", "Set NetFlow v9 MTU" ,
  104:         NetflowSetCommand, NULL, 2, (void *) SET_MTU },
  105:     { "version {version}", "Set version to export" ,
  106:         NetflowSetCommand, NULL, 2, (void *) SET_VERSION },
  107: #endif
  108:     { "node {name}", "Set node name to use" ,
  109:         NetflowSetCommand, NULL, 2, (void *) SET_NODE },
  110:     { "hook {number}", "Set initial hook number" ,
  111:         NetflowSetCommand, NULL, 2, (void *) SET_HOOK },
  112:     { NULL },
  113:   };
  114: #endif
  115: 
  116: /*
  117:  * INTERNAL VARIABLES
  118:  */
  119: 
  120: #ifdef USE_NG_TCPMSS
  121:   u_char gTcpMSSNode = FALSE;
  122: #endif
  123: #ifdef USE_NG_NETFLOW
  124:   u_char gNetflowNode = FALSE;
  125:   u_char gNetflowNodeShutdown = TRUE;
  126:   char gNetflowNodeName[64] = "mpd-nf";
  127:   ng_ID_t gNetflowNodeID = 0;
  128:   u_int gNetflowIface = 0;
  129:   struct sockaddr_storage gNetflowExport;
  130:   struct sockaddr_storage gNetflowSource;
  131:   uint32_t gNetflowInactive = 0;
  132:   uint32_t gNetflowActive = 0;
  133: #if NGM_NETFLOW_COOKIE >= 1309868867
  134:   uint16_t gNetflowTime = 0;
  135:   uint16_t gNetflowPackets = 0;
  136:   uint16_t gNetflowMTU = 0;
  137:   u_int gNetflowVer = 5;
  138: #endif
  139: #endif
  140:   
  141:   static int	gNgStatSock=0;
  142: 
  143: 
  144: #ifdef USE_NG_NETFLOW
  145: int
  146: NgFuncInitGlobalNetflow(void)
  147: {
  148:     char		path[NG_PATHSIZ];
  149:     struct ngm_mkpeer	mp;
  150:     struct ngm_rmhook	rm;
  151:     struct ngm_name	nm;
  152:     int			csock;
  153: 
  154:     /* Create a netgraph socket node */
  155:     if (NgMkSockNode(NULL, &csock, NULL) < 0) {
  156: 	Perror("NETFLOW: Can't create %s node", NG_SOCKET_NODE_TYPE);
  157:         return (-1);
  158:     }
  159: 
  160:     /* If node exist just get it's ID. */
  161:     if (gNetflowNode) {
  162: 	snprintf(path, sizeof(path), "%s:", gNetflowNodeName);
  163: 	gNetflowNodeID = NgGetNodeID(csock, path);
  164: 	close(csock);
  165: 	return (0);
  166:     }
  167: 
  168:     snprintf(gNetflowNodeName, sizeof(gNetflowNodeName), "mpd%d-nf", gPid);
  169: 
  170:     /* Create a global netflow node. */
  171:     strcpy(mp.type, NG_NETFLOW_NODE_TYPE);
  172:     strcpy(mp.ourhook, TEMPHOOK);
  173:     strcpy(mp.peerhook, NG_NETFLOW_HOOK_DATA "0");
  174:     if (NgSendMsg(csock, ".:",
  175:       NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
  176: 	Perror("NETFLOW: Can't create %s node at \"%s\"->\"%s\"", 
  177: 	    mp.type, ".:", mp.ourhook);
  178: 	goto fail;
  179:     }
  180:     
  181:     /* Get new node ID. */
  182:     gNetflowNodeID = NgGetNodeID(csock, TEMPHOOK);
  183: 
  184:     /* Set the new node's name. */
  185:     strcpy(nm.name, gNetflowNodeName);
  186:     if (NgSendMsg(csock, TEMPHOOK,
  187:       NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
  188: 	Perror("NETFLOW: Can't name %s node", NG_NETFLOW_NODE_TYPE);
  189: 	goto fail;
  190:     }
  191: 
  192:     /* Connect ng_ksocket(4) node for export. */
  193:     strcpy(mp.type, NG_KSOCKET_NODE_TYPE);
  194: #if NGM_NETFLOW_COOKIE >= 1309868867
  195:     if (gNetflowVer == 5) {
  196: #endif
  197: 	strcpy(mp.ourhook, NG_NETFLOW_HOOK_EXPORT);
  198: #if NGM_NETFLOW_COOKIE >= 1309868867
  199:     } else {
  200: 	strcpy(mp.ourhook, NG_NETFLOW_HOOK_EXPORT9);
  201:     }
  202: #endif
  203:     if (gNetflowExport.ss_family==AF_INET6) {
  204: 	snprintf(mp.peerhook, sizeof(mp.peerhook), "%d/%d/%d", PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  205:     } else {
  206:         snprintf(mp.peerhook, sizeof(mp.peerhook), "inet/dgram/udp");
  207:     }
  208:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
  209:     if (NgSendMsg(csock, path,
  210:       NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
  211: 	Perror("NETFLOW: Can't create %s node at \"%s\"->\"%s\"",
  212: 	    mp.type, path, mp.ourhook);
  213: 	goto fail;
  214:     }
  215: 
  216:     /* Configure timeouts for ng_netflow(4). */
  217:     if (gNetflowInactive != 0 && gNetflowActive != 0) {
  218: 	struct ng_netflow_settimeouts nf_settime;
  219: 
  220: 	nf_settime.inactive_timeout = gNetflowInactive;
  221: 	nf_settime.active_timeout = gNetflowActive;
  222: 
  223: 	if (NgSendMsg(csock, path, NGM_NETFLOW_COOKIE,
  224: 	  NGM_NETFLOW_SETTIMEOUTS, &nf_settime, sizeof(nf_settime)) < 0) {
  225: 	    Perror("NETFLOW: Can't set timeouts on netflow %s node",
  226: 		NG_NETFLOW_NODE_TYPE);
  227: 	    goto fail2;
  228: 	}
  229:     }
  230: 
  231: #if NGM_NETFLOW_COOKIE >= 1309868867
  232:     if (gNetflowTime != 0 && gNetflowPackets != 0) {
  233: 	struct ng_netflow_settemplate nf_settempl;
  234: 
  235: 	nf_settempl.time = gNetflowTime;
  236: 	nf_settempl.packets = gNetflowPackets;
  237: 	if (NgSendMsg(csock, path, NGM_NETFLOW_COOKIE,
  238: 	  NGM_NETFLOW_SETTEMPLATE, &nf_settempl, sizeof(nf_settempl)) < 0) {
  239: 	    Perror("NETFLOW: Can't set NetFlow v9 template on netflow %s node",
  240: 		NG_NETFLOW_NODE_TYPE);
  241: 	    goto fail2;
  242: 	}
  243:     }
  244: 
  245:     if (gNetflowMTU != 0) {
  246: 	struct ng_netflow_setmtu nf_setmtu;
  247: 
  248: 	nf_setmtu.mtu = gNetflowMTU;
  249: 	if (NgSendMsg(csock, path, NGM_NETFLOW_COOKIE,
  250: 	  NGM_NETFLOW_SETMTU, &nf_setmtu, sizeof(nf_setmtu)) < 0) {
  251: 	    Perror("NETFLOW: Can't set NetFlow v9 MTU on netflow %s node",
  252: 		NG_NETFLOW_NODE_TYPE);
  253: 	  goto fail2;
  254: 	}
  255:     }
  256: #endif
  257: 
  258:     /* Configure export destination and source on ng_ksocket(4). */
  259: #if NGM_NETFLOW_COOKIE >= 1309868867
  260:     if (gNetflowVer == 5) {
  261: #endif
  262: 	strlcat(path, NG_NETFLOW_HOOK_EXPORT, sizeof(path));
  263: #if NGM_NETFLOW_COOKIE >= 1309868867
  264:     } else {
  265: 	strlcat(path, NG_NETFLOW_HOOK_EXPORT9, sizeof(path));
  266:     }
  267: #endif
  268:     if (gNetflowSource.ss_len != 0) {
  269: 	if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
  270: 	  NGM_KSOCKET_BIND, &gNetflowSource, sizeof(gNetflowSource)) < 0) {
  271: 	    Perror("NETFLOW: Can't bind export %s node", NG_KSOCKET_NODE_TYPE);
  272: 	    goto fail2;
  273: 	}
  274:     }
  275:     if (gNetflowExport.ss_len != 0) {
  276: 	if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
  277: 	  NGM_KSOCKET_CONNECT, &gNetflowExport, sizeof(gNetflowExport)) < 0) {
  278: 	    Perror("NETFLOW: Can't connect export %s node", NG_KSOCKET_NODE_TYPE);
  279: 	    goto fail2;
  280: 	}
  281:     }
  282: 
  283:     /* Set the new node's name. */
  284:     snprintf(nm.name, sizeof(nm.name), "mpd%d-nfso", gPid);
  285:     if (NgSendMsg(csock, path,
  286:       NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
  287: 	Perror("NETFLOW: Can't name %s node", NG_KSOCKET_NODE_TYPE);
  288: 	goto fail2;
  289:     }
  290: 
  291:     /* Disconnect temporary hook. */
  292:     memset(&rm, 0, sizeof(rm));
  293:     strncpy(rm.ourhook, TEMPHOOK, sizeof(rm.ourhook));
  294:     if (NgSendMsg(csock, ".:",
  295:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
  296: 	Perror("can't remove hook %s", TEMPHOOK);
  297: 	goto fail2;
  298:     }
  299:     gNetflowNode = TRUE;
  300:     close(csock);
  301: 
  302:     return (0);
  303: fail2:
  304:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
  305:     NgFuncShutdownNode(csock, "netflow", path);
  306: fail:
  307:     gNetflowNodeID = 0;
  308:     close(csock);
  309:     return (-1);
  310: }
  311: #endif
  312: 
  313: /*
  314:  * NgFuncCreateIface()
  315:  *
  316:  * Create a new netgraph interface.
  317:  */
  318: 
  319: int
  320: NgFuncCreateIface(Bund b, char *buf, int max)
  321: {
  322:     union {
  323:         u_char		buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
  324:         struct ng_mesg	reply;
  325:     }			u;
  326:     struct nodeinfo	*const ni = (struct nodeinfo *)(void *)u.reply.data;
  327:     struct ngm_rmhook	rm;
  328:     struct ngm_mkpeer	mp;
  329:     int			rtn = 0;
  330: 
  331:     /* Create iface node (as a temporary peer of the socket node) */
  332:     strcpy(mp.type, NG_IFACE_NODE_TYPE);
  333:     strcpy(mp.ourhook, TEMPHOOK);
  334:     strcpy(mp.peerhook, NG_IFACE_HOOK_INET);
  335:     if (NgSendMsg(gLinksCsock, ".:",
  336:       NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
  337: 	Log(LG_ERR, ("[%s] can't create %s node at \"%s\"->\"%s\": %s %d",
  338:     	    b->name, NG_IFACE_NODE_TYPE, ".:", mp.ourhook, strerror(errno), gLinksCsock));
  339: 	return(-1);
  340:     }
  341: 
  342:     /* Get the new node's name */
  343:     if (NgSendMsg(gLinksCsock, TEMPHOOK,
  344:       NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) {
  345: 	Perror("[%s] %s", b->name, "NGM_NODEINFO");
  346: 	rtn = -1;
  347: 	goto done;
  348:     }
  349:     if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
  350: 	Perror("[%s] reply from %s", b->name, NG_IFACE_NODE_TYPE);
  351: 	rtn = -1;
  352: 	goto done;
  353:     }
  354:     strlcpy(buf, ni->name, max);
  355: 
  356: done:
  357:     /* Disconnect temporary hook */
  358:     strcpy(rm.ourhook, TEMPHOOK);
  359:     if (NgSendMsg(gLinksCsock, ".:",
  360:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
  361: 	Perror("[%s] can't remove hook %s", b->name, TEMPHOOK);
  362: 	rtn = -1;
  363:     }
  364: 
  365:     /* Done */
  366:     return(rtn);
  367: }
  368: 
  369: /*
  370:  * NgFuncShutdownGlobal()
  371:  *
  372:  * Shutdown nodes, that are shared between bundles.
  373:  */
  374: 
  375: void
  376: NgFuncShutdownGlobal(void)
  377: {
  378: #ifdef USE_NG_NETFLOW
  379:     char	path[NG_PATHSIZ];
  380:     int		csock;
  381: 
  382:     if (gNetflowNode == FALSE || gNetflowNodeShutdown==FALSE)
  383: 	return;
  384: 
  385:     /* Create a netgraph socket node */
  386:     if (NgMkSockNode(NULL, &csock, NULL) < 0) {
  387: 	Perror("NgFuncShutdownGlobal: can't create %s node", NG_SOCKET_NODE_TYPE);
  388: 	return;
  389:     }
  390: 
  391:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
  392:     NgFuncShutdownNode(csock, "netflow", path);
  393:     
  394:     close(csock);
  395: #endif
  396: }
  397: 
  398: /*
  399:  * NgFuncShutdownNode()
  400:  */
  401: 
  402: int
  403: NgFuncShutdownNode(int csock, const char *label, const char *path)
  404: {
  405:     int rtn, retry = 10, delay = 1000;
  406: 
  407: retry:
  408:     if ((rtn = NgSendMsg(csock, path,
  409:       NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0)) < 0) {
  410: 	if (errno == ENOBUFS && retry > 0) {
  411:     	    Log(LG_ERR, ("[%s] shutdown \"%s\": %s, retrying...",
  412: 	      label, path, strerror(errno)));
  413: 	    usleep(delay);
  414: 	    retry--;
  415: 	    delay *= 2;
  416: 	    goto retry;
  417: 	}
  418: 	if (errno != ENOENT) {
  419: 	    Perror("[%s] can't shutdown \"%s\"", label, path);
  420: 	}
  421:     }
  422:     return(rtn);
  423: }
  424: 
  425: /*
  426:  * NgFuncSetConfig()
  427:  */
  428: 
  429: void
  430: NgFuncSetConfig(Bund b)
  431: {
  432:     char	path[NG_PATHSIZ];
  433:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
  434:     if (NgSendMsg(gLinksCsock, path, NGM_PPP_COOKIE,
  435:     	    NGM_PPP_SET_CONFIG, &b->pppConfig, sizeof(b->pppConfig)) < 0) {
  436: 	Perror("[%s] can't config %s", b->name, path);
  437: 	DoExit(EX_ERRDEAD);
  438:     }
  439: }
  440: 
  441: /*
  442:  * NgFuncSendQuery()
  443:  */
  444: 
  445: int
  446: NgFuncSendQuery(const char *path, int cookie, int cmd, const void *args,
  447: 	size_t arglen, struct ng_mesg *rbuf, size_t replen, char *raddr)
  448: {
  449: 
  450:     if (!gNgStatSock) {
  451: 	char		name[NG_NODESIZ];
  452: 	
  453: 	/* Create a netgraph socket node */
  454: 	snprintf(name, sizeof(name), "mpd%d-stats", gPid);
  455: 	if (NgMkSockNode(name, &gNgStatSock, NULL) < 0) {
  456: 	    Perror("NgFuncSendQuery: can't create %s node", NG_SOCKET_NODE_TYPE);
  457: 	    return(-1);
  458: 	}
  459: 	(void) fcntl(gNgStatSock, F_SETFD, 1);
  460:     }
  461: 
  462:     /* Send message */
  463:     if (NgSendMsg(gNgStatSock, path, cookie, cmd, args, arglen) < 0) {
  464: 	Perror("NgFuncSendQuery: can't send message");
  465: 	return (-1);
  466:     }
  467: 
  468:     /* Read message */
  469:     if (NgRecvMsg(gNgStatSock, rbuf, replen, raddr) < 0) {
  470: 	Perror("NgFuncSendQuery: can't read unexpected message");
  471: 	return (-1);
  472:     }
  473: 
  474:     return (0);
  475: }
  476: 
  477: /*
  478:  * NgFuncConnect()
  479:  */
  480: 
  481: int
  482: NgFuncConnect(int csock, char *label, const char *path, const char *hook,
  483: 	const char *path2, const char *hook2)
  484: {
  485:     struct ngm_connect	cn;
  486: 
  487:     strlcpy(cn.path, path2, sizeof(cn.path));
  488:     strlcpy(cn.ourhook, hook, sizeof(cn.ourhook));
  489:     strlcpy(cn.peerhook, hook2, sizeof(cn.peerhook));
  490:     if (NgSendMsg(csock, path,
  491:       NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
  492: 	Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
  493: 	    label, path, hook, path2, hook2);
  494: 	return(-1);
  495:     }
  496:     return(0);
  497: }
  498: 
  499: /*
  500:  * NgFuncDisconnect()
  501:  */
  502: 
  503: int
  504: NgFuncDisconnect(int csock, char *label, const char *path, const char *hook)
  505: {
  506:     struct ngm_rmhook	rm;
  507:     int		retry = 10, delay = 1000;
  508: 
  509:     /* Disconnect hook */
  510:     memset(&rm, 0, sizeof(rm));
  511:     strlcpy(rm.ourhook, hook, sizeof(rm.ourhook));
  512: retry:
  513:     if (NgSendMsg(csock, path,
  514:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
  515: 	if (errno == ENOBUFS && retry > 0) {
  516:     	    Log(LG_ERR, ("[%s] remove hook %s from node \"%s\": %s, retrying...",
  517: 	      label, hook, path, strerror(errno)));
  518: 	    usleep(delay);
  519: 	    retry--;
  520: 	    delay *= 2;
  521: 	    goto retry;
  522: 	}
  523: 	Perror("[%s] can't remove hook %s from node \"%s\"", label, hook, path);
  524: 	return(-1);
  525:     }
  526:     return(0);
  527: }
  528: 
  529: /*
  530:  * NgFuncWritePppFrame()
  531:  *
  532:  * Consumes the mbuf.
  533:  */
  534: 
  535: int
  536: NgFuncWritePppFrame(Bund b, int linkNum, int proto, Mbuf bp)
  537: {
  538:     u_int16_t	temp;
  539: 
  540:     /* Prepend ppp node bypass header */
  541:     temp = htons(linkNum);
  542:     bp = mbcopyback(bp, -4, &temp, 2);
  543:     temp = htons(proto);
  544:     bp = mbcopyback(bp, 2, &temp, 2);
  545: 
  546:     /* Debugging */
  547:     LogDumpBp(LG_FRAME, bp,
  548: 	"[%s] xmit bypass frame link=%d proto=0x%04x",
  549: 	b->name, (int16_t)linkNum, proto);
  550: 
  551:     if ((linkNum == NG_PPP_BUNDLE_LINKNUM && b->n_up == 0) ||
  552: 	(linkNum != NG_PPP_BUNDLE_LINKNUM &&
  553: 	    (b->links[linkNum] == NULL ||
  554: 	    b->links[linkNum]->state != PHYS_STATE_UP))) {
  555: 	Log(LG_FRAME, ("[%s] Bundle: No links ready to send packet", b->name));
  556: 	mbfree(bp);
  557: 	return (-1);
  558:     }
  559: 
  560:     /* Write frame */
  561:     return NgFuncWriteFrame(gLinksDsock, b->hook, b->name, bp);
  562: }
  563: 
  564: /*
  565:  * NgFuncWritePppFrameLink()
  566:  *
  567:  * Consumes the mbuf.
  568:  */
  569: 
  570: int
  571: NgFuncWritePppFrameLink(Link l, int proto, Mbuf bp)
  572: {
  573:     u_int16_t	temp;
  574: 
  575:     if (l->joined_bund) {
  576: 	return (NgFuncWritePppFrame(l->bund, l->bundleIndex, proto, bp));
  577:     }
  578: 
  579:     /* Prepend framing */
  580:     temp = htons(0xff03);
  581:     bp = mbcopyback(bp, -4, &temp, 2);
  582:     temp = htons(proto);
  583:     bp = mbcopyback(bp, 2, &temp, 2);
  584: 
  585:     /* Debugging */
  586:     LogDumpBp(LG_FRAME, bp,
  587: 	"[%s] xmit frame to link proto=0x%04x",
  588: 	l->name, proto);
  589: 
  590:     if (l->state != PHYS_STATE_UP) {
  591: 	Log(LG_FRAME, ("[%s] Link: Not ready to send packet", l->name));
  592: 	mbfree(bp);
  593: 	return (-1);
  594:     }
  595: 
  596:     /* Write frame */
  597:     return NgFuncWriteFrame(gLinksDsock, l->hook, l->name, bp);
  598: }
  599: 
  600: /*
  601:  * NgFuncWriteFrame()
  602:  *
  603:  * Consumes the mbuf.
  604:  */
  605: 
  606: int
  607: NgFuncWriteFrame(int dsock, const char *hookname, const char *label, Mbuf bp)
  608: {
  609:     union {
  610:         u_char          buf[sizeof(struct sockaddr_ng) + NG_HOOKSIZ];
  611: 	struct sockaddr_ng sa_ng;
  612:     }                   u;
  613:     struct sockaddr_ng	*ng = &u.sa_ng;
  614:     int			rtn;
  615: 
  616:     /* Write frame */
  617:     if (bp == NULL)  
  618: 	return (-1);
  619: 
  620:     /* Set dest address */
  621:     memset(&u.buf, 0, sizeof(u.buf));
  622:     strlcpy(ng->sg_data, hookname, NG_HOOKSIZ);
  623:     ng->sg_family = AF_NETGRAPH;
  624:     ng->sg_len = 3 + strlen(ng->sg_data);
  625: 
  626:     rtn = sendto(dsock, MBDATAU(bp), MBLEN(bp),
  627: 	0, (struct sockaddr *)ng, ng->sg_len);
  628: 
  629:     /* ENOBUFS can be expected on some links, e.g., ng_pptpgre(4) */
  630:     if (rtn < 0 && errno != ENOBUFS) {
  631: 	Perror("[%s] error writing len %d frame to %s",
  632: 	    label, (int)MBLEN(bp), hookname);
  633:     }
  634:     mbfree(bp);
  635:     return (rtn);
  636: }
  637: 
  638: /*
  639:  * NgFuncClrStats()
  640:  *
  641:  * Clear link or whole bundle statistics
  642:  */
  643: 
  644: int
  645: NgFuncClrStats(Bund b, u_int16_t linkNum)
  646: {
  647:     char	path[NG_PATHSIZ];
  648: 
  649:     /* Get stats */
  650:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
  651:     if (NgSendMsg(gLinksCsock, path, 
  652: 	NGM_PPP_COOKIE, NGM_PPP_CLR_LINK_STATS, &linkNum, sizeof(linkNum)) < 0) {
  653: 	    Perror("[%s] can't clear stats, link=%d", b->name, linkNum);
  654: 	    return (-1);
  655:     }
  656:     return(0);
  657: }
  658: 
  659: /*
  660:  * NgFuncGetStats()
  661:  *
  662:  * Get link or whole bundle statistics
  663:  */
  664: 
  665: int
  666: NgFuncGetStats(Bund b, u_int16_t linkNum, struct ng_ppp_link_stat *statp)
  667: {
  668:     union {
  669:         u_char			buf[sizeof(struct ng_mesg)
  670: 				  + sizeof(struct ng_ppp_link_stat)];
  671:         struct ng_mesg		reply;
  672:     }				u;
  673:     char			path[NG_PATHSIZ];
  674: 
  675:     /* Get stats */
  676:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
  677:     if (NgFuncSendQuery(path, NGM_PPP_COOKIE, NGM_PPP_GET_LINK_STATS,
  678:       &linkNum, sizeof(linkNum), &u.reply, sizeof(u), NULL) < 0) {
  679: 	Perror("[%s] can't get stats, link=%d", b->name, linkNum);
  680: 	return -1;
  681:     }
  682:     if (statp != NULL)
  683: 	memcpy(statp, u.reply.data, sizeof(*statp));
  684:     return(0);
  685: }
  686: 
  687: #ifdef NG_PPP_STATS64
  688: /*
  689:  * NgFuncGetStats64()
  690:  *
  691:  * Get 64bit link or whole bundle statistics
  692:  */
  693: 
  694: int
  695: NgFuncGetStats64(Bund b, u_int16_t linkNum, struct ng_ppp_link_stat64 *statp)
  696: {
  697:     union {
  698:         u_char			buf[sizeof(struct ng_mesg)
  699: 				  + sizeof(struct ng_ppp_link_stat64)];
  700:         struct ng_mesg		reply;
  701:     }				u;
  702:     char			path[NG_PATHSIZ];
  703: 
  704:     /* Get stats */
  705:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
  706:     if (NgFuncSendQuery(path, NGM_PPP_COOKIE, NGM_PPP_GET_LINK_STATS64,
  707:       &linkNum, sizeof(linkNum), &u.reply, sizeof(u), NULL) < 0) {
  708: 	Perror("[%s] can't get stats, link=%d", b->name, linkNum);
  709: 	return -1;
  710:     }
  711:     if (statp != NULL)
  712: 	memcpy(statp, u.reply.data, sizeof(*statp));
  713:     return(0);
  714: }
  715: #endif
  716: 
  717: /*
  718:  * NgFuncErrx()
  719:  */
  720: 
  721: void
  722: NgFuncErrx(const char *fmt, ...)
  723: {
  724:     char	buf[100];
  725:     va_list	args;
  726: 
  727:     va_start(args, fmt);
  728:     vsnprintf(buf, sizeof(buf), fmt, args);
  729:     va_end(args);
  730:     Log(LG_ERR, ("netgraph: %s", buf));
  731: }
  732: 
  733: /*
  734:  * NgFuncErr()
  735:  */
  736: 
  737: void
  738: NgFuncErr(const char *fmt, ...)
  739: {
  740:     char	buf[100];
  741:     va_list	args;
  742: 
  743:     va_start(args, fmt);
  744:     vsnprintf(buf, sizeof(buf), fmt, args);
  745:     va_end(args);
  746:     Perror("netgraph: %s", buf);
  747: }
  748: 
  749: #ifdef USE_NG_NETFLOW
  750: /*
  751:  * NetflowSetCommand()
  752:  */
  753:        
  754: static int
  755: NetflowSetCommand(Context ctx, int ac, char *av[], void *arg)
  756: {
  757:     struct sockaddr_storage *sin;
  758: 
  759:     switch ((intptr_t)arg) {
  760: 	case SET_PEER: 
  761:     	    if (ac != 2)
  762: 		return (-1);
  763:     	    if ((sin = ParseAddrPort(ac, av, ALLOW_IPV4|ALLOW_IPV6)) == NULL)
  764: 		return (-1);
  765:     	    gNetflowExport = *sin;
  766:     	    break;
  767: 	case SET_SELF:
  768: 	    if (ac != 1 && ac != 2)
  769: 		return (-1);
  770:     	    if ((sin = ParseAddrPort(ac, av, ALLOW_IPV4|ALLOW_IPV6)) == NULL)
  771: 		return (-1);
  772:     	    gNetflowSource = *sin;
  773:     	    break;
  774: 	case SET_TIMEOUTS:
  775:     	    if (ac != 2)
  776: 		return (-1);
  777:     	    if (atoi(av[0]) <= 0 || atoi(av[1]) <= 0)
  778: 		Error("Bad netflow timeouts \"%s %s\"", av[0], av[1]);
  779:     	    gNetflowInactive = atoi(av[0]);
  780:     	    gNetflowActive = atoi(av[1]);
  781:     	    break;
  782: #if NGM_NETFLOW_COOKIE >= 1309868867
  783: 	case SET_TEMPLATE:
  784:     	    if (ac != 2)
  785: 		return (-1);
  786: 	    /*
  787: 	     * RFC 3954 clause 7.3
  788: 	     * "Both options MUST be configurable by the user on the Exporter."
  789: 	     */
  790:     	    if (atoi(av[0]) <= 0 || atoi(av[1]) <= 0)
  791: 		Error("Bad netflow v9 template values \"%s %s\"", av[0], av[1]);
  792:     	    gNetflowTime = atoi(av[0]);		/* Default 600 */
  793:     	    gNetflowPackets = atoi(av[1]);	/* Default 500 */
  794:     	    break;
  795: 	case SET_MTU:
  796:     	    if (ac != 1)
  797: 		return (-1);
  798:     	    if (atoi(av[0]) < MIN_MTU || atoi(av[0]) > MAX_MTU)
  799: 		Error("Bad netflow v9 MTU \"%s\"", av[0]);
  800:     	    gNetflowMTU = atoi(av[0]);		/* Default 1500 */
  801:     	    break;
  802: 	case SET_VERSION:
  803:     	    if (ac != 1)
  804: 		return (-1);
  805:     	    if (atoi(av[0]) != 5 && atoi(av[0]) != 9)
  806: 		Error("Bad netflow export version \"%s\"", av[0]);
  807:     	    gNetflowVer = atoi(av[0]);		/* Default 5 */
  808:     	    break;
  809: #endif
  810: 	case SET_NODE:
  811:     	    if (ac != 1)
  812: 		return (-1);
  813:     	    if (strlen(av[0]) == 0 || strlen(av[0]) > 63)
  814: 		Error("Bad netflow node name \"%s\"", av[0]);
  815:     	    strlcpy(gNetflowNodeName, av[0], sizeof(gNetflowNodeName));
  816:     	    gNetflowNode=TRUE;
  817:     	    gNetflowNodeShutdown=FALSE;
  818:     	    break;
  819: 	case SET_HOOK:
  820:     	    if (ac != 1)
  821: 		return (-1);
  822:     	    if (atoi(av[0]) <= 0 || atoi(av[0]) >= NG_NETFLOW_MAXIFACES)
  823: 		Error("Bad netflow hook number \"%s\"", av[0]);
  824:     	    gNetflowIface = atoi(av[0])-1;
  825:     	    break;
  826: 
  827: 	default:
  828: 	    return (-1);
  829:     }
  830: 
  831:     return (0);
  832: }
  833: 
  834: /*
  835:  * ShowNetflow()
  836:  *
  837:  * Show state of a Netflow
  838:  */
  839: 
  840: int
  841: ShowNetflow(Context ctx, int ac, char *av[], void *arg)
  842: {
  843:     struct u_addr addr;
  844:     in_port_t port;
  845:     char buf[64];
  846:     char path[NG_PATHSIZ];
  847:     union {
  848:         u_char buf[sizeof(struct ng_mesg) + sizeof(struct ng_netflow_info)];
  849:         struct ng_mesg reply;
  850:     } u;
  851:     struct ng_netflow_info *const ni = \
  852:         (struct ng_netflow_info *)(void *)u.reply.data;
  853: #ifdef NGM_NETFLOW_V9_COOKIE
  854:     union {
  855:         u_char buf[sizeof(struct ng_mesg) + sizeof(struct ng_netflow_v9info)];
  856:         struct ng_mesg reply;
  857:     } uv9;
  858:     struct ng_netflow_v9info *const niv9 = \
  859:         (struct ng_netflow_v9info *)(void *)uv9.reply.data;
  860: #endif /* NGM_NETFLOW_V9_COOKIE */
  861: 
  862:     if (gNetflowNodeID>0) {
  863:         snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
  864:         if (NgFuncSendQuery(path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_INFO,
  865:         NULL, 0, &u.reply, sizeof(u), NULL) < 0)
  866:             return(-7);
  867: #ifdef NGM_NETFLOW_V9_COOKIE
  868:         if (NgFuncSendQuery(path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_V9INFO,
  869:         NULL, 0, &uv9.reply, sizeof(uv9), NULL) < 0)
  870:             return(-7);
  871: #endif /* NGM_NETFLOW_V9_COOKIE */
  872:     }
  873: 
  874:     Printf("Netflow status:\r\n");
  875:     Printf("\tNode created   : %s\r\n", gNetflowNodeID ? "Yes" : "No");
  876:     Printf("Netflow settings:\r\n");
  877:     Printf("\tNode name      : %s\r\n", gNetflowNodeName);
  878:     Printf("\tInitial hook   : %d\r\n", gNetflowIface);
  879:     Printf("\tTimeouts, sec:\r\n");
  880:     Printf("\t  Active       : %u\r\n",
  881:         (gNetflowNodeID>0) ? ni->nfinfo_act_t :
  882:         (gNetflowActive ? gNetflowActive : ACTIVE_TIMEOUT));
  883:     Printf("\t  Inactive     : %u\r\n",
  884:         (gNetflowNodeID>0) ? ni->nfinfo_inact_t :
  885:         (gNetflowInactive ? gNetflowInactive : INACTIVE_TIMEOUT));
  886:     sockaddrtou_addr(&gNetflowExport, &addr, &port);
  887:     Printf("\tExport address : %s port %d\r\n",
  888:         u_addrtoa(&addr, buf, sizeof(buf)), (int)port);
  889:     sockaddrtou_addr(&gNetflowSource, &addr, &port);
  890:     Printf("\tSource address : %s port %d\r\n",
  891:         u_addrtoa(&addr, buf, sizeof(buf)), (int)port);
  892: #if NGM_NETFLOW_COOKIE >= 1309868867
  893:     Printf("\tExport version : v%d\r\n", gNetflowVer);
  894:     Printf("Netflow v9 configuration:\r\n");
  895:     Printf("\tTemplate:\r\n");
  896: #ifdef NGM_NETFLOW_V9_COOKIE
  897:     Printf("\t  Time         : %d\r\n",
  898:         (gNetflowNodeID>0) ? niv9->templ_time :
  899:         (gNetflowTime ? gNetflowTime : NETFLOW_V9_MAX_TIME_TEMPL));
  900:     Printf("\t  Packets      : %d\r\n",
  901:         (gNetflowNodeID>0) ? niv9->templ_packets :
  902:         (gNetflowPackets ? gNetflowPackets : NETFLOW_V9_MAX_PACKETS_TEMPL));
  903:     Printf("\tNetflow v9 MTU : %d\r\n",
  904:         (gNetflowNodeID>0) ? niv9->mtu :
  905:         (gNetflowMTU ? gNetflowMTU : BASE_MTU));
  906: #else
  907:     Printf("\t  Time         : %d\r\n",
  908:         gNetflowTime ? gNetflowTime : NETFLOW_V9_MAX_TIME_TEMPL);
  909:     Printf("\t  Packets      : %d\r\n",
  910:         gNetflowPackets ? gNetflowPackets : NETFLOW_V9_MAX_PACKETS_TEMPL);
  911:     Printf("\tNetflow v9 MTU : %d\r\n",
  912:         gNetflowMTU ? gNetflowMTU : BASE_MTU);
  913: #endif /* NGM_NETFLOW_V9_COOKIE */
  914: #endif
  915:     if (gNetflowNodeID>0) {
  916:         Printf("Traffic stats:\r\n");
  917: #if NGM_NETFLOW_COOKIE >= 1365756954
  918:         Printf("\tAccounted IPv4 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes);
  919:         Printf("\tAccounted IPv4 packets : %llu\r\n", (unsigned long long)ni->nfinfo_packets);
  920:         Printf("\tAccounted IPv6 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes6);
  921:         Printf("\tAccounted IPv6 packets : %llu\r\n", (unsigned long long)ni->nfinfo_packets6);
  922:         Printf("\tSkipped IPv4 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes);
  923:         Printf("\tSkipped IPv4 packets   : %llu\r\n", (unsigned long long)ni->nfinfo_spackets);
  924:         Printf("\tSkipped IPv6 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes6);
  925:         Printf("\tSkipped IPv6 packets   : %llu\r\n", (unsigned long long)ni->nfinfo_spackets6);
  926:         Printf("\tActive expiries        : %llu\r\n", (unsigned long long)ni->nfinfo_act_exp);
  927:         Printf("\tInactive expiries      : %llu\r\n", (unsigned long long)ni->nfinfo_inact_exp);
  928:         Printf("\tUsed IPv4 cache records: %u\r\n", ni->nfinfo_used);
  929:         Printf("\tUsed IPv6 cache records: %u\r\n", ni->nfinfo_used6);
  930:         Printf("\tFailed allocations     : %u\r\n", ni->nfinfo_alloc_failed);
  931:         Printf("\tFailed v5 export       : %u\r\n", ni->nfinfo_export_failed);
  932:         Printf("\tFailed v9 export       : %u\r\n", ni->nfinfo_export9_failed);
  933:         Printf("\tRallocated mbufs       : %u\r\n", ni->nfinfo_realloc_mbuf);
  934:         Printf("\tFibs allocated         : %u\r\n", ni->nfinfo_alloc_fibs);
  935: #else /* NGM_NETFLOW_COOKIE >= 1365756954 */
  936:         Printf("\tAccounted IPv4 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes);
  937:         Printf("\tAccounted IPv4 packets : %u\r\n", ni->nfinfo_packets);
  938: #if NGM_NETFLOW_COOKIE >= 1309868867
  939:         Printf("\tAccounted IPv6 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes6);
  940:         Printf("\tAccounted IPv6 packets : %u\r\n", ni->nfinfo_packets6);
  941:         Printf("\tSkipped IPv4 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes);
  942:         Printf("\tSkipped IPv4 packets   : %u\r\n", ni->nfinfo_spackets);
  943:         Printf("\tSkipped IPv6 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes6);
  944:         Printf("\tSkipped IPv6 packets   : %u\r\n", ni->nfinfo_spackets6);
  945: #endif
  946:         Printf("\tUsed IPv4 cache records: %u\r\n", ni->nfinfo_used);
  947: #if NGM_NETFLOW_COOKIE >= 1309868867
  948:         Printf("\tUsed IPv6 cache records: %u\r\n", ni->nfinfo_used6);
  949: #endif
  950:         Printf("\tFailed allocations     : %u\r\n", ni->nfinfo_alloc_failed);
  951:         Printf("\tFailed v5 export       : %u\r\n", ni->nfinfo_export_failed);
  952: #if NGM_NETFLOW_COOKIE >= 1309868867
  953:         Printf("\tFailed v9 export       : %u\r\n", ni->nfinfo_export9_failed);
  954:         Printf("\tRallocated mbufs       : %u\r\n", ni->nfinfo_realloc_mbuf);
  955:         Printf("\tFibs allocated         : %u\r\n", ni->nfinfo_alloc_fibs);
  956: #endif
  957:         Printf("\tActive expiries        : %u\r\n", ni->nfinfo_act_exp);
  958:         Printf("\tInactive expiries      : %u\r\n", ni->nfinfo_inact_exp);
  959: #endif /* NGM_NETFLOW_COOKIE >= 1365756954 */
  960:     }
  961:     return(0);
  962: }
  963: #endif /* USE_NG_NETFLOW */
  964: 
  965: ng_ID_t
  966: NgGetNodeID(int csock, const char *path)
  967: {
  968:     union {
  969:         u_char          buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
  970: 	struct ng_mesg  reply;
  971:     }                   u;
  972:     struct nodeinfo     *const ni = (struct nodeinfo *)(void *)u.reply.data;
  973:     
  974:     if (csock < 0) {
  975: 	if (!gNgStatSock) {
  976: 	    char		name[NG_NODESIZ];
  977: 	
  978: 	    /* Create a netgraph socket node */
  979: 	    snprintf(name, sizeof(name), "mpd%d-stats", gPid);
  980: 	    if (NgMkSockNode(name, &gNgStatSock, NULL) < 0) {
  981:     		Perror("NgFuncSendQuery: can't create %s node", NG_SOCKET_NODE_TYPE);
  982:     		return(-1);
  983: 	    }
  984: 	    (void) fcntl(gNgStatSock, F_SETFD, 1);
  985: 	}
  986: 	csock = gNgStatSock;
  987:     }
  988: 
  989:     if (NgSendMsg(csock, path,
  990:       NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0)
  991:         return (0);
  992:     if (NgRecvMsg(csock, &u.reply, sizeof(u), NULL) < 0)
  993: 	return (0);
  994:     
  995:     return (ni->id);
  996: }
  997: 

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