Annotation of embedaddon/mpd/src/bund.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * bund.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: * Bundle handling stuff
10: */
11:
12: #include "ppp.h"
13: #include "bund.h"
14: #include "ipcp.h"
15: #include "ccp.h"
16: #include "mp.h"
17: #include "iface.h"
18: #include "link.h"
19: #include "msg.h"
20: #include "ngfunc.h"
21: #include "log.h"
22: #include "util.h"
23: #include "input.h"
24:
25: #include <netgraph.h>
26: #include <netgraph/ng_message.h>
27: #include <netgraph/ng_socket.h>
28: #include <netgraph/ng_iface.h>
29: #ifdef USE_NG_VJC
30: #include <netgraph/ng_vjc.h>
31: #endif
32:
33: /*
34: * DEFINITIONS
35: */
36:
37: /* #define DEBUG_BOD */
38:
39: #define BUND_REOPEN_DELAY 3 /* wait this long before closing */
40: #define BUND_REOPEN_PAUSE 3 /* wait this long before re-opening */
41:
42: #define BUND_MIN_TOT_BW 9600
43:
44: /* Set menu options */
45: enum {
46: SET_PERIOD,
47: SET_LOW_WATER,
48: SET_HIGH_WATER,
49: SET_MIN_CONNECT,
50: SET_MIN_DISCONNECT,
51: SET_LINKS,
52: SET_AUTHNAME,
53: SET_PASSWORD,
54: SET_RETRY,
55: SET_ACCEPT,
56: SET_DENY,
57: SET_ENABLE,
58: SET_DISABLE,
59: SET_YES,
60: SET_NO
61: };
62:
63: /*
64: * INTERNAL FUNCTIONS
65: */
66:
67: static int BundNgInit(Bund b);
68: static void BundNgShutdown(Bund b, int iface, int ppp);
69:
70: static void BundBmStart(Bund b);
71: static void BundBmStop(Bund b);
72: static void BundBmTimeout(void *arg);
73:
74: static void BundReasses(Bund b);
75: static int BundSetCommand(Context ctx, int ac, char *av[], void *arg);
76:
77: static void BundNcpsUp(Bund b);
78: static void BundNcpsDown(Bund b);
79:
80: static void BundReOpenLinks(void *arg);
81: static void BundCloseLink(Link l);
82:
83: static void BundMsg(int type, void *cookie);
84:
85: /*
86: * GLOBAL VARIABLES
87: */
88:
89: struct discrim self_discrim;
90:
91: const struct cmdtab BundSetCmds[] = {
92: { "period {seconds}", "BoD sampling period",
93: BundSetCommand, NULL, 2, (void *) SET_PERIOD },
94: { "lowat {percent}", "BoD low water mark",
95: BundSetCommand, NULL, 2, (void *) SET_LOW_WATER },
96: { "hiwat {percent}", "BoD high water mark",
97: BundSetCommand, NULL, 2, (void *) SET_HIGH_WATER },
98: { "min-con {seconds}", "BoD min connected time",
99: BundSetCommand, NULL, 2, (void *) SET_MIN_CONNECT },
100: { "min-dis {seconds}", "BoD min disconnected time",
101: BundSetCommand, NULL, 2, (void *) SET_MIN_DISCONNECT },
102: { "links {link list ...}", "Links list for BoD/DoD",
103: BundSetCommand, NULL, 2, (void *) SET_LINKS },
104: { "fsm-timeout {seconds}", "FSM retry timeout",
105: BundSetCommand, NULL, 2, (void *) SET_RETRY },
106: { "accept {opt ...}", "Accept option",
107: BundSetCommand, NULL, 2, (void *) SET_ACCEPT },
108: { "deny {opt ...}", "Deny option",
109: BundSetCommand, NULL, 2, (void *) SET_DENY },
110: { "enable {opt ...}", "Enable option",
111: BundSetCommand, NULL, 2, (void *) SET_ENABLE },
112: { "disable {opt ...}", "Disable option",
113: BundSetCommand, NULL, 2, (void *) SET_DISABLE },
114: { "yes {opt ...}", "Enable and accept option",
115: BundSetCommand, NULL, 2, (void *) SET_YES },
116: { "no {opt ...}", "Disable and deny option",
117: BundSetCommand, NULL, 2, (void *) SET_NO },
118: { NULL },
119: };
120:
121: /*
122: * INTERNAL VARIABLES
123: */
124:
125: static const struct confinfo gConfList[] = {
126: { 0, BUND_CONF_IPCP, "ipcp" },
127: { 0, BUND_CONF_IPV6CP, "ipv6cp" },
128: { 0, BUND_CONF_COMPRESSION, "compression" },
129: { 0, BUND_CONF_ENCRYPTION, "encryption" },
130: { 0, BUND_CONF_CRYPT_REQD, "crypt-reqd" },
131: { 0, BUND_CONF_BWMANAGE, "bw-manage" },
132: { 0, BUND_CONF_ROUNDROBIN, "round-robin" },
133: { 0, 0, NULL },
134: };
135:
136: /*
137: * BundOpen()
138: */
139:
140: void
141: BundOpen(Bund b)
142: {
143: REF(b);
144: MsgSend(&b->msgs, MSG_OPEN, b);
145: }
146:
147: /*
148: * BundClose()
149: */
150:
151: void
152: BundClose(Bund b)
153: {
154: REF(b);
155: MsgSend(&b->msgs, MSG_CLOSE, b);
156: }
157:
158: /*
159: * BundOpenCmd()
160: */
161:
162: int
163: BundOpenCmd(Context ctx)
164: {
165: if (ctx->bund->tmpl)
166: Error("impossible to open template");
167: BundOpen(ctx->bund);
168: return (0);
169: }
170:
171: /*
172: * BundCloseCmd()
173: */
174:
175: int
176: BundCloseCmd(Context ctx)
177: {
178: if (ctx->bund->tmpl)
179: Error("impossible to close template");
180: BundClose(ctx->bund);
181: return (0);
182: }
183:
184: /*
185: * BundJoin()
186: *
187: * This is called when a link enters the NETWORK phase.
188: *
189: * Verify that link is OK to come up as part of it's bundle.
190: * If so, join it to the bundle. Returns FALSE if there's a problem.
191: * If this is the first link to join, and it's not supporting
192: * multi-link, then prevent any further links from joining.
193: *
194: * Right now this is fairly simple minded: you have to define
195: * the links in a bundle first, then stick to that plan. For
196: * a server this might be too restrictive a policy.
197: *
198: * Returns zero if fails, otherwise the new number of up links.
199: */
200:
201: int
202: BundJoin(Link l)
203: {
204: Bund b, bt;
205: LcpState const lcp = &l->lcp;
206: int k;
207:
208: if (gShutdownInProgress) {
209: Log(LG_BUND, ("Shutdown sequence in progress, BundJoin() denied"));
210: return(0);
211: }
212:
213: if (!l->bund) {
214: b = NULL;
215: if (lcp->peer_mrru) {
216: for (k = 0; k < gNumBundles; k++) {
217: if (gBundles[k] && !gBundles[k]->tmpl && gBundles[k]->peer_mrru &&
218: MpDiscrimEqual(&lcp->peer_discrim, &gBundles[k]->peer_discrim) &&
219: !strcmp(lcp->auth.params.authname, gBundles[k]->params.authname)) {
220: break;
221: }
222: }
223: if (k != gNumBundles) {
224: b = gBundles[k];
225: }
226: }
227: if (!b) {
228: const char *bundt;
229: if (strncmp(l->lcp.auth.params.action, "bundle ", 7) == 0) {
230: bundt = l->lcp.auth.params.action + 7;
231: } else {
232: bundt = LinkMatchAction(l, 3, l->lcp.auth.params.authname);
233: }
234: if (bundt) {
235: if (strcmp(bundt,"##DROP##") == 0) {
236: /* Action told we must drop this connection */
237: Log(LG_BUND, ("[%s] Drop link", l->name));
238: return (0);
239: }
240: if ((bt = BundFind(bundt))) {
241: if (bt->tmpl) {
242: Log(LG_BUND, ("[%s] Creating new bundle using template \"%s\".", l->name, bundt));
243: b = BundInst(bt, NULL, 0, 0);
244: } else {
245: b = bt;
246: }
247: } else {
248: Log(LG_BUND, ("[%s] Bundle \"%s\" not found.", l->name, bundt));
249: return (0);
250: }
251: } else {
252: Log(LG_BUND, ("[%s] No bundle specified", l->name));
253: return (0);
254: }
255: if (!b) {
256: Log(LG_BUND, ("[%s] Bundle creation error", l->name));
257: return (0);
258: }
259: }
260: if (b->n_up > 0 &&
261: (b->peer_mrru == 0 || lcp->peer_mrru == 0 || lcp->want_mrru == 0)) {
262: Log(LG_BUND, ("[%s] Can't join bundle %s without "
263: "multilink negotiated.", l->name, b->name));
264: return (0);
265: }
266: if (b->n_up > 0 &&
267: (!MpDiscrimEqual(&lcp->peer_discrim, &b->peer_discrim) ||
268: strcmp(lcp->auth.params.authname, b->params.authname))) {
269: Log(LG_BUND, ("[%s] Can't join bundle %s with different "
270: "peer discriminator/authname.", l->name, b->name));
271: return (0);
272: }
273: k = 0;
274: while (k < NG_PPP_MAX_LINKS && b->links[k] != NULL)
275: k++;
276: if (k < NG_PPP_MAX_LINKS) {
277: l->bund = b;
278: l->bundleIndex = k;
279: b->links[k] = l;
280: b->n_links++;
281: } else {
282: Log(LG_BUND, ("[%s] No more then %d links per bundle allowed. "
283: "Can't join budle.", l->name, NG_PPP_MAX_LINKS));
284: return (0);
285: }
286: }
287:
288: b = l->bund;
289:
290: Log(LG_LINK, ("[%s] Link: Join bundle \"%s\"", l->name, b->name));
291:
292: b->open = TRUE; /* Open bundle on incoming */
293:
294: if (LinkNgJoin(l)) {
295: Log(LG_ERR, ("[%s] Bundle netgraph join failed", l->name));
296: l->bund = NULL;
297: b->links[l->bundleIndex] = NULL;
298: if (!b->stay)
299: BundShutdown(b);
300: return(0);
301: }
302: l->joined_bund = 1;
303: b->n_up++;
304:
305: LinkResetStats(l);
306:
307: if (b->n_up == 1) {
308:
309: /* Cancel re-open timer; we've come up somehow (eg, LCP renegotiation) */
310: TimerStop(&b->reOpenTimer);
311:
312: b->last_up = time(NULL);
313:
314: /* Copy auth params from the first link */
315: authparamsCopy(&l->lcp.auth.params,&b->params);
316:
317: /* Initialize multi-link stuff */
318: if ((b->peer_mrru = lcp->peer_mrru)) {
319: b->peer_discrim = lcp->peer_discrim;
320: }
321:
322: /* Start bandwidth management */
323: BundBmStart(b);
324: }
325:
326: /* Reasses MTU, bandwidth, etc. */
327: BundReasses(b);
328:
329: /* Configure this link */
330: b->pppConfig.links[l->bundleIndex].enableLink = 1;
331: b->pppConfig.links[l->bundleIndex].mru = lcp->peer_mru;
332: b->pppConfig.links[l->bundleIndex].enableACFComp = lcp->peer_acfcomp;
333: b->pppConfig.links[l->bundleIndex].enableProtoComp = lcp->peer_protocomp;
334: b->pppConfig.links[l->bundleIndex].bandwidth =
335: MIN((l->bandwidth / 8 + 5) / 10, NG_PPP_MAX_BANDWIDTH);
336: b->pppConfig.links[l->bundleIndex].latency =
337: MIN((l->latency + 500) / 1000, NG_PPP_MAX_LATENCY);
338:
339: /* What to do when the first link comes up */
340: if (b->n_up == 1) {
341:
342: /* Configure the bundle */
343: b->pppConfig.bund.enableMultilink = (lcp->peer_mrru && lcp->want_mrru)?1:0;
344: /* ng_ppp does not allow MRRU less then 1500 bytes. */
345: b->pppConfig.bund.mrru = (lcp->peer_mrru < 1500) ? 1500 : lcp->peer_mrru;
346: b->pppConfig.bund.xmitShortSeq = lcp->peer_shortseq;
347: b->pppConfig.bund.recvShortSeq = lcp->want_shortseq;
348: b->pppConfig.bund.enableRoundRobin =
349: Enabled(&b->conf.options, BUND_CONF_ROUNDROBIN);
350:
351: /* generate a uniq msession_id */
352: snprintf(b->msession_id, AUTH_MAX_SESSIONID, "%d-%s",
353: (int)(time(NULL) % 10000000), b->name);
354:
355: b->originate = l->originate;
356: }
357:
358: /* Update PPP node configuration */
359: NgFuncSetConfig(b);
360:
361: /* copy msession_id to link */
362: strlcpy(l->msession_id, b->msession_id, sizeof(l->msession_id));
363:
364: /* What to do when the first link comes up */
365: if (b->n_up == 1) {
366:
367: BundNcpsOpen(b);
368: BundNcpsUp(b);
369:
370: BundResetStats(b);
371:
372: #ifndef NG_PPP_STATS64
373: /* starting bundle statistics timer */
374: TimerInit(&b->statsUpdateTimer, "BundUpdateStats",
375: BUND_STATS_UPDATE_INTERVAL, BundUpdateStatsTimer, b);
376: TimerStartRecurring(&b->statsUpdateTimer);
377: #endif
378: }
379:
380: AuthAccountStart(l, AUTH_ACCT_START);
381:
382: return(b->n_up);
383: }
384:
385: /*
386: * BundLeave()
387: *
388: * This is called when a link leaves the NETWORK phase.
389: */
390:
391: void
392: BundLeave(Link l)
393: {
394: Bund b = l->bund;
395:
396: /* Elvis has left the bundle */
397: assert(b->n_up > 0);
398:
399: Log(LG_LINK, ("[%s] Link: Leave bundle \"%s\"", l->name, b->name));
400:
401: AuthAccountStart(l, AUTH_ACCT_STOP);
402:
403: /* Disable link */
404: b->pppConfig.links[l->bundleIndex].enableLink = 0;
405: b->pppConfig.links[l->bundleIndex].mru = LCP_DEFAULT_MRU;
406: NgFuncSetConfig(b);
407:
408: LinkNgLeave(l);
409: l->joined_bund = 0;
410: b->n_up--;
411:
412: /* Divorce link and bundle */
413: b->links[l->bundleIndex] = NULL;
414: b->n_links--;
415: l->bund = NULL;
416:
417: BundReasses(b);
418:
419: /* Forget session_ids */
420: l->msession_id[0] = 0;
421:
422: /* Special stuff when last link goes down... */
423: if (b->n_up == 0) {
424:
425: #ifndef NG_PPP_STATS64
426: /* stopping bundle statistics timer */
427: TimerStop(&b->statsUpdateTimer);
428: #endif
429:
430: /* Reset statistics and auth information */
431: BundBmStop(b);
432:
433: BundNcpsClose(b);
434: BundNcpsDown(b);
435:
436: #ifdef USE_NG_BPF
437: IfaceFreeStats(&b->iface.prevstats);
438: #endif
439:
440: authparamsDestroy(&b->params);
441:
442: b->msession_id[0] = 0;
443:
444: /* try to open again later */
445: if (b->open && Enabled(&b->conf.options, BUND_CONF_BWMANAGE) &&
446: !Enabled(&b->iface.options, IFACE_CONF_ONDEMAND) && !gShutdownInProgress) {
447: if (b->n_links != 0 || b->conf.linkst[0][0]) {
448: /* wait BUND_REOPEN_DELAY to see if it comes back up */
449: int delay = BUND_REOPEN_DELAY;
450: delay += ((random() ^ gPid ^ time(NULL)) & 1);
451: Log(LG_BUND, ("[%s] Bundle: Last link has gone, reopening in %d seconds",
452: b->name, delay));
453: TimerStop(&b->reOpenTimer);
454: TimerInit(&b->reOpenTimer, "BundReOpen",
455: delay * SECONDS, BundReOpenLinks, b);
456: TimerStart(&b->reOpenTimer);
457: return;
458: } else {
459: Log(LG_BUND, ("[%s] Bundle: Last link has gone, no links for bw-manage defined",
460: b->name));
461: }
462: }
463: b->open = FALSE;
464: if (!b->stay)
465: BundShutdown(b);
466: }
467: }
468:
469: /*
470: * BundReOpenLinks()
471: *
472: * The last link went down, and we waited BUND_REOPEN_DELAY seconds for
473: * it to come back up. It didn't, so close all the links and re-open them
474: * BUND_REOPEN_PAUSE seconds from now.
475: *
476: * The timer calling this is cancelled whenever any link comes up.
477: */
478:
479: static void
480: BundReOpenLinks(void *arg)
481: {
482: Bund b = (Bund)arg;
483:
484: Log(LG_BUND, ("[%s] Bundle: Last link has gone, reopening...", b->name));
485: BundOpenLinks(b);
486: }
487:
488: /*
489: * BundMsg()
490: *
491: * Deal with incoming message to the bundle
492: */
493:
494: static void
495: BundMsg(int type, void *arg)
496: {
497: Bund b = (Bund)arg;
498:
499: if (b->dead) {
500: UNREF(b);
501: return;
502: }
503: Log(LG_BUND, ("[%s] Bundle: %s event in state %s",
504: b->name, MsgName(type), b->open ? "OPENED" : "CLOSED"));
505: TimerStop(&b->reOpenTimer);
506: switch (type) {
507: case MSG_OPEN:
508: b->open = TRUE;
509: BundOpenLinks(b);
510: break;
511:
512: case MSG_CLOSE:
513: b->open = FALSE;
514: BundCloseLinks(b);
515: break;
516:
517: default:
518: assert(FALSE);
519: }
520: UNREF(b);
521: }
522:
523: /*
524: * BundOpenLinks()
525: *
526: * Open one link or all links, depending on whether bandwidth
527: * management is in effect or not.
528: */
529:
530: void
531: BundOpenLinks(Bund b)
532: {
533: int k;
534:
535: TimerStop(&b->reOpenTimer);
536: if (Enabled(&b->conf.options, BUND_CONF_BWMANAGE)) {
537: if (b->n_links != 0)
538: return;
539: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
540: if (b->links[k]) {
541: BundOpenLink(b->links[k]);
542: break;
543: } else if (b->conf.linkst[k][0]) {
544: BundCreateOpenLink(b, k);
545: break;
546: }
547: }
548: } else {
549: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
550: if (b->links[k])
551: BundOpenLink(b->links[k]);
552: else if (b->conf.linkst[k][0])
553: BundCreateOpenLink(b, k);
554: }
555: }
556: }
557:
558: /*
559: * BundCreateOpenLink()
560: */
561:
562: int
563: BundCreateOpenLink(Bund b, int n)
564: {
565: if (!b->links[n]) {
566: if (b->conf.linkst[n][0]) {
567: Link l;
568: Link lt = LinkFind(b->conf.linkst[n]);
569: if (!lt) {
570: Log(LG_BUND, ("[%s] Bund: Link \"%s\" not found", b->name, b->conf.linkst[n]));
571: return (-1);
572: }
573: if (PhysIsBusy(lt)) {
574: Log(LG_BUND, ("[%s] Bund: Link \"%s\" is busy", b->name, b->conf.linkst[n]));
575: return (-1);
576: }
577: if (lt->tmpl) {
578: l = LinkInst(lt, NULL, 0, 0);
579: } else
580: l = lt;
581: if (!l) {
582: Log(LG_BUND, ("[%s] Bund: Link \"%s\" creation error", b->name, b->conf.linkst[n]));
583: return (-1);
584: }
585: b->links[n] = l;
586: b->n_links++;
587: l->bund = b;
588: l->bundleIndex = n;
589: l->conf.max_redial = -1;
590: } else {
591: Log(LG_BUND, ("[%s] Bund: Link %d name not specified", b->name, n));
592: return (-1);
593: }
594: }
595: BundOpenLink(b->links[n]);
596: return (0);
597: }
598:
599: /*
600: * BundOpenLink()
601: */
602:
603: void
604: BundOpenLink(Link l)
605: {
606: Log(LG_BUND, ("[%s] opening link \"%s\"...", l->bund->name, l->name));
607: LinkOpen(l);
608: }
609:
610: /*
611: * BundCloseLinks()
612: *
613: * Close all links
614: */
615:
616: void
617: BundCloseLinks(Bund b)
618: {
619: int k;
620:
621: TimerStop(&b->reOpenTimer);
622: for (k = 0; k < NG_PPP_MAX_LINKS; k++)
623: if (b->links[k] && OPEN_STATE(b->links[k]->lcp.fsm.state))
624: BundCloseLink(b->links[k]);
625: }
626:
627: /*
628: * BundCloseLink()
629: */
630:
631: static void
632: BundCloseLink(Link l)
633: {
634: Log(LG_BUND, ("[%s] Bundle: closing link \"%s\"...", l->bund->name, l->name));
635: LinkClose(l);
636: }
637:
638: /*
639: * BundNcpsOpen()
640: */
641:
642: void
643: BundNcpsOpen(Bund b)
644: {
645: if (Enabled(&b->conf.options, BUND_CONF_IPCP))
646: IpcpOpen(b);
647: if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
648: Ipv6cpOpen(b);
649: if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
650: CcpOpen(b);
651: if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
652: EcpOpen(b);
653: }
654:
655: /*
656: * BundNcpsUp()
657: */
658:
659: static void
660: BundNcpsUp(Bund b)
661: {
662: if (Enabled(&b->conf.options, BUND_CONF_IPCP))
663: IpcpUp(b);
664: if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
665: Ipv6cpUp(b);
666: if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
667: CcpUp(b);
668: if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
669: EcpUp(b);
670: }
671:
672: void
673: BundNcpsStart(Bund b, int proto)
674: {
675: b->ncpstarted |= ((1<<proto)>>1);
676: }
677:
678: void
679: BundNcpsFinish(Bund b, int proto)
680: {
681: b->ncpstarted &= (~((1<<proto)>>1));
682: if (!b->ncpstarted) {
683: Log(LG_BUND, ("[%s] Bundle: No NCPs left. Closing links...", b->name));
684: RecordLinkUpDownReason(b, NULL, 0, STR_PROTO_ERR, NULL);
685: BundCloseLinks(b); /* We have nothing to live for */
686: }
687: }
688:
689: void
690: BundNcpsJoin(Bund b, int proto)
691: {
692: IfaceState iface = &b->iface;
693:
694: if (iface->dod) {
695: if (iface->ip_up) {
696: iface->ip_up = 0;
697: IfaceIpIfaceDown(b);
698: }
699: if (iface->ipv6_up) {
700: iface->ipv6_up = 0;
701: IfaceIpv6IfaceDown(b);
702: }
703: iface->dod = 0;
704: iface->up = 0;
705: IfaceDown(b);
706: }
707:
708: switch(proto) {
709: case NCP_IPCP:
710: if (!iface->ip_up) {
711: iface->ip_up = 1;
712: if (IfaceIpIfaceUp(b, 1)) {
713: iface->ip_up = 0;
714: return;
715: };
716: }
717: break;
718: case NCP_IPV6CP:
719: if (!iface->ipv6_up) {
720: iface->ipv6_up = 1;
721: if (IfaceIpv6IfaceUp(b, 1)) {
722: iface->ipv6_up = 0;
723: return;
724: };
725: }
726: break;
727: case NCP_NONE: /* Manual call by 'open iface' */
728: if (Enabled(&b->conf.options, BUND_CONF_IPCP) &&
729: !iface->ip_up) {
730: iface->ip_up = 1;
731: if (IfaceIpIfaceUp(b, 0)) {
732: iface->ip_up = 0;
733: return;
734: };
735: }
736: if (Enabled(&b->conf.options, BUND_CONF_IPV6CP) &&
737: !iface->ipv6_up) {
738: iface->ipv6_up = 1;
739: if (IfaceIpv6IfaceUp(b, 0)) {
740: iface->ipv6_up = 0;
741: return;
742: };
743: }
744: break;
745: }
746:
747: if (!iface->up) {
748: iface->up = 1;
749: if (proto == NCP_NONE) {
750: iface->dod = 1;
751: IfaceUp(b, 0);
752: } else {
753: IfaceUp(b, 1);
754: }
755: }
756: }
757:
758: void
759: BundNcpsLeave(Bund b, int proto)
760: {
761: IfaceState iface = &b->iface;
762: switch(proto) {
763: case NCP_IPCP:
764: if (iface->ip_up) {
765: iface->ip_up=0;
766: IfaceIpIfaceDown(b);
767: }
768: break;
769: case NCP_IPV6CP:
770: if (iface->ipv6_up) {
771: iface->ipv6_up=0;
772: IfaceIpv6IfaceDown(b);
773: }
774: break;
775: case NCP_NONE:
776: if (iface->ip_up) {
777: iface->ip_up=0;
778: IfaceIpIfaceDown(b);
779: }
780: if (iface->ipv6_up) {
781: iface->ipv6_up=0;
782: IfaceIpv6IfaceDown(b);
783: }
784: break;
785: }
786:
787: if ((iface->up) && (!iface->ip_up) && (!iface->ipv6_up)) {
788: iface->dod=0;
789: iface->up=0;
790: IfaceDown(b);
791: if (iface->open) {
792: if (Enabled(&b->conf.options, BUND_CONF_IPCP)) {
793: iface->ip_up=1;
794: if (IfaceIpIfaceUp(b, 0))
795: iface->ip_up = 0;
796: }
797: if (Enabled(&b->conf.options, BUND_CONF_IPV6CP)) {
798: iface->ipv6_up=1;
799: if (IfaceIpv6IfaceUp(b, 0))
800: iface->ipv6_up = 0;
801: }
802: if (iface->ip_up || iface->ipv6_up) {
803: iface->dod=1;
804: iface->up=1;
805: IfaceUp(b, 0);
806: }
807: }
808: }
809: }
810:
811: /*
812: * BundNcpsDown()
813: */
814:
815: static void
816: BundNcpsDown(Bund b)
817: {
818: if (Enabled(&b->conf.options, BUND_CONF_IPCP))
819: IpcpDown(b);
820: if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
821: Ipv6cpDown(b);
822: if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
823: CcpDown(b);
824: if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
825: EcpDown(b);
826: }
827:
828: /*
829: * BundNcpsClose()
830: */
831:
832: void
833: BundNcpsClose(Bund b)
834: {
835: if (Enabled(&b->conf.options, BUND_CONF_IPCP))
836: IpcpClose(b);
837: if (Enabled(&b->conf.options, BUND_CONF_IPV6CP))
838: Ipv6cpClose(b);
839: if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
840: CcpClose(b);
841: if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
842: EcpClose(b);
843: }
844:
845: /*
846: * BundReasses()
847: *
848: * Here we do a reassessment of things after a new link has been
849: * added to or removed from the bundle.
850: */
851:
852: static void
853: BundReasses(Bund b)
854: {
855: BundBm const bm = &b->bm;
856:
857: /* Update system interface parameters */
858: BundUpdateParams(b);
859:
860: Log(LG_BUND, ("[%s] Bundle: Status update: up %d link%s, total bandwidth %d bps",
861: b->name, b->n_up, b->n_up == 1 ? "" : "s", bm->total_bw));
862:
863: }
864:
865: /*
866: * BundUpdateParams()
867: *
868: * Recalculate interface MTU and bandwidth.
869: */
870:
871: void
872: BundUpdateParams(Bund b)
873: {
874: BundBm const bm = &b->bm;
875: int k, mtu, the_link = 0;
876:
877: /* Recalculate how much bandwidth we have */
878: bm->total_bw = 0;
879: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
880: if (b->links[k] && b->links[k]->lcp.phase == PHASE_NETWORK) {
881: bm->total_bw += b->links[k]->bandwidth;
882: the_link = k;
883: }
884: }
885: if (bm->total_bw < BUND_MIN_TOT_BW)
886: bm->total_bw = BUND_MIN_TOT_BW;
887:
888: /* Recalculate MTU corresponding to peer's MRU */
889: if (b->n_up == 0) {
890: mtu = NG_IFACE_MTU_DEFAULT; /* Reset to default settings */
891:
892: } else if (!b->peer_mrru) { /* If no multilink, use peer MRU */
893: mtu = MIN(b->links[the_link]->lcp.peer_mru,
894: b->links[the_link]->type->mtu);
895:
896: } else { /* Multilink, use peer MRRU */
897: mtu = MIN(b->peer_mrru, MP_MAX_MRRU);
898: }
899:
900: /* Subtract to make room for various frame-bloating protocols */
901: if (b->n_up > 0) {
902: if (Enabled(&b->conf.options, BUND_CONF_COMPRESSION))
903: mtu = CcpSubtractBloat(b, mtu);
904: if (Enabled(&b->conf.options, BUND_CONF_ENCRYPTION))
905: mtu = EcpSubtractBloat(b, mtu);
906: }
907:
908: /* Update interface MTU */
909: IfaceSetMTU(b, mtu);
910:
911: }
912:
913: /*
914: * BundCommand()
915: *
916: * Show list of all bundles or set bundle
917: */
918:
919: int
920: BundCommand(Context ctx, int ac, char *av[], void *arg)
921: {
922: Bund sb;
923: int j, k;
924:
925: if (ac > 1)
926: return (-1);
927:
928: if (ac == 0) {
929: Printf("Defined bundles:\r\n");
930: for (k = 0; k < gNumBundles; k++) {
931: if ((sb = gBundles[k]) != NULL) {
932: Printf("\t%-15s", sb->name);
933: for (j = 0; j < NG_PPP_MAX_LINKS; j++) {
934: if (sb->links[j])
935: Printf("%s ", sb->links[j]->name);
936: }
937: Printf("\r\n");
938: }
939: }
940: return (0);
941: }
942:
943: if ((sb = BundFind(av[0])) == NULL) {
944: RESETREF(ctx->lnk, NULL);
945: RESETREF(ctx->bund, NULL);
946: RESETREF(ctx->rep, NULL);
947: Error("Bundle \"%s\" not defined.", av[0]);
948: }
949:
950: /* Change bundle, and link also if needed */
951: RESETREF(ctx->bund, sb);
952: if (ctx->lnk == NULL || ctx->lnk->bund != ctx->bund) {
953: RESETREF(ctx->lnk, ctx->bund->links[0]);
954: }
955: RESETREF(ctx->rep, NULL);
956: return(0);
957: }
958:
959: /*
960: * MSessionCommand()
961: */
962:
963: int
964: MSessionCommand(Context ctx, int ac, char *av[], void *arg)
965: {
966: int k;
967:
968: if (ac > 1)
969: return (-1);
970:
971: if (ac == 0) {
972: Printf("Present msessions:\r\n");
973: for (k = 0; k < gNumBundles; k++) {
974: if (gBundles[k] && gBundles[k]->msession_id[0])
975: Printf("\t%s\r\n", gBundles[k]->msession_id);
976: }
977: return (0);
978: }
979:
980: /* Find bundle */
981: for (k = 0;
982: k < gNumBundles && (gBundles[k] == NULL ||
983: strcmp(gBundles[k]->msession_id, av[0]));
984: k++);
985: if (k == gNumBundles) {
986: /* Change default link and bundle */
987: RESETREF(ctx->lnk, NULL);
988: RESETREF(ctx->bund, NULL);
989: RESETREF(ctx->rep, NULL);
990: Error("msession \"%s\" is not found", av[0]);
991: }
992:
993: /* Change default link and bundle */
994: RESETREF(ctx->bund, gBundles[k]);
995: if (ctx->lnk == NULL || ctx->lnk->bund != ctx->bund) {
996: RESETREF(ctx->lnk, ctx->bund->links[0]);
997: }
998: RESETREF(ctx->rep, NULL);
999:
1000: return(0);
1001: }
1002:
1003: /*
1004: * IfaceCommand()
1005: */
1006:
1007: int
1008: IfaceCommand(Context ctx, int ac, char *av[], void *arg)
1009: {
1010: int k;
1011:
1012: if (ac > 1)
1013: return (-1);
1014:
1015: if (ac == 0) {
1016: Printf("Present ifaces:\r\n");
1017: for (k = 0; k < gNumBundles; k++) {
1018: if (gBundles[k] && gBundles[k]->iface.ifname[0])
1019: Printf("\t%s\t%s\r\n", gBundles[k]->iface.ifname, gBundles[k]->name);
1020: }
1021: return (0);
1022: }
1023:
1024: /* Find bundle */
1025: for (k = 0;
1026: k < gNumBundles && (gBundles[k] == NULL ||
1027: strcmp(gBundles[k]->iface.ifname, av[0]));
1028: k++);
1029: if (k == gNumBundles) {
1030: /* Change default link and bundle */
1031: RESETREF(ctx->lnk, NULL);
1032: RESETREF(ctx->bund, NULL);
1033: RESETREF(ctx->rep, NULL);
1034: Error("iface \"%s\" is not found", av[0]);
1035: }
1036:
1037: /* Change default link and bundle */
1038: RESETREF(ctx->bund, gBundles[k]);
1039: if (ctx->lnk == NULL || ctx->lnk->bund != ctx->bund) {
1040: RESETREF(ctx->lnk, ctx->bund->links[0]);
1041: }
1042: RESETREF(ctx->rep, NULL);
1043:
1044: return(0);
1045: }
1046:
1047: /*
1048: * BundCreate()
1049: */
1050:
1051: int
1052: BundCreate(Context ctx, int ac, char *av[], void *arg)
1053: {
1054: Bund b, bt = NULL;
1055: u_char tmpl = 0;
1056: u_char stay = 0;
1057: int k;
1058:
1059: RESETREF(ctx->lnk, NULL);
1060: RESETREF(ctx->bund, NULL);
1061: RESETREF(ctx->rep, NULL);
1062:
1063: if (ac < 1)
1064: return(-1);
1065:
1066: if (strcmp(av[0], "template") == 0) {
1067: tmpl = 1;
1068: stay = 1;
1069: } else if (strcmp(av[0], "static") == 0)
1070: stay = 1;
1071:
1072: if (ac - stay < 1 || ac - stay > 2)
1073: return(-1);
1074:
1075: if (strlen(av[0 + stay]) >= (LINK_MAX_NAME - tmpl * (IFNUMLEN + 1)))
1076: Error("Bundle name \"%s\" is too long", av[0 + stay]);
1077:
1078: /* See if bundle name already taken */
1079: if ((b = BundFind(av[0 + stay])) != NULL)
1080: Error("Bundle \"%s\" already exists", av[0 + stay]);
1081:
1082: if (ac - stay == 2) {
1083: /* See if template name specified */
1084: if ((bt = BundFind(av[1 + stay])) == NULL)
1085: Error("Bundle template \"%s\" not found", av[1 + stay]);
1086: if (!bt->tmpl)
1087: Error("Bundle \"%s\" is not a template", av[1 + stay]);
1088: }
1089:
1090: if (bt) {
1091: b = BundInst(bt, av[0 + stay], tmpl, stay);
1092: } else {
1093: /* Create a new bundle structure */
1094: b = Malloc(MB_BUND, sizeof(*b));
1095: strlcpy(b->name, av[0 + stay], sizeof(b->name));
1096: b->tmpl = tmpl;
1097: b->stay = stay;
1098:
1099: /* Add bundle to the list of bundles and make it the current active bundle */
1100: for (k = 0; k < gNumBundles && gBundles[k] != NULL; k++);
1101: if (k == gNumBundles) /* add a new bundle pointer */
1102: LengthenArray(&gBundles, sizeof(*gBundles), &gNumBundles, MB_BUND);
1103:
1104: b->id = k;
1105: gBundles[k] = b;
1106: REF(b);
1107:
1108: /* Get message channel */
1109: MsgRegister(&b->msgs, BundMsg);
1110:
1111: /* Initialize bundle configuration */
1112: b->conf.retry_timeout = BUND_DEFAULT_RETRY;
1113: b->conf.bm_S = BUND_BM_DFL_S;
1114: b->conf.bm_Hi = BUND_BM_DFL_Hi;
1115: b->conf.bm_Lo = BUND_BM_DFL_Lo;
1116: b->conf.bm_Mc = BUND_BM_DFL_Mc;
1117: b->conf.bm_Md = BUND_BM_DFL_Md;
1118:
1119: Enable(&b->conf.options, BUND_CONF_IPCP);
1120: Disable(&b->conf.options, BUND_CONF_IPV6CP);
1121:
1122: Disable(&b->conf.options, BUND_CONF_BWMANAGE);
1123: Disable(&b->conf.options, BUND_CONF_COMPRESSION);
1124: Disable(&b->conf.options, BUND_CONF_ENCRYPTION);
1125: Disable(&b->conf.options, BUND_CONF_CRYPT_REQD);
1126:
1127: /* Init iface and NCP's */
1128: IfaceInit(b);
1129: IpcpInit(b);
1130: Ipv6cpInit(b);
1131: CcpInit(b);
1132: EcpInit(b);
1133:
1134: if (!tmpl) {
1135: /* Setup netgraph stuff */
1136: if (BundNgInit(b) < 0) {
1137: gBundles[b->id] = NULL;
1138: Freee(b);
1139: Error("Bundle netgraph initialization failed");
1140: }
1141: }
1142: }
1143:
1144: RESETREF(ctx->bund, b);
1145:
1146: /* Done */
1147: return(0);
1148: }
1149:
1150: /*
1151: * BundDestroy()
1152: */
1153:
1154: int
1155: BundDestroy(Context ctx, int ac, char *av[], void *arg)
1156: {
1157: Bund b;
1158:
1159: if (ac > 1)
1160: return(-1);
1161:
1162: if (ac == 1) {
1163: if ((b = BundFind(av[0])) == NULL)
1164: Error("Bund \"%s\" not found", av[0]);
1165: } else {
1166: if (ctx->bund) {
1167: b = ctx->bund;
1168: } else
1169: Error("No bundle selected to destroy");
1170: }
1171:
1172: if (b->tmpl) {
1173: b->tmpl = 0;
1174: b->stay = 0;
1175: BundShutdown(b);
1176: } else {
1177: b->stay = 0;
1178: if (b->n_up) {
1179: BundClose(b);
1180: } else {
1181: BundShutdown(b);
1182: }
1183: }
1184:
1185: return (0);
1186: }
1187:
1188: /*
1189: * BundInst()
1190: */
1191:
1192: Bund
1193: BundInst(Bund bt, char *name, int tmpl, int stay)
1194: {
1195: Bund b;
1196: int k;
1197:
1198: /* Create a new bundle structure */
1199: b = Mdup(MB_BUND, bt, sizeof(*b));
1200: b->tmpl = tmpl;
1201: b->stay = stay;
1202: b->refs = 0;
1203:
1204: /* Add bundle to the list of bundles and make it the current active bundle */
1205: for (k = 0; k < gNumBundles && gBundles[k] != NULL; k++);
1206: if (k == gNumBundles) /* add a new bundle pointer */
1207: LengthenArray(&gBundles, sizeof(*gBundles), &gNumBundles, MB_BUND);
1208:
1209: b->id = k;
1210: if (name)
1211: strlcpy(b->name, name, sizeof(b->name));
1212: else
1213: snprintf(b->name, sizeof(b->name), "%s-%d", bt->name, k);
1214: gBundles[k] = b;
1215: REF(b);
1216:
1217: /* Inst iface and NCP's */
1218: IfaceInst(b, bt);
1219: IpcpInst(b, bt);
1220: Ipv6cpInst(b, bt);
1221: CcpInst(b, bt);
1222: EcpInst(b, bt);
1223:
1224: if (!tmpl) {
1225: /* Setup netgraph stuff */
1226: if (BundNgInit(b) < 0) {
1227: Log(LG_ERR, ("[%s] Bundle netgraph initialization failed", b->name));
1228: gBundles[b->id] = NULL;
1229: Freee(b);
1230: return(0);
1231: }
1232: }
1233:
1234: return (b);
1235: }
1236:
1237: /*
1238: * BundShutdown()
1239: *
1240: * Shutdown the netgraph stuff associated with bundle
1241: */
1242:
1243: void
1244: BundShutdown(Bund b)
1245: {
1246: Link l;
1247: int k;
1248:
1249: Log(LG_BUND, ("[%s] Bundle: Shutdown", b->name));
1250: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1251: if ((l = b->links[k]) != NULL) {
1252: if (!l->stay)
1253: LinkShutdown(l);
1254: else {
1255: l->bund = NULL;
1256: b->links[k] = NULL;
1257: }
1258: }
1259: }
1260:
1261: if (b->hook[0])
1262: BundNgShutdown(b, 1, 1);
1263: gBundles[b->id] = NULL;
1264: MsgUnRegister(&b->msgs);
1265: b->dead = 1;
1266: IfaceDestroy(b);
1267: UNREF(b);
1268: }
1269:
1270: /*
1271: * BundStat()
1272: *
1273: * Show state of a bundle
1274: */
1275:
1276: int
1277: BundStat(Context ctx, int ac, char *av[], void *arg)
1278: {
1279: Bund sb;
1280: int k, bw, tbw, nup;
1281: char buf[64];
1282:
1283: /* Find bundle they're talking about */
1284: switch (ac) {
1285: case 0:
1286: sb = ctx->bund;
1287: break;
1288: case 1:
1289: if ((sb = BundFind(av[0])) == NULL)
1290: Error("Bundle \"%s\" not defined", av[0]);
1291: break;
1292: default:
1293: return(-1);
1294: }
1295:
1296: /* Show stuff about the bundle */
1297: for (tbw = bw = nup = k = 0; k < NG_PPP_MAX_LINKS; k++) {
1298: if (sb->links[k]) {
1299: if (sb->links[k]->lcp.phase == PHASE_NETWORK) {
1300: nup++;
1301: bw += sb->links[k]->bandwidth;
1302: }
1303: tbw += sb->links[k]->bandwidth;
1304: }
1305: }
1306:
1307: Printf("Bundle '%s'%s:\r\n", sb->name, sb->tmpl?" (template)":(sb->stay?" (static)":""));
1308: Printf("\tLinks : ");
1309: BundShowLinks(ctx, sb);
1310: Printf("\tStatus : %s\r\n", sb->open ? "OPEN" : "CLOSED");
1311: if (sb->n_up)
1312: Printf("\tSession time : %ld seconds\r\n", (long int)(time(NULL) - sb->last_up));
1313: Printf("\tMultiSession Id: %s\r\n", sb->msession_id);
1314: Printf("\tTotal bandwidth: %u bits/sec\r\n", tbw);
1315: Printf("\tAvail bandwidth: %u bits/sec\r\n", bw);
1316: Printf("\tPeer authname : \"%s\"\r\n", sb->params.authname);
1317:
1318: /* Show configuration */
1319: Printf("Configuration:\r\n");
1320: Printf("\tRetry timeout : %d seconds\r\n", sb->conf.retry_timeout);
1321: Printf("\tBW-manage:\r\n");
1322: Printf("\t Period : %d seconds\r\n", sb->conf.bm_S);
1323: Printf("\t Low mark : %d%%\r\n", sb->conf.bm_Lo);
1324: Printf("\t High mark : %d%%\r\n", sb->conf.bm_Hi);
1325: Printf("\t Min conn : %d seconds\r\n", sb->conf.bm_Mc);
1326: Printf("\t Min disc : %d seconds\r\n", sb->conf.bm_Md);
1327: Printf("\t Links : ");
1328: for (k = 0; k < NG_PPP_MAX_LINKS; k++)
1329: Printf("%s ", sb->conf.linkst[k]);
1330: Printf("\r\n");
1331: Printf("Bundle level options:\r\n");
1332: OptStat(ctx, &sb->conf.options, gConfList);
1333:
1334: /* Show peer info */
1335: Printf("Multilink PPP:\r\n");
1336: Printf("\tStatus : %s\r\n",
1337: sb->peer_mrru ? "Active" : "Inactive");
1338: if (sb->peer_mrru) {
1339: Printf("\tPeer MRRU : %d bytes\r\n", sb->peer_mrru);
1340: Printf("\tPeer auth name : \"%s\"\r\n", sb->params.authname);
1341: Printf("\tPeer discrimin.: %s\r\n", MpDiscrimText(&sb->peer_discrim, buf, sizeof(buf)));
1342: }
1343:
1344: if (!sb->tmpl) {
1345: /* Show stats */
1346: BundUpdateStats(sb);
1347: Printf("Traffic stats:\r\n");
1348:
1349: Printf("\tInput octets : %llu\r\n", (unsigned long long)sb->stats.recvOctets);
1350: Printf("\tInput frames : %llu\r\n", (unsigned long long)sb->stats.recvFrames);
1351: Printf("\tOutput octets : %llu\r\n", (unsigned long long)sb->stats.xmitOctets);
1352: Printf("\tOutput frames : %llu\r\n", (unsigned long long)sb->stats.xmitFrames);
1353: Printf("\tBad protocols : %llu\r\n", (unsigned long long)sb->stats.badProtos);
1354: Printf("\tRunts : %llu\r\n", (unsigned long long)sb->stats.runts);
1355: Printf("\tDup fragments : %llu\r\n", (unsigned long long)sb->stats.dupFragments);
1356: Printf("\tDrop fragments : %llu\r\n", (unsigned long long)sb->stats.dropFragments);
1357: }
1358:
1359: return(0);
1360: }
1361:
1362: /*
1363: * BundUpdateStats()
1364: */
1365:
1366: void
1367: BundUpdateStats(Bund b)
1368: {
1369: #ifndef NG_PPP_STATS64
1370: struct ng_ppp_link_stat stats;
1371: #endif
1372: int l = NG_PPP_BUNDLE_LINKNUM;
1373:
1374: #if (__FreeBSD_version < 602104 || (__FreeBSD_version >= 700000 && __FreeBSD_version < 700029))
1375: /* Workaround for broken ng_ppp bundle stats */
1376: if (!b->peer_mrru)
1377: l = 0;
1378: #endif
1379:
1380: #ifndef NG_PPP_STATS64
1381: if (NgFuncGetStats(b, l, &stats) != -1) {
1382: b->stats.xmitFrames += abs(stats.xmitFrames - b->oldStats.xmitFrames);
1383: b->stats.xmitOctets += abs(stats.xmitOctets - b->oldStats.xmitOctets);
1384: b->stats.recvFrames += abs(stats.recvFrames - b->oldStats.recvFrames);
1385: b->stats.recvOctets += abs(stats.recvOctets - b->oldStats.recvOctets);
1386: b->stats.badProtos += abs(stats.badProtos - b->oldStats.badProtos);
1387: b->stats.runts += abs(stats.runts - b->oldStats.runts);
1388: b->stats.dupFragments += abs(stats.dupFragments - b->oldStats.dupFragments);
1389: b->stats.dropFragments += abs(stats.dropFragments - b->oldStats.dropFragments);
1390: }
1391:
1392: b->oldStats = stats;
1393: #else
1394: NgFuncGetStats64(b, l, &b->stats);
1395: #endif
1396: }
1397:
1398: /*
1399: * BundUpdateStatsTimer()
1400: */
1401:
1402: void
1403: BundUpdateStatsTimer(void *cookie)
1404: {
1405: Bund b = (Bund)cookie;
1406: int k;
1407:
1408: BundUpdateStats(b);
1409: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1410: if (b->links[k] && b->links[k]->joined_bund)
1411: LinkUpdateStats(b->links[k]);
1412: }
1413: }
1414:
1415: /*
1416: * BundResetStats()
1417: */
1418:
1419: void
1420: BundResetStats(Bund b)
1421: {
1422: NgFuncClrStats(b, NG_PPP_BUNDLE_LINKNUM);
1423: memset(&b->stats, 0, sizeof(b->stats));
1424: #ifndef NG_PPP_STATS64
1425: memset(&b->oldStats, 0, sizeof(b->oldStats));
1426: #endif
1427: }
1428:
1429: /*
1430: * BundShowLinks()
1431: */
1432:
1433: void
1434: BundShowLinks(Context ctx, Bund sb)
1435: {
1436: int j;
1437:
1438: for (j = 0; j < NG_PPP_MAX_LINKS; j++) {
1439: if (sb->links[j]) {
1440: Printf("%s[%s/%s] ", sb->links[j]->name,
1441: FsmStateName(sb->links[j]->lcp.fsm.state),
1442: gPhysStateNames[sb->links[j]->state]);
1443: }
1444: }
1445: Printf("\r\n");
1446: }
1447:
1448: /*
1449: * BundFind()
1450: *
1451: * Find a bundle structure
1452: */
1453:
1454: Bund
1455: BundFind(const char *name)
1456: {
1457: int k;
1458:
1459: for (k = 0;
1460: k < gNumBundles && (!gBundles[k] || strcmp(gBundles[k]->name, name));
1461: k++);
1462: return((k < gNumBundles) ? gBundles[k] : NULL);
1463: }
1464:
1465: /*
1466: * BundBmStart()
1467: *
1468: * Start bandwidth management timer
1469: */
1470:
1471: static void
1472: BundBmStart(Bund b)
1473: {
1474: int k;
1475:
1476: /* Reset bandwidth management stats */
1477: memset(&b->bm.traffic, 0, sizeof(b->bm.traffic));
1478: memset(&b->bm.avail, 0, sizeof(b->bm.avail));
1479: memset(&b->bm.wasUp, 0, sizeof(b->bm.wasUp));
1480: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1481: if (b->links[k]) {
1482: memset(&b->links[k]->bm.idleStats,
1483: 0, sizeof(b->links[k]->bm.idleStats));
1484: }
1485: }
1486:
1487: /* Start bandwidth management timer */
1488: TimerStop(&b->bm.bmTimer);
1489: if (Enabled(&b->conf.options, BUND_CONF_BWMANAGE)) {
1490: TimerInit(&b->bm.bmTimer, "BundBm",
1491: (b->conf.bm_S * SECONDS) / BUND_BM_N,
1492: BundBmTimeout, b);
1493: TimerStart(&b->bm.bmTimer);
1494: }
1495: }
1496:
1497: /*
1498: * BundBmStop()
1499: */
1500:
1501: static void
1502: BundBmStop(Bund b)
1503: {
1504: TimerStop(&b->bm.bmTimer);
1505: }
1506:
1507: /*
1508: * BundBmTimeout()
1509: *
1510: * Do a bandwidth management update
1511: */
1512:
1513: static void
1514: BundBmTimeout(void *arg)
1515: {
1516: Bund b = (Bund)arg;
1517:
1518: const time_t now = time(NULL);
1519: u_int availTotal;
1520: u_int inUtilTotal = 0, outUtilTotal = 0;
1521: u_int inBitsTotal, outBitsTotal;
1522: u_int inUtil[BUND_BM_N]; /* Incoming % utilization */
1523: u_int outUtil[BUND_BM_N]; /* Outgoing % utilization */
1524: int j, k;
1525:
1526: /* Shift and update stats */
1527: memmove(&b->bm.wasUp[1], &b->bm.wasUp[0],
1528: (BUND_BM_N - 1) * sizeof(b->bm.wasUp[0]));
1529: b->bm.wasUp[0] = b->n_up;
1530: memmove(&b->bm.avail[1], &b->bm.avail[0],
1531: (BUND_BM_N - 1) * sizeof(b->bm.avail[0]));
1532: b->bm.avail[0] = b->bm.total_bw;
1533:
1534: /* Shift stats */
1535: memmove(&b->bm.traffic[0][1], &b->bm.traffic[0][0],
1536: (BUND_BM_N - 1) * sizeof(b->bm.traffic[0][0]));
1537: memmove(&b->bm.traffic[1][1], &b->bm.traffic[1][0],
1538: (BUND_BM_N - 1) * sizeof(b->bm.traffic[1][0]));
1539: b->bm.traffic[0][0] = 0;
1540: b->bm.traffic[1][0] = 0;
1541: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1542: if (b->links[k] && b->links[k]->joined_bund) {
1543: Link const l = b->links[k];
1544:
1545: struct ng_ppp_link_stat oldStats;
1546:
1547: /* Get updated link traffic statistics */
1548: oldStats = l->bm.idleStats;
1549: NgFuncGetStats(l->bund, l->bundleIndex, &l->bm.idleStats);
1550: b->bm.traffic[0][0] += l->bm.idleStats.recvOctets - oldStats.recvOctets;
1551: b->bm.traffic[1][0] += l->bm.idleStats.xmitOctets - oldStats.xmitOctets;
1552: }
1553: }
1554:
1555: /* Compute utilizations */
1556: memset(&inUtil, 0, sizeof(inUtil));
1557: memset(&outUtil, 0, sizeof(outUtil));
1558: availTotal = inBitsTotal = outBitsTotal = 0;
1559: for (j = 0; j < BUND_BM_N; j++) {
1560: u_int avail, inBits, outBits;
1561:
1562: avail = (b->bm.avail[j] * b->conf.bm_S) / BUND_BM_N;
1563: inBits = b->bm.traffic[0][j] * 8;
1564: outBits = b->bm.traffic[1][j] * 8;
1565:
1566: availTotal += avail;
1567: inBitsTotal += inBits;
1568: outBitsTotal += outBits;
1569:
1570: /* Compute bandwidth utilizations as percentages */
1571: if (avail != 0) {
1572: inUtil[j] = ((float) inBits / avail) * 100;
1573: outUtil[j] = ((float) outBits / avail) * 100;
1574: }
1575: }
1576:
1577: /* Compute total averaged utilization */
1578: if (availTotal != 0) {
1579: inUtilTotal = ((float) inBitsTotal / availTotal) * 100;
1580: outUtilTotal = ((float) outBitsTotal / availTotal) * 100;
1581: }
1582:
1583: {
1584: char ins[100], outs[100];
1585:
1586: ins[0] = 0;
1587: for (j = 0; j < BUND_BM_N; j++) {
1588: snprintf(ins + strlen(ins), sizeof(ins) - strlen(ins),
1589: " %3u ", b->bm.wasUp[BUND_BM_N - 1 - j]);
1590: }
1591: Log(LG_BUND2, ("[%s] %s", b->name, ins));
1592:
1593: snprintf(ins, sizeof(ins), " IN util: total %3u%% ", inUtilTotal);
1594: snprintf(outs, sizeof(outs), "OUT util: total %3u%% ", outUtilTotal);
1595: for (j = 0; j < BUND_BM_N; j++) {
1596: snprintf(ins + strlen(ins), sizeof(ins) - strlen(ins),
1597: " %3u%%", inUtil[BUND_BM_N - 1 - j]);
1598: snprintf(outs + strlen(outs), sizeof(outs) - strlen(outs),
1599: " %3u%%", outUtil[BUND_BM_N - 1 - j]);
1600: }
1601: Log(LG_BUND2, ("[%s] %s", b->name, ins));
1602: Log(LG_BUND2, ("[%s] %s", b->name, outs));
1603: }
1604:
1605: /* See if it's time to bring up another link */
1606: if (now - b->bm.last_open >= b->conf.bm_Mc
1607: && (inUtilTotal >= b->conf.bm_Hi || outUtilTotal >= b->conf.bm_Hi)) {
1608: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1609: cont:
1610: if (!b->links[k] && b->conf.linkst[k][0])
1611: break;
1612: }
1613: if (k < NG_PPP_MAX_LINKS) {
1614: Log(LG_BUND, ("[%s] opening link \"%s\" due to increased demand",
1615: b->name, b->conf.linkst[k]));
1616: b->bm.last_open = now;
1617: if (b->links[k]) {
1618: RecordLinkUpDownReason(NULL, b->links[k], 1, STR_PORT_NEEDED, NULL);
1619: BundOpenLink(b->links[k]);
1620: } else {
1621: if (BundCreateOpenLink(b, k)) {
1622: if (k < NG_PPP_MAX_LINKS) {
1623: k++;
1624: goto cont;
1625: }
1626: } else
1627: RecordLinkUpDownReason(NULL, b->links[k], 1, STR_PORT_NEEDED, NULL);
1628: }
1629: }
1630: }
1631:
1632: /* See if it's time to bring down a link */
1633: if (now - b->bm.last_close >= b->conf.bm_Md
1634: && (inUtilTotal < b->conf.bm_Lo && outUtilTotal < b->conf.bm_Lo)
1635: && b->n_links > 1) {
1636: k = NG_PPP_MAX_LINKS - 1;
1637: while (k >= 0 && (!b->links[k] || !OPEN_STATE(b->links[k]->lcp.fsm.state)))
1638: k--;
1639: assert(k >= 0);
1640: Log(LG_BUND, ("[%s] Bundle: closing link %s due to reduced demand",
1641: b->name, b->links[k]->name));
1642: b->bm.last_close = now;
1643: RecordLinkUpDownReason(NULL, b->links[k], 0, STR_PORT_UNNEEDED, NULL);
1644: BundCloseLink(b->links[k]);
1645: }
1646:
1647: /* Restart timer */
1648: TimerStart(&b->bm.bmTimer);
1649: }
1650:
1651: /*
1652: * BundNgInit()
1653: *
1654: * Setup the initial PPP netgraph framework. Initializes these fields
1655: * in the supplied bundle structure:
1656: *
1657: * iface.ifname - Interface name
1658: * csock - Control socket for socket netgraph node
1659: * dsock - Data socket for socket netgraph node
1660: *
1661: * Returns -1 if error.
1662: */
1663:
1664: static int
1665: BundNgInit(Bund b)
1666: {
1667: struct ngm_mkpeer mp;
1668: struct ngm_name nm;
1669: int newIface = 0;
1670: int newPpp = 0;
1671:
1672: /* Create new iface node */
1673: if (NgFuncCreateIface(b,
1674: b->iface.ifname, sizeof(b->iface.ifname)) < 0) {
1675: Log(LG_ERR, ("[%s] can't create netgraph interface", b->name));
1676: goto fail;
1677: }
1678: strlcpy(b->iface.ngname, b->iface.ifname, sizeof(b->iface.ngname));
1679: newIface = 1;
1680: b->iface.ifindex = if_nametoindex(b->iface.ifname);
1681: Log(LG_BUND|LG_IFACE, ("[%s] Bundle: Interface %s created",
1682: b->name, b->iface.ifname));
1683:
1684: /* Create new PPP node */
1685: snprintf(b->hook, sizeof(b->hook), "b%d", b->id);
1686: memset(&mp, 0, sizeof(mp));
1687: strcpy(mp.type, NG_PPP_NODE_TYPE);
1688: strcpy(mp.ourhook, b->hook);
1689: strcpy(mp.peerhook, NG_PPP_HOOK_BYPASS);
1690: if (NgSendMsg(gLinksCsock, ".:",
1691: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
1692: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
1693: b->name, mp.type, ".:", mp.ourhook);
1694: goto fail;
1695: }
1696: newPpp = 1;
1697:
1698: /* Get PPP node ID */
1699: b->nodeID = NgGetNodeID(gLinksCsock, b->hook);
1700:
1701: /* Give it a name */
1702: memset(&nm, 0, sizeof(nm));
1703: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", gPid, b->name);
1704: if (NgSendMsg(gLinksCsock, b->hook,
1705: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
1706: Perror("[%s] can't name %s node \"%s\"",
1707: b->name, NG_PPP_NODE_TYPE, b->hook);
1708: goto fail;
1709: }
1710:
1711: /* OK */
1712: return(0);
1713:
1714: fail:
1715: BundNgShutdown(b, newIface, newPpp);
1716: return(-1);
1717: }
1718:
1719: /*
1720: * NgFuncShutdown()
1721: */
1722:
1723: void
1724: BundNgShutdown(Bund b, int iface, int ppp)
1725: {
1726: char path[NG_PATHSIZ];
1727:
1728: if (iface) {
1729: snprintf(path, sizeof(path), "%s:", b->iface.ngname);
1730: NgFuncShutdownNode(gLinksCsock, b->name, path);
1731: }
1732: if (ppp) {
1733: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
1734: NgFuncShutdownNode(gLinksCsock, b->name, path);
1735: }
1736: b->hook[0] = 0;
1737: }
1738:
1739: /*
1740: * BundSetCommand()
1741: */
1742:
1743: static int
1744: BundSetCommand(Context ctx, int ac, char *av[], void *arg)
1745: {
1746: Bund b = ctx->bund;
1747: int i, val;
1748:
1749: if (ac == 0)
1750: return(-1);
1751: switch ((intptr_t)arg) {
1752: case SET_PERIOD:
1753: b->conf.bm_S = atoi(*av);
1754: break;
1755: case SET_LOW_WATER:
1756: b->conf.bm_Lo = atoi(*av);
1757: break;
1758: case SET_HIGH_WATER:
1759: b->conf.bm_Hi = atoi(*av);
1760: break;
1761: case SET_MIN_CONNECT:
1762: b->conf.bm_Mc = atoi(*av);
1763: break;
1764: case SET_MIN_DISCONNECT:
1765: b->conf.bm_Md = atoi(*av);
1766: break;
1767: case SET_LINKS:
1768: if (ac > NG_PPP_MAX_LINKS)
1769: return (-1);
1770: for (i = 0; i < ac; i++)
1771: strlcpy(b->conf.linkst[i], av[i], LINK_MAX_NAME);
1772: for (; i < NG_PPP_MAX_LINKS; i++)
1773: b->conf.linkst[i][0] = 0;
1774: break;
1775:
1776: case SET_RETRY:
1777: val = atoi(*av);
1778: if (val < 1 || val > 10)
1779: Error("[%s] incorrect fsm-timeout value %d", b->name, val);
1780: else
1781: b->conf.retry_timeout = val;
1782: break;
1783:
1784: case SET_ACCEPT:
1785: AcceptCommand(ac, av, &b->conf.options, gConfList);
1786: break;
1787:
1788: case SET_DENY:
1789: DenyCommand(ac, av, &b->conf.options, gConfList);
1790: break;
1791:
1792: case SET_ENABLE:
1793: EnableCommand(ac, av, &b->conf.options, gConfList);
1794: break;
1795:
1796: case SET_DISABLE:
1797: DisableCommand(ac, av, &b->conf.options, gConfList);
1798: break;
1799:
1800: case SET_YES:
1801: YesCommand(ac, av, &b->conf.options, gConfList);
1802: break;
1803:
1804: case SET_NO:
1805: NoCommand(ac, av, &b->conf.options, gConfList);
1806: break;
1807:
1808: default:
1809: assert(0);
1810: }
1811: return(0);
1812: }
1813:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>