Annotation of embedaddon/mpd/src/ngfunc.c, revision 1.1.1.3
1.1 misho 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>
1.1.1.2 misho 48: #if NGM_NETFLOW_COOKIE >= 1309868867
1.1 misho 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 */
1.1.1.2 misho 463: if (NgSendMsg(gNgStatSock, path, cookie, cmd, args, arglen) < 0) {
464: Perror("NgFuncSendQuery: can't send message");
1.1 misho 465: return (-1);
1.1.1.2 misho 466: }
1.1 misho 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",
1.1.1.3 ! misho 632: label, (int)MBLEN(bp), hookname);
1.1 misho 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:
1.1.1.3 ! misho 768: if (ac != 1 && ac != 2)
! 769: return (-1);
1.1 misho 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);
1.1.1.3 ! misho 822: if (atoi(av[0]) <= 0 || atoi(av[0]) >= NG_NETFLOW_MAXIFACES)
1.1 misho 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: }
1.1.1.2 misho 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");
1.1.1.3 ! misho 880: Printf("\t Active : %u\r\n",
1.1.1.2 misho 881: (gNetflowNodeID>0) ? ni->nfinfo_act_t :
882: (gNetflowActive ? gNetflowActive : ACTIVE_TIMEOUT));
1.1.1.3 ! misho 883: Printf("\t Inactive : %u\r\n",
1.1.1.2 misho 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");
1.1.1.3 ! misho 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 */
1.1.1.2 misho 936: Printf("\tAccounted IPv4 octets : %llu\r\n", (unsigned long long)ni->nfinfo_bytes);
1.1.1.3 ! misho 937: Printf("\tAccounted IPv4 packets : %u\r\n", ni->nfinfo_packets);
1.1.1.2 misho 938: #if NGM_NETFLOW_COOKIE >= 1309868867
939: Printf("\tAccounted IPv6 octets : %llu\r\n", (unsigned long long)ni->nfinfo_bytes6);
1.1.1.3 ! misho 940: Printf("\tAccounted IPv6 packets : %u\r\n", ni->nfinfo_packets6);
1.1.1.2 misho 941: Printf("\tSkipped IPv4 octets : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes);
1.1.1.3 ! misho 942: Printf("\tSkipped IPv4 packets : %u\r\n", ni->nfinfo_spackets);
1.1.1.2 misho 943: Printf("\tSkipped IPv6 octets : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes6);
1.1.1.3 ! misho 944: Printf("\tSkipped IPv6 packets : %u\r\n", ni->nfinfo_spackets6);
1.1.1.2 misho 945: #endif
1.1.1.3 ! misho 946: Printf("\tUsed IPv4 cache records: %u\r\n", ni->nfinfo_used);
1.1.1.2 misho 947: #if NGM_NETFLOW_COOKIE >= 1309868867
1.1.1.3 ! misho 948: Printf("\tUsed IPv6 cache records: %u\r\n", ni->nfinfo_used6);
1.1.1.2 misho 949: #endif
1.1.1.3 ! misho 950: Printf("\tFailed allocations : %u\r\n", ni->nfinfo_alloc_failed);
! 951: Printf("\tFailed v5 export : %u\r\n", ni->nfinfo_export_failed);
1.1.1.2 misho 952: #if NGM_NETFLOW_COOKIE >= 1309868867
1.1.1.3 ! misho 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);
1.1.1.2 misho 956: #endif
1.1.1.3 ! misho 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 */
1.1.1.2 misho 960: }
961: return(0);
962: }
1.1 misho 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>