Annotation of embedaddon/mpd/src/bund.c, revision 1.1.1.3
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,
1.1.1.3 ! misho 894: PhysGetMtu(b->links[the_link], 0));
1.1 misho 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;
1.1.1.2 misho 1138: IfaceDestroy(b);
1.1 misho 1139: Freee(b);
1140: Error("Bundle netgraph initialization failed");
1141: }
1142: }
1143: }
1144:
1145: RESETREF(ctx->bund, b);
1146:
1147: /* Done */
1148: return(0);
1149: }
1150:
1151: /*
1152: * BundDestroy()
1153: */
1154:
1155: int
1156: BundDestroy(Context ctx, int ac, char *av[], void *arg)
1157: {
1158: Bund b;
1159:
1160: if (ac > 1)
1161: return(-1);
1162:
1163: if (ac == 1) {
1164: if ((b = BundFind(av[0])) == NULL)
1165: Error("Bund \"%s\" not found", av[0]);
1166: } else {
1167: if (ctx->bund) {
1168: b = ctx->bund;
1169: } else
1170: Error("No bundle selected to destroy");
1171: }
1172:
1173: if (b->tmpl) {
1174: b->tmpl = 0;
1175: b->stay = 0;
1176: BundShutdown(b);
1177: } else {
1178: b->stay = 0;
1179: if (b->n_up) {
1180: BundClose(b);
1181: } else {
1182: BundShutdown(b);
1183: }
1184: }
1185:
1186: return (0);
1187: }
1188:
1189: /*
1190: * BundInst()
1191: */
1192:
1193: Bund
1194: BundInst(Bund bt, char *name, int tmpl, int stay)
1195: {
1196: Bund b;
1197: int k;
1198:
1199: /* Create a new bundle structure */
1200: b = Mdup(MB_BUND, bt, sizeof(*b));
1201: b->tmpl = tmpl;
1202: b->stay = stay;
1203: b->refs = 0;
1204:
1205: /* Add bundle to the list of bundles and make it the current active bundle */
1206: for (k = 0; k < gNumBundles && gBundles[k] != NULL; k++);
1207: if (k == gNumBundles) /* add a new bundle pointer */
1208: LengthenArray(&gBundles, sizeof(*gBundles), &gNumBundles, MB_BUND);
1209:
1210: b->id = k;
1211: if (name)
1212: strlcpy(b->name, name, sizeof(b->name));
1213: else
1214: snprintf(b->name, sizeof(b->name), "%s-%d", bt->name, k);
1215: gBundles[k] = b;
1216: REF(b);
1217:
1218: /* Inst iface and NCP's */
1219: IfaceInst(b, bt);
1220: IpcpInst(b, bt);
1221: Ipv6cpInst(b, bt);
1222: CcpInst(b, bt);
1223: EcpInst(b, bt);
1224:
1225: if (!tmpl) {
1226: /* Setup netgraph stuff */
1227: if (BundNgInit(b) < 0) {
1228: Log(LG_ERR, ("[%s] Bundle netgraph initialization failed", b->name));
1229: gBundles[b->id] = NULL;
1230: Freee(b);
1231: return(0);
1232: }
1233: }
1234:
1235: return (b);
1236: }
1237:
1238: /*
1239: * BundShutdown()
1240: *
1241: * Shutdown the netgraph stuff associated with bundle
1242: */
1243:
1244: void
1245: BundShutdown(Bund b)
1246: {
1247: Link l;
1248: int k;
1249:
1250: Log(LG_BUND, ("[%s] Bundle: Shutdown", b->name));
1251: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1252: if ((l = b->links[k]) != NULL) {
1253: if (!l->stay)
1254: LinkShutdown(l);
1255: else {
1256: l->bund = NULL;
1257: b->links[k] = NULL;
1258: }
1259: }
1260: }
1261:
1262: if (b->hook[0])
1263: BundNgShutdown(b, 1, 1);
1264: gBundles[b->id] = NULL;
1265: MsgUnRegister(&b->msgs);
1266: b->dead = 1;
1267: IfaceDestroy(b);
1268: UNREF(b);
1269: }
1270:
1271: /*
1272: * BundStat()
1273: *
1274: * Show state of a bundle
1275: */
1276:
1277: int
1278: BundStat(Context ctx, int ac, char *av[], void *arg)
1279: {
1280: Bund sb;
1281: int k, bw, tbw, nup;
1282: char buf[64];
1283:
1284: /* Find bundle they're talking about */
1285: switch (ac) {
1286: case 0:
1287: sb = ctx->bund;
1288: break;
1289: case 1:
1290: if ((sb = BundFind(av[0])) == NULL)
1291: Error("Bundle \"%s\" not defined", av[0]);
1292: break;
1293: default:
1294: return(-1);
1295: }
1296:
1297: /* Show stuff about the bundle */
1298: for (tbw = bw = nup = k = 0; k < NG_PPP_MAX_LINKS; k++) {
1299: if (sb->links[k]) {
1300: if (sb->links[k]->lcp.phase == PHASE_NETWORK) {
1301: nup++;
1302: bw += sb->links[k]->bandwidth;
1303: }
1304: tbw += sb->links[k]->bandwidth;
1305: }
1306: }
1307:
1308: Printf("Bundle '%s'%s:\r\n", sb->name, sb->tmpl?" (template)":(sb->stay?" (static)":""));
1309: Printf("\tLinks : ");
1310: BundShowLinks(ctx, sb);
1311: Printf("\tStatus : %s\r\n", sb->open ? "OPEN" : "CLOSED");
1312: if (sb->n_up)
1313: Printf("\tSession time : %ld seconds\r\n", (long int)(time(NULL) - sb->last_up));
1314: Printf("\tMultiSession Id: %s\r\n", sb->msession_id);
1315: Printf("\tTotal bandwidth: %u bits/sec\r\n", tbw);
1316: Printf("\tAvail bandwidth: %u bits/sec\r\n", bw);
1317: Printf("\tPeer authname : \"%s\"\r\n", sb->params.authname);
1318:
1319: /* Show configuration */
1320: Printf("Configuration:\r\n");
1.1.1.2 misho 1321: #ifdef SIOCSIFDESCR
1322: Printf("\tDesc. template : %s\r\n",
1323: sb->iface.conf.ifdescr ? sb->iface.conf.ifdescr : "<none>");
1324: Printf("\tDescription : %s\r\n",
1325: sb->iface.ifdescr ? sb->iface.ifdescr : "<none>");
1326: #endif
1.1 misho 1327: Printf("\tRetry timeout : %d seconds\r\n", sb->conf.retry_timeout);
1328: Printf("\tBW-manage:\r\n");
1329: Printf("\t Period : %d seconds\r\n", sb->conf.bm_S);
1330: Printf("\t Low mark : %d%%\r\n", sb->conf.bm_Lo);
1331: Printf("\t High mark : %d%%\r\n", sb->conf.bm_Hi);
1332: Printf("\t Min conn : %d seconds\r\n", sb->conf.bm_Mc);
1333: Printf("\t Min disc : %d seconds\r\n", sb->conf.bm_Md);
1334: Printf("\t Links : ");
1335: for (k = 0; k < NG_PPP_MAX_LINKS; k++)
1336: Printf("%s ", sb->conf.linkst[k]);
1337: Printf("\r\n");
1338: Printf("Bundle level options:\r\n");
1339: OptStat(ctx, &sb->conf.options, gConfList);
1340:
1341: /* Show peer info */
1342: Printf("Multilink PPP:\r\n");
1343: Printf("\tStatus : %s\r\n",
1344: sb->peer_mrru ? "Active" : "Inactive");
1345: if (sb->peer_mrru) {
1346: Printf("\tPeer MRRU : %d bytes\r\n", sb->peer_mrru);
1347: Printf("\tPeer auth name : \"%s\"\r\n", sb->params.authname);
1348: Printf("\tPeer discrimin.: %s\r\n", MpDiscrimText(&sb->peer_discrim, buf, sizeof(buf)));
1349: }
1350:
1351: if (!sb->tmpl) {
1352: /* Show stats */
1353: BundUpdateStats(sb);
1354: Printf("Traffic stats:\r\n");
1355:
1356: Printf("\tInput octets : %llu\r\n", (unsigned long long)sb->stats.recvOctets);
1357: Printf("\tInput frames : %llu\r\n", (unsigned long long)sb->stats.recvFrames);
1358: Printf("\tOutput octets : %llu\r\n", (unsigned long long)sb->stats.xmitOctets);
1359: Printf("\tOutput frames : %llu\r\n", (unsigned long long)sb->stats.xmitFrames);
1360: Printf("\tBad protocols : %llu\r\n", (unsigned long long)sb->stats.badProtos);
1361: Printf("\tRunts : %llu\r\n", (unsigned long long)sb->stats.runts);
1362: Printf("\tDup fragments : %llu\r\n", (unsigned long long)sb->stats.dupFragments);
1363: Printf("\tDrop fragments : %llu\r\n", (unsigned long long)sb->stats.dropFragments);
1364: }
1365:
1366: return(0);
1367: }
1368:
1369: /*
1370: * BundUpdateStats()
1371: */
1372:
1373: void
1374: BundUpdateStats(Bund b)
1375: {
1376: #ifndef NG_PPP_STATS64
1377: struct ng_ppp_link_stat stats;
1378: #endif
1379: int l = NG_PPP_BUNDLE_LINKNUM;
1380:
1381: #if (__FreeBSD_version < 602104 || (__FreeBSD_version >= 700000 && __FreeBSD_version < 700029))
1382: /* Workaround for broken ng_ppp bundle stats */
1383: if (!b->peer_mrru)
1384: l = 0;
1385: #endif
1386:
1387: #ifndef NG_PPP_STATS64
1388: if (NgFuncGetStats(b, l, &stats) != -1) {
1389: b->stats.xmitFrames += abs(stats.xmitFrames - b->oldStats.xmitFrames);
1390: b->stats.xmitOctets += abs(stats.xmitOctets - b->oldStats.xmitOctets);
1391: b->stats.recvFrames += abs(stats.recvFrames - b->oldStats.recvFrames);
1392: b->stats.recvOctets += abs(stats.recvOctets - b->oldStats.recvOctets);
1393: b->stats.badProtos += abs(stats.badProtos - b->oldStats.badProtos);
1394: b->stats.runts += abs(stats.runts - b->oldStats.runts);
1395: b->stats.dupFragments += abs(stats.dupFragments - b->oldStats.dupFragments);
1396: b->stats.dropFragments += abs(stats.dropFragments - b->oldStats.dropFragments);
1397: }
1398:
1399: b->oldStats = stats;
1400: #else
1401: NgFuncGetStats64(b, l, &b->stats);
1402: #endif
1403: }
1404:
1405: /*
1406: * BundUpdateStatsTimer()
1407: */
1408:
1409: void
1410: BundUpdateStatsTimer(void *cookie)
1411: {
1412: Bund b = (Bund)cookie;
1413: int k;
1414:
1415: BundUpdateStats(b);
1416: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1417: if (b->links[k] && b->links[k]->joined_bund)
1418: LinkUpdateStats(b->links[k]);
1419: }
1420: }
1421:
1422: /*
1423: * BundResetStats()
1424: */
1425:
1426: void
1427: BundResetStats(Bund b)
1428: {
1429: NgFuncClrStats(b, NG_PPP_BUNDLE_LINKNUM);
1430: memset(&b->stats, 0, sizeof(b->stats));
1431: #ifndef NG_PPP_STATS64
1432: memset(&b->oldStats, 0, sizeof(b->oldStats));
1433: #endif
1434: }
1435:
1436: /*
1437: * BundShowLinks()
1438: */
1439:
1440: void
1441: BundShowLinks(Context ctx, Bund sb)
1442: {
1443: int j;
1444:
1445: for (j = 0; j < NG_PPP_MAX_LINKS; j++) {
1446: if (sb->links[j]) {
1447: Printf("%s[%s/%s] ", sb->links[j]->name,
1448: FsmStateName(sb->links[j]->lcp.fsm.state),
1449: gPhysStateNames[sb->links[j]->state]);
1450: }
1451: }
1452: Printf("\r\n");
1453: }
1454:
1455: /*
1456: * BundFind()
1457: *
1458: * Find a bundle structure
1459: */
1460:
1461: Bund
1462: BundFind(const char *name)
1463: {
1464: int k;
1465:
1466: for (k = 0;
1467: k < gNumBundles && (!gBundles[k] || strcmp(gBundles[k]->name, name));
1468: k++);
1469: return((k < gNumBundles) ? gBundles[k] : NULL);
1470: }
1471:
1472: /*
1473: * BundBmStart()
1474: *
1475: * Start bandwidth management timer
1476: */
1477:
1478: static void
1479: BundBmStart(Bund b)
1480: {
1481: int k;
1482:
1483: /* Reset bandwidth management stats */
1484: memset(&b->bm.traffic, 0, sizeof(b->bm.traffic));
1485: memset(&b->bm.avail, 0, sizeof(b->bm.avail));
1486: memset(&b->bm.wasUp, 0, sizeof(b->bm.wasUp));
1487: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1488: if (b->links[k]) {
1489: memset(&b->links[k]->bm.idleStats,
1490: 0, sizeof(b->links[k]->bm.idleStats));
1491: }
1492: }
1493:
1494: /* Start bandwidth management timer */
1495: TimerStop(&b->bm.bmTimer);
1496: if (Enabled(&b->conf.options, BUND_CONF_BWMANAGE)) {
1497: TimerInit(&b->bm.bmTimer, "BundBm",
1498: (b->conf.bm_S * SECONDS) / BUND_BM_N,
1499: BundBmTimeout, b);
1500: TimerStart(&b->bm.bmTimer);
1501: }
1502: }
1503:
1504: /*
1505: * BundBmStop()
1506: */
1507:
1508: static void
1509: BundBmStop(Bund b)
1510: {
1511: TimerStop(&b->bm.bmTimer);
1512: }
1513:
1514: /*
1515: * BundBmTimeout()
1516: *
1517: * Do a bandwidth management update
1518: */
1519:
1520: static void
1521: BundBmTimeout(void *arg)
1522: {
1523: Bund b = (Bund)arg;
1524:
1525: const time_t now = time(NULL);
1526: u_int availTotal;
1527: u_int inUtilTotal = 0, outUtilTotal = 0;
1528: u_int inBitsTotal, outBitsTotal;
1529: u_int inUtil[BUND_BM_N]; /* Incoming % utilization */
1530: u_int outUtil[BUND_BM_N]; /* Outgoing % utilization */
1531: int j, k;
1532:
1533: /* Shift and update stats */
1534: memmove(&b->bm.wasUp[1], &b->bm.wasUp[0],
1535: (BUND_BM_N - 1) * sizeof(b->bm.wasUp[0]));
1536: b->bm.wasUp[0] = b->n_up;
1537: memmove(&b->bm.avail[1], &b->bm.avail[0],
1538: (BUND_BM_N - 1) * sizeof(b->bm.avail[0]));
1539: b->bm.avail[0] = b->bm.total_bw;
1540:
1541: /* Shift stats */
1542: memmove(&b->bm.traffic[0][1], &b->bm.traffic[0][0],
1543: (BUND_BM_N - 1) * sizeof(b->bm.traffic[0][0]));
1544: memmove(&b->bm.traffic[1][1], &b->bm.traffic[1][0],
1545: (BUND_BM_N - 1) * sizeof(b->bm.traffic[1][0]));
1546: b->bm.traffic[0][0] = 0;
1547: b->bm.traffic[1][0] = 0;
1548: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1549: if (b->links[k] && b->links[k]->joined_bund) {
1550: Link const l = b->links[k];
1551:
1552: struct ng_ppp_link_stat oldStats;
1553:
1554: /* Get updated link traffic statistics */
1555: oldStats = l->bm.idleStats;
1556: NgFuncGetStats(l->bund, l->bundleIndex, &l->bm.idleStats);
1557: b->bm.traffic[0][0] += l->bm.idleStats.recvOctets - oldStats.recvOctets;
1558: b->bm.traffic[1][0] += l->bm.idleStats.xmitOctets - oldStats.xmitOctets;
1559: }
1560: }
1561:
1562: /* Compute utilizations */
1563: memset(&inUtil, 0, sizeof(inUtil));
1564: memset(&outUtil, 0, sizeof(outUtil));
1565: availTotal = inBitsTotal = outBitsTotal = 0;
1566: for (j = 0; j < BUND_BM_N; j++) {
1567: u_int avail, inBits, outBits;
1568:
1569: avail = (b->bm.avail[j] * b->conf.bm_S) / BUND_BM_N;
1570: inBits = b->bm.traffic[0][j] * 8;
1571: outBits = b->bm.traffic[1][j] * 8;
1572:
1573: availTotal += avail;
1574: inBitsTotal += inBits;
1575: outBitsTotal += outBits;
1576:
1577: /* Compute bandwidth utilizations as percentages */
1578: if (avail != 0) {
1579: inUtil[j] = ((float) inBits / avail) * 100;
1580: outUtil[j] = ((float) outBits / avail) * 100;
1581: }
1582: }
1583:
1584: /* Compute total averaged utilization */
1585: if (availTotal != 0) {
1586: inUtilTotal = ((float) inBitsTotal / availTotal) * 100;
1587: outUtilTotal = ((float) outBitsTotal / availTotal) * 100;
1588: }
1589:
1590: {
1591: char ins[100], outs[100];
1592:
1593: ins[0] = 0;
1594: for (j = 0; j < BUND_BM_N; j++) {
1595: snprintf(ins + strlen(ins), sizeof(ins) - strlen(ins),
1596: " %3u ", b->bm.wasUp[BUND_BM_N - 1 - j]);
1597: }
1598: Log(LG_BUND2, ("[%s] %s", b->name, ins));
1599:
1600: snprintf(ins, sizeof(ins), " IN util: total %3u%% ", inUtilTotal);
1601: snprintf(outs, sizeof(outs), "OUT util: total %3u%% ", outUtilTotal);
1602: for (j = 0; j < BUND_BM_N; j++) {
1603: snprintf(ins + strlen(ins), sizeof(ins) - strlen(ins),
1604: " %3u%%", inUtil[BUND_BM_N - 1 - j]);
1605: snprintf(outs + strlen(outs), sizeof(outs) - strlen(outs),
1606: " %3u%%", outUtil[BUND_BM_N - 1 - j]);
1607: }
1608: Log(LG_BUND2, ("[%s] %s", b->name, ins));
1609: Log(LG_BUND2, ("[%s] %s", b->name, outs));
1610: }
1611:
1612: /* See if it's time to bring up another link */
1613: if (now - b->bm.last_open >= b->conf.bm_Mc
1614: && (inUtilTotal >= b->conf.bm_Hi || outUtilTotal >= b->conf.bm_Hi)) {
1615: for (k = 0; k < NG_PPP_MAX_LINKS; k++) {
1616: cont:
1617: if (!b->links[k] && b->conf.linkst[k][0])
1618: break;
1619: }
1620: if (k < NG_PPP_MAX_LINKS) {
1621: Log(LG_BUND, ("[%s] opening link \"%s\" due to increased demand",
1622: b->name, b->conf.linkst[k]));
1623: b->bm.last_open = now;
1624: if (b->links[k]) {
1625: RecordLinkUpDownReason(NULL, b->links[k], 1, STR_PORT_NEEDED, NULL);
1626: BundOpenLink(b->links[k]);
1627: } else {
1628: if (BundCreateOpenLink(b, k)) {
1629: if (k < NG_PPP_MAX_LINKS) {
1630: k++;
1631: goto cont;
1632: }
1633: } else
1634: RecordLinkUpDownReason(NULL, b->links[k], 1, STR_PORT_NEEDED, NULL);
1635: }
1636: }
1637: }
1638:
1639: /* See if it's time to bring down a link */
1640: if (now - b->bm.last_close >= b->conf.bm_Md
1641: && (inUtilTotal < b->conf.bm_Lo && outUtilTotal < b->conf.bm_Lo)
1642: && b->n_links > 1) {
1643: k = NG_PPP_MAX_LINKS - 1;
1644: while (k >= 0 && (!b->links[k] || !OPEN_STATE(b->links[k]->lcp.fsm.state)))
1645: k--;
1646: assert(k >= 0);
1647: Log(LG_BUND, ("[%s] Bundle: closing link %s due to reduced demand",
1648: b->name, b->links[k]->name));
1649: b->bm.last_close = now;
1650: RecordLinkUpDownReason(NULL, b->links[k], 0, STR_PORT_UNNEEDED, NULL);
1651: BundCloseLink(b->links[k]);
1652: }
1653:
1654: /* Restart timer */
1655: TimerStart(&b->bm.bmTimer);
1656: }
1657:
1658: /*
1659: * BundNgInit()
1660: *
1661: * Setup the initial PPP netgraph framework. Initializes these fields
1662: * in the supplied bundle structure:
1663: *
1664: * iface.ifname - Interface name
1665: * csock - Control socket for socket netgraph node
1666: * dsock - Data socket for socket netgraph node
1667: *
1668: * Returns -1 if error.
1669: */
1670:
1671: static int
1672: BundNgInit(Bund b)
1673: {
1674: struct ngm_mkpeer mp;
1675: struct ngm_name nm;
1676: int newIface = 0;
1677: int newPpp = 0;
1678:
1679: /* Create new iface node */
1680: if (NgFuncCreateIface(b,
1681: b->iface.ifname, sizeof(b->iface.ifname)) < 0) {
1682: Log(LG_ERR, ("[%s] can't create netgraph interface", b->name));
1683: goto fail;
1684: }
1685: strlcpy(b->iface.ngname, b->iface.ifname, sizeof(b->iface.ngname));
1686: newIface = 1;
1687: b->iface.ifindex = if_nametoindex(b->iface.ifname);
1688: Log(LG_BUND|LG_IFACE, ("[%s] Bundle: Interface %s created",
1689: b->name, b->iface.ifname));
1690:
1691: /* Create new PPP node */
1692: snprintf(b->hook, sizeof(b->hook), "b%d", b->id);
1693: memset(&mp, 0, sizeof(mp));
1694: strcpy(mp.type, NG_PPP_NODE_TYPE);
1695: strcpy(mp.ourhook, b->hook);
1696: strcpy(mp.peerhook, NG_PPP_HOOK_BYPASS);
1697: if (NgSendMsg(gLinksCsock, ".:",
1698: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
1699: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
1700: b->name, mp.type, ".:", mp.ourhook);
1701: goto fail;
1702: }
1703: newPpp = 1;
1704:
1705: /* Get PPP node ID */
1706: b->nodeID = NgGetNodeID(gLinksCsock, b->hook);
1707:
1708: /* Give it a name */
1709: memset(&nm, 0, sizeof(nm));
1710: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", gPid, b->name);
1711: if (NgSendMsg(gLinksCsock, b->hook,
1712: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
1713: Perror("[%s] can't name %s node \"%s\"",
1714: b->name, NG_PPP_NODE_TYPE, b->hook);
1715: goto fail;
1716: }
1717:
1718: /* OK */
1719: return(0);
1720:
1721: fail:
1722: BundNgShutdown(b, newIface, newPpp);
1723: return(-1);
1724: }
1725:
1726: /*
1727: * NgFuncShutdown()
1728: */
1729:
1730: void
1731: BundNgShutdown(Bund b, int iface, int ppp)
1732: {
1733: char path[NG_PATHSIZ];
1734:
1735: if (iface) {
1736: snprintf(path, sizeof(path), "%s:", b->iface.ngname);
1737: NgFuncShutdownNode(gLinksCsock, b->name, path);
1738: }
1739: if (ppp) {
1740: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
1741: NgFuncShutdownNode(gLinksCsock, b->name, path);
1742: }
1743: b->hook[0] = 0;
1744: }
1745:
1746: /*
1747: * BundSetCommand()
1748: */
1749:
1750: static int
1751: BundSetCommand(Context ctx, int ac, char *av[], void *arg)
1752: {
1753: Bund b = ctx->bund;
1754: int i, val;
1755:
1756: if (ac == 0)
1757: return(-1);
1758: switch ((intptr_t)arg) {
1759: case SET_PERIOD:
1760: b->conf.bm_S = atoi(*av);
1761: break;
1762: case SET_LOW_WATER:
1763: b->conf.bm_Lo = atoi(*av);
1764: break;
1765: case SET_HIGH_WATER:
1766: b->conf.bm_Hi = atoi(*av);
1767: break;
1768: case SET_MIN_CONNECT:
1769: b->conf.bm_Mc = atoi(*av);
1770: break;
1771: case SET_MIN_DISCONNECT:
1772: b->conf.bm_Md = atoi(*av);
1773: break;
1774: case SET_LINKS:
1775: if (ac > NG_PPP_MAX_LINKS)
1776: return (-1);
1777: for (i = 0; i < ac; i++)
1778: strlcpy(b->conf.linkst[i], av[i], LINK_MAX_NAME);
1779: for (; i < NG_PPP_MAX_LINKS; i++)
1780: b->conf.linkst[i][0] = 0;
1781: break;
1782:
1783: case SET_RETRY:
1784: val = atoi(*av);
1785: if (val < 1 || val > 10)
1786: Error("[%s] incorrect fsm-timeout value %d", b->name, val);
1787: else
1788: b->conf.retry_timeout = val;
1789: break;
1790:
1791: case SET_ACCEPT:
1792: AcceptCommand(ac, av, &b->conf.options, gConfList);
1793: break;
1794:
1795: case SET_DENY:
1796: DenyCommand(ac, av, &b->conf.options, gConfList);
1797: break;
1798:
1799: case SET_ENABLE:
1800: EnableCommand(ac, av, &b->conf.options, gConfList);
1801: break;
1802:
1803: case SET_DISABLE:
1804: DisableCommand(ac, av, &b->conf.options, gConfList);
1805: break;
1806:
1807: case SET_YES:
1808: YesCommand(ac, av, &b->conf.options, gConfList);
1809: break;
1810:
1811: case SET_NO:
1812: NoCommand(ac, av, &b->conf.options, gConfList);
1813: break;
1814:
1815: default:
1816: assert(0);
1817: }
1818: return(0);
1819: }
1820:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>