From 04eaa58c59b2ef73f89c48a9a7ea4ccdf2805e73 Mon Sep 17 00:00:00 2001 From: Brian Somers Date: Thu, 21 May 1998 01:13:32 +0000 Subject: o Add `set autoload'. You can now set the minimum and maximum thresholds (in terms of queued packets for a period of time) where -auto links will be brought up and down. By default, all auto links come up when we reach NETWORK phase and never go down. o Display current autoload state in `show bundle'. o Disable the idle timer as soon as it's called. o Disable the idle and autoload timers when exiting (in case we're abending). --- usr.sbin/ppp/bundle.c | 322 ++++++++++++++++++++++++++++++++++++++----------- usr.sbin/ppp/bundle.h | 17 ++- usr.sbin/ppp/command.c | 63 ++++++---- usr.sbin/ppp/ppp.8 | 32 ++++- 4 files changed, 340 insertions(+), 94 deletions(-) (limited to 'usr.sbin') diff --git a/usr.sbin/ppp/bundle.c b/usr.sbin/ppp/bundle.c index 0029f0e01fad..cf1fe4bfacef 100644 --- a/usr.sbin/ppp/bundle.c +++ b/usr.sbin/ppp/bundle.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bundle.c,v 1.1.2.87 1998/05/19 21:51:19 brian Exp $ + * $Id: bundle.c,v 1.1.2.88 1998/05/19 23:05:10 brian Exp $ */ #include @@ -87,6 +87,9 @@ #define SOCKET_OVERHEAD 100 /* additional buffer space for large */ /* {recv,send}msg() calls */ +static int bundle_RemainingIdleTime(struct bundle *); +static int bundle_RemainingAutoLoadTime(struct bundle *); + static const char *PhaseNames[] = { "Dead", "Establish", "Authenticate", "Network", "Terminate" }; @@ -202,13 +205,106 @@ bundle_Notify(struct bundle *bundle, char c) } } +static void +bundle_AutoLoadTimeout(void *v) +{ + struct bundle *bundle = (struct bundle *)v; + + if (bundle->autoload.comingup) { + log_Printf(LogPHASE, "autoload: Another link is required\n"); + /* bundle_Open() stops the timer */ + bundle_Open(bundle, NULL, PHYS_DEMAND); + } else { + struct datalink *dl, *last; + + timer_Stop(&bundle->autoload.timer); + for (last = NULL, dl = bundle->links; dl; dl = dl->next) + if (dl->physical->type == PHYS_DEMAND && dl->state == DATALINK_OPEN) + last = dl; + + if (last) + datalink_Close(last, 1); + } +} + +static void +bundle_StartAutoLoadTimer(struct bundle *bundle, int up) +{ + struct datalink *dl; + + timer_Stop(&bundle->autoload.timer); + + if (bundle->CleaningUp || bundle->phase != PHASE_NETWORK) { + dl = NULL; + bundle->autoload.running = 0; + } else if (up) { + for (dl = bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_CLOSED && dl->physical->type == PHYS_DEMAND) { + if (bundle->cfg.autoload.max.timeout) { + bundle->autoload.timer.func = bundle_AutoLoadTimeout; + bundle->autoload.timer.name = "autoload up"; + bundle->autoload.timer.load = + bundle->cfg.autoload.max.timeout * SECTICKS; + bundle->autoload.timer.arg = bundle; + timer_Start(&bundle->autoload.timer); + bundle->autoload.done = time(NULL) + bundle->cfg.autoload.max.timeout; + } else + bundle_AutoLoadTimeout(bundle); + break; + } + bundle->autoload.running = (dl || bundle->cfg.autoload.min.timeout) ? 1 : 0; + } else { + int nlinks; + struct datalink *adl; + + for (nlinks = 0, adl = NULL, dl = bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_OPEN) { + if (dl->physical->type == PHYS_DEMAND) + adl = dl; + if (++nlinks > 1 && adl) { + if (bundle->cfg.autoload.min.timeout) { + bundle->autoload.timer.func = bundle_AutoLoadTimeout; + bundle->autoload.timer.name = "autoload down"; + bundle->autoload.timer.load = + bundle->cfg.autoload.min.timeout * SECTICKS; + bundle->autoload.timer.arg = bundle; + timer_Start(&bundle->autoload.timer); + bundle->autoload.done = + time(NULL) + bundle->cfg.autoload.min.timeout; + } + break; + } + } + + bundle->autoload.running = 1; + } + + bundle->autoload.comingup = up ? 1 : 0; +} + +static void +bundle_StopAutoLoadTimer(struct bundle *bundle) +{ + timer_Stop(&bundle->autoload.timer); + bundle->autoload.done = 0; +} + +static int +bundle_RemainingAutoLoadTime(struct bundle *bundle) +{ + if (bundle->autoload.done) + return bundle->autoload.done - time(NULL); + return -1; +} + + static void bundle_LayerUp(void *v, struct fsm *fp) { /* * The given fsm is now up * If it's an LCP set our mtu (if we're multilink, add up the link - * speeds and set the MRRU). + * speeds and set the MRRU) and start our autoload timer. * If it's an NCP, tell our -background parent to go away. * If it's the first NCP, start the idle timer. */ @@ -223,6 +319,7 @@ bundle_LayerUp(void *v, struct fsm *fp) if (dl->state == DATALINK_OPEN) bundle->ifp.Speed += modem_Speed(dl->physical); tun_configure(bundle, bundle->ncp.mp.peer_mrru); + bundle->autoload.running = 1; } else { bundle->ifp.Speed = modem_Speed(link2physical(fp->link)); tun_configure(bundle, fsm2lcp(fp)->his_mru); @@ -335,6 +432,8 @@ bundle_Close(struct bundle *bundle, const char *name, int staydown) } if (!others_active) { + bundle_StopIdleTimer(bundle); + bundle_StopAutoLoadTimer(bundle); if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || bundle->ncp.ipcp.fsm.state == ST_STARTING) fsm_Close(&bundle->ncp.ipcp.fsm); @@ -366,7 +465,7 @@ bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) struct bundle *bundle = descriptor2bundle(d); struct datalink *dl; struct descriptor *desc; - int result; + int result, want, queued, nlinks; result = 0; for (dl = bundle->links; dl; dl = dl->next) @@ -376,18 +475,44 @@ bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) result += descriptor_UpdateSet(desc, r, w, e, n); /* If there are aren't many packets queued, look for some more. */ - if (r && bundle->links && bundle_FillQueues(bundle) < 20) { - if (*n < bundle->dev.fd + 1) - *n = bundle->dev.fd + 1; - FD_SET(bundle->dev.fd, r); - log_Printf(LogTIMER, "tun: fdset(r) %d\n", bundle->dev.fd); - result++; + for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) + nlinks++; + + if (nlinks) { + queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(); + if (bundle->autoload.running) { + if (queued < bundle->cfg.autoload.max.packets) { + if (queued > bundle->cfg.autoload.min.packets) + bundle_StopAutoLoadTimer(bundle); + else if (bundle->autoload.timer.state != TIMER_RUNNING || + bundle->autoload.comingup) + bundle_StartAutoLoadTimer(bundle, 0); + } else if (bundle->autoload.timer.state != TIMER_RUNNING || + !bundle->autoload.comingup) + bundle_StartAutoLoadTimer(bundle, 1); + } + + if (r) { + /* enough surplus so that we can tell if we're getting swamped */ + want = bundle->cfg.autoload.max.packets + nlinks * 2; + /* but at least 20 packets ! */ + if (want < 20) + want = 20; + if (queued < want) { + /* Not enough - select() for more */ + FD_SET(bundle->dev.fd, r); + if (*n < bundle->dev.fd + 1) + *n = bundle->dev.fd + 1; + log_Printf(LogTIMER, "tun: fdset(r) %d\n", bundle->dev.fd); + result++; + } + } } /* * This *MUST* be called after the datalink UpdateSet()s as it - * might be ``holding'' one of the datalinks and wants to be - * able to de-select() from the descriptor set + * might be ``holding'' one of the datalinks (death-row) and + * wants to be able to de-select() it from the descriptor set. */ descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); @@ -637,6 +762,10 @@ bundle_Create(const char *prefix, struct prompt *prompt, int type) OPT_THROUGHPUT | OPT_UTMP; *bundle.cfg.label = '\0'; bundle.cfg.mtu = DEF_MTU; + bundle.cfg.autoload.max.packets = 0; + bundle.cfg.autoload.max.timeout = 0; + bundle.cfg.autoload.min.packets = 0; + bundle.cfg.autoload.min.timeout = 0; bundle.phys_type = type; bundle.links = datalink_Create("deflink", &bundle, type); @@ -672,6 +801,9 @@ bundle_Create(const char *prefix, struct prompt *prompt, int type) memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); bundle.idle.done = 0; bundle.notify.fd = -1; + memset(&bundle.autoload.timer, '\0', sizeof bundle.autoload.timer); + bundle.autoload.done = 0; + bundle.autoload.running = 0; /* Clean out any leftover crud */ bundle_CleanInterface(&bundle); @@ -725,10 +857,12 @@ bundle_Destroy(struct bundle *bundle) struct descriptor *desc, *ndesc; /* - * Clean up the interface. We don't need to mp_Down(), + * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting * out under exceptional conditions such as a descriptor exception. */ + timer_Stop(&bundle->idle.timer); + timer_Stop(&bundle->autoload.timer); mp_Down(&bundle->ncp.mp); ipcp_CleanInterface(&bundle->ncp.ipcp); bundle_DownInterface(bundle); @@ -907,7 +1041,10 @@ bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) } bundle_NewPhase(bundle, PHASE_DEAD); bundle_DisplayPrompt(bundle); - } + bundle_StopAutoLoadTimer(bundle); + bundle->autoload.running = 0; + } else + bundle->autoload.running = 1; } void @@ -918,10 +1055,15 @@ bundle_Open(struct bundle *bundle, const char *name, int mask) */ struct datalink *dl; + timer_Stop(&bundle->autoload.timer); for (dl = bundle->links; dl; dl = dl->next) if (name == NULL || !strcasecmp(dl->name, name)) { - if (mask & dl->physical->type) + if (dl->state == DATALINK_CLOSED && (mask & dl->physical->type)) { datalink_Up(dl, 1, 1); + if (mask == PHYS_DEMAND) + /* Only one DEMAND link at a time (see the AutoLoad timer) */ + break; + } if (name != NULL) break; } @@ -1002,6 +1144,22 @@ bundle_ShowStatus(struct cmdargs const *arg) prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); prompt_Printf(arg->prompt, " Auth name: %s\n", arg->bundle->cfg.auth.name); + prompt_Printf(arg->prompt, " Auto Load: Up after %ds of >= %d packets\n", + arg->bundle->cfg.autoload.max.timeout, + arg->bundle->cfg.autoload.max.packets); + prompt_Printf(arg->prompt, " Down after %ds of <= %d" + " packets\n", arg->bundle->cfg.autoload.min.timeout, + arg->bundle->cfg.autoload.min.packets); + if (arg->bundle->autoload.timer.state == TIMER_RUNNING) + prompt_Printf(arg->prompt, " %ds remaining 'till " + "a link comes %s\n", + bundle_RemainingAutoLoadTime(arg->bundle), + arg->bundle->autoload.comingup ? "up" : "down"); + else + prompt_Printf(arg->prompt, " %srunning with %d" + " packets queued\n", arg->bundle->autoload.running ? + "" : "not ", ip_QueueLen()); + prompt_Printf(arg->prompt, " Idle Timer: "); if (arg->bundle->cfg.idle_timeout) { prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout); @@ -1040,8 +1198,8 @@ bundle_IdleTimeout(void *v) { struct bundle *bundle = (struct bundle *)v; - bundle->idle.done = 0; log_Printf(LogPHASE, "Idle timer expired.\n"); + bundle_StopIdleTimer(bundle); bundle_Close(bundle, NULL, 1); } @@ -1052,16 +1210,15 @@ bundle_IdleTimeout(void *v) void bundle_StartIdleTimer(struct bundle *bundle) { - if (!(bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM))) { - timer_Stop(&bundle->idle.timer); - if (bundle->cfg.idle_timeout) { - bundle->idle.timer.func = bundle_IdleTimeout; - bundle->idle.timer.name = "idle"; - bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS; - bundle->idle.timer.arg = bundle; - timer_Start(&bundle->idle.timer); - bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout; - } + timer_Stop(&bundle->idle.timer); + if ((bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM)) != bundle->phys_type && + bundle->cfg.idle_timeout) { + bundle->idle.timer.func = bundle_IdleTimeout; + bundle->idle.timer.name = "idle"; + bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS; + bundle->idle.timer.arg = bundle; + timer_Start(&bundle->idle.timer); + bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout; } } @@ -1080,7 +1237,7 @@ bundle_StopIdleTimer(struct bundle *bundle) bundle->idle.done = 0; } -int +static int bundle_RemainingIdleTime(struct bundle *bundle) { if (bundle->idle.done) @@ -1173,60 +1330,96 @@ bundle_SetTtyCommandMode(struct bundle *bundle, struct datalink *dl) } static void -bundle_GenPhysType(struct bundle *bundle) +bundle_LinkAdded(struct bundle *bundle, struct datalink *dl) +{ + bundle->phys_type |= dl->physical->type; + if (dl->physical->type == PHYS_DEMAND && + bundle->autoload.timer.state == TIMER_STOPPED && + bundle->phase == PHASE_NETWORK) + bundle->autoload.running = 1; +} + +static void +bundle_LinksRemoved(struct bundle *bundle) { struct datalink *dl; bundle->phys_type = 0; for (dl = bundle->links; dl; dl = dl->next) - bundle->phys_type |= dl->physical->type; -} - -int -bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, - const char *name) -{ - struct datalink *ndl; - - ndl = bundle2datalink(bundle, name); - if (!ndl) { - ndl = datalink_Clone(dl, name); - ndl->next = dl->next; - dl->next = ndl; - bundle_GenPhysType(bundle); - return 1; - } + bundle_LinkAdded(bundle, dl); - log_Printf(LogWARN, "Clone: %s: name already exists\n", ndl->name); - return 0; + if ((bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM)) == bundle->phys_type) + timer_Stop(&bundle->idle.timer); } -void -bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) +static struct datalink * +bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) { struct datalink **dlp; if (dl->state == DATALINK_CLOSED) for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) if (*dlp == dl) { - *dlp = datalink_Destroy(dl); - break; + *dlp = dl->next; + dl->next = NULL; + bundle_LinksRemoved(bundle); + return dl; } - bundle_GenPhysType(bundle); + + return NULL; +} + +static void +bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) +{ + struct datalink **dlp = &bundle->links; + + while (*dlp) + dlp = &(*dlp)->next; + + *dlp = dl; + dl->next = NULL; + + bundle_LinkAdded(bundle, dl); } void bundle_CleanDatalinks(struct bundle *bundle) { struct datalink **dlp = &bundle->links; + int found = 0; while (*dlp) if ((*dlp)->state == DATALINK_CLOSED && - (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF)) + (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF)) { *dlp = datalink_Destroy(*dlp); - else + found++; + } else dlp = &(*dlp)->next; - bundle_GenPhysType(bundle); + + if (found) + bundle_LinksRemoved(bundle); +} + +int +bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, + const char *name) +{ + if (bundle2datalink(bundle, name)) { + log_Printf(LogWARN, "Clone: %s: name already exists\n", name); + return 0; + } + + bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); + return 1; +} + +void +bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) +{ + dl = bundle_DatalinkLinkout(bundle, dl); + if (dl) + datalink_Destroy(dl); } void @@ -1310,9 +1503,7 @@ bundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun) niov = 1; dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd); if (dl) { - dl->next = bundle->links; - bundle->links = dl; - bundle_GenPhysType(bundle); + bundle_DatalinkLinkin(bundle, dl); datalink_AuthOk(dl); } else close(link_fd); @@ -1328,21 +1519,11 @@ bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) struct msghdr msg; struct iovec iov[SCATTER_SEGMENTS]; int niov, link_fd, f, expect; - struct datalink **pdl; - struct bundle *bundle = dl->bundle; log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); - /* First, un-hook the datalink */ - for (pdl = &bundle->links; *pdl; pdl = &(*pdl)->next) - if (*pdl == dl) { - *pdl = dl->next; - dl->next = NULL; - break; - } - - bundle_GenPhysType(bundle); - bundle_LinkClosed(bundle, dl); + bundle_DatalinkLinkout(dl->bundle, dl); + bundle_LinkClosed(dl->bundle, dl); /* Build our scatter/gather array */ iov[0].iov_len = strlen(Version) + 1; @@ -1423,7 +1604,8 @@ bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) if (mode == PHYS_DEMAND && !(bundle->phys_type & PHYS_DEMAND)) ipcp_InterfaceUp(&bundle->ncp.ipcp); - bundle_GenPhysType(bundle); + /* Regenerate phys_type and adjust autoload & idle timers */ + bundle_LinksRemoved(bundle); if (omode == PHYS_DEMAND && !(bundle->phys_type & PHYS_DEMAND)) /* Changing from demand-dial mode */ diff --git a/usr.sbin/ppp/bundle.h b/usr.sbin/ppp/bundle.h index 1c1daf567dea..36ef9657b844 100644 --- a/usr.sbin/ppp/bundle.h +++ b/usr.sbin/ppp/bundle.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bundle.h,v 1.1.2.40 1998/05/15 23:58:15 brian Exp $ + * $Id: bundle.h,v 1.1.2.41 1998/05/16 23:47:21 brian Exp $ */ #define PHASE_DEAD 0 /* Link is dead */ @@ -85,6 +85,13 @@ struct bundle { unsigned opt; /* Uses OPT_ bits from above */ char label[50]; /* last thing `load'ed */ u_short mtu; /* Interface mtu */ + + struct { /* We need/don't need another link when */ + struct { /* more/less than */ + int packets; /* this number of packets are queued for */ + int timeout; /* this number of seconds */ + } max, min; + } autoload; } cfg; struct { @@ -107,6 +114,13 @@ struct bundle { struct { int fd; /* write status here */ } notify; + + struct { + struct pppTimer timer; + time_t done; + unsigned running : 1; + unsigned comingup : 1; + } autoload; }; #define descriptor2bundle(d) \ @@ -131,7 +145,6 @@ extern int bundle_ShowStatus(struct cmdargs const *); extern void bundle_StartIdleTimer(struct bundle *); extern void bundle_SetIdleTimer(struct bundle *, int); extern void bundle_StopIdleTimer(struct bundle *); -extern int bundle_RemainingIdleTime(struct bundle *); extern int bundle_IsDead(struct bundle *); extern struct datalink *bundle2datalink(struct bundle *, const char *); diff --git a/usr.sbin/ppp/command.c b/usr.sbin/ppp/command.c index f14f467b794f..2f9765f9fe9f 100644 --- a/usr.sbin/ppp/command.c +++ b/usr.sbin/ppp/command.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: command.c,v 1.131.2.86 1998/05/16 23:47:41 brian Exp $ + * $Id: command.c,v 1.131.2.87 1998/05/19 19:58:18 brian Exp $ * */ #include @@ -85,25 +85,26 @@ #define VAR_DIAL 1 #define VAR_LOGIN 2 #define VAR_AUTHNAME 3 -#define VAR_WINSIZE 4 -#define VAR_DEVICE 5 -#define VAR_ACCMAP 6 -#define VAR_MRRU 7 -#define VAR_MRU 8 -#define VAR_MTU 9 -#define VAR_OPENMODE 10 -#define VAR_PHONE 11 -#define VAR_HANGUP 12 -#define VAR_IDLETIMEOUT 13 -#define VAR_LQRPERIOD 14 -#define VAR_LCPRETRY 15 -#define VAR_CHAPRETRY 16 -#define VAR_PAPRETRY 17 -#define VAR_CCPRETRY 18 -#define VAR_IPCPRETRY 19 -#define VAR_DNS 20 -#define VAR_NBNS 21 -#define VAR_MODE 22 +#define VAR_AUTOLOAD 4 +#define VAR_WINSIZE 5 +#define VAR_DEVICE 6 +#define VAR_ACCMAP 7 +#define VAR_MRRU 8 +#define VAR_MRU 9 +#define VAR_MTU 10 +#define VAR_OPENMODE 11 +#define VAR_PHONE 12 +#define VAR_HANGUP 13 +#define VAR_IDLETIMEOUT 14 +#define VAR_LQRPERIOD 15 +#define VAR_LCPRETRY 16 +#define VAR_CHAPRETRY 17 +#define VAR_PAPRETRY 18 +#define VAR_CCPRETRY 19 +#define VAR_IPCPRETRY 20 +#define VAR_DNS 21 +#define VAR_NBNS 22 +#define VAR_MODE 23 /* ``accept|deny|disable|enable'' masks */ #define NEG_HISMASK (1) @@ -123,7 +124,7 @@ #define NEG_DNS 50 const char Version[] = "2.0-beta"; -const char VersionDate[] = "$Date: 1998/05/16 23:47:41 $"; +const char VersionDate[] = "$Date: 1998/05/19 19:58:18 $"; static int ShowCommand(struct cmdargs const *); static int TerminalCommand(struct cmdargs const *); @@ -1196,6 +1197,23 @@ SetVariable(struct cmdargs const *arg) log_Printf(LogWARN, err); } break; + case VAR_AUTOLOAD: + if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) { + arg->bundle->autoload.running = 1; + arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]); + arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]); + if (arg->argc == arg->argn + 4) { + arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]); + arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]); + } else { + arg->bundle->cfg.autoload.min.timeout = 0; + arg->bundle->cfg.autoload.min.packets = 0; + } + } else { + err = "Set autoload requires two or four arguments\n"; + log_Printf(LogWARN, err); + } + break; case VAR_DIAL: strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; @@ -1412,6 +1430,9 @@ static struct cmdtab const SetCommands[] = { "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, {"authname", NULL, SetVariable, LOCAL_AUTH, "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, + {"autoload", NULL, SetVariable, LOCAL_AUTH, + "auto link [de]activation", "set autoload maxtime maxload mintime minload", + (const void *)VAR_AUTOLOAD}, {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY}, {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp.8 index 20803d5d3685..b3a50e181de8 100644 --- a/usr.sbin/ppp/ppp.8 +++ b/usr.sbin/ppp/ppp.8 @@ -1,4 +1,4 @@ -.\" $Id: ppp.8,v 1.97.2.36 1998/05/18 23:24:24 brian Exp $ +.\" $Id: ppp.8,v 1.97.2.37 1998/05/19 19:58:21 brian Exp $ .Dd 20 September 1995 .Os FreeBSD .Dt PPP 8 @@ -2472,6 +2472,36 @@ is logged as for security reasons. .It set authname Ar id This sets the authentication id used in client mode PAP or CHAP negotiation. +.It set autoload Ar maxduration maxload Op Ar minduration minload +These settings apply only in multilink mode and all default to zero. +When more than one +.Ar demand-dial +.Pq also known as Fl auto +mode link is available, only the first link is made active when +.Nm +first reads data from the tun device. The next +.Ar demand-dial +link will be opened only when at least +.Ar maxload +packets have been in the send queue for +.Ar maxduration +seconds. Because both values default to zero, +.Ar demand-dial +links will simply come up one at a time by default. +.Pp +If two or more links are open, at least one of which is a +.Ar demand-dial +link, a +.Ar demand-dial +link will be closed when there is less than +.Ar minpackets +in the queue for more than +.Ar minduration . +If +.Ar minduration +is zero, this timer is disabled. Because both values default to zero, +.Ar demand-dial +links will stay active until the bundle idle timer expires. .It set ctsrts|crtscts on|off This sets hardware flow control. Hardware flow control is .Ar on -- cgit v1.2.3