diff --git a/usr.sbin/ppp/acf.c b/usr.sbin/ppp/acf.c index 4db0b6b264d8..60e2de4b534a 100644 --- a/usr.sbin/ppp/acf.c +++ b/usr.sbin/ppp/acf.c @@ -85,14 +85,14 @@ acf_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) /* We expect the packet not to be compressed */ bp = mbuf_Read(bp, cp, 2); if (cp[0] != HDLC_ADDR) { - p->hdlc.lqm.SaveInErrors++; + p->hdlc.lqm.ifInErrors++; p->hdlc.stats.badaddr++; log_Printf(LogDEBUG, "acf_LayerPull: addr 0x%02x\n", cp[0]); m_freem(bp); return NULL; } if (cp[1] != HDLC_UI) { - p->hdlc.lqm.SaveInErrors++; + p->hdlc.lqm.ifInErrors++; p->hdlc.stats.badcommand++; log_Printf(LogDEBUG, "acf_LayerPull: control 0x%02x\n", cp[1]); m_freem(bp); diff --git a/usr.sbin/ppp/async.c b/usr.sbin/ppp/async.c index 0fcf865264fb..b938e6845b8c 100644 --- a/usr.sbin/ppp/async.c +++ b/usr.sbin/ppp/async.c @@ -106,6 +106,7 @@ async_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, struct physical *p = link2physical(l); u_char *cp, *sp, *ep; struct mbuf *wp; + size_t oldcnt; int cnt; if (!p || m_length(bp) > HDLCSIZE) { @@ -113,6 +114,8 @@ async_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, return NULL; } + oldcnt = m_length(bp); + cp = p->async.xbuff; ep = cp + HDLCSIZE - 10; wp = bp; @@ -134,6 +137,7 @@ async_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, m_freem(bp); bp = m_get(cnt, MB_ASYNCOUT); memcpy(MBUF_CTOP(bp), p->async.xbuff, cnt); + bp->priv = cnt - oldcnt; log_DumpBp(LogASYNC, "Write", bp); return bp; diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/hdlc.c index 27077dcef7cc..81b537da4f9b 100644 --- a/usr.sbin/ppp/hdlc.c +++ b/usr.sbin/ppp/hdlc.c @@ -318,22 +318,26 @@ hdlc_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, log_DumpBp(LogHDLC, "hdlc_LayerPull:", bp); - fcs = hdlc_Fcs(MBUF_CTOP(bp), bp->m_len); + bp = m_pullup(bp); + len = m_length(bp); + fcs = hdlc_Fcs(MBUF_CTOP(bp), len); log_Printf(LogDEBUG, "%s: hdlc_LayerPull: fcs = %04x (%s)\n", p->link.name, fcs, (fcs == GOODFCS) ? "good" : "BAD!"); + p->hdlc.lqm.ifInOctets += len + 1; /* plus 1 flag octet! */ + if (fcs != GOODFCS) { - p->hdlc.lqm.SaveInErrors++; + p->hdlc.lqm.ifInErrors++; p->hdlc.stats.badfcs++; m_freem(bp); return NULL; } - p->hdlc.lqm.SaveInOctets += bp->m_len + 1; - p->hdlc.lqm.SaveInPackets++; + /* Either done here or by the sync layer */ + p->hdlc.lqm.lqr.InGoodOctets += len + 1; /* plus 1 flag octet! */ + p->hdlc.lqm.ifInUniPackets++; - len = m_length(bp); if (len < 4) { /* rfc1662 section 4.3 */ m_freem(bp); bp = NULL; diff --git a/usr.sbin/ppp/hdlc.h b/usr.sbin/ppp/hdlc.h index 71f08143b1f5..839d83cf0152 100644 --- a/usr.sbin/ppp/hdlc.h +++ b/usr.sbin/ppp/hdlc.h @@ -73,16 +73,21 @@ struct hdlc { struct pppTimer timer; /* When to send */ int method; /* bit-mask for LQM_* from lqr.h */ - u_int32_t OutPackets; /* Packets sent by me */ - u_int32_t OutOctets; /* Octets sent by me */ - u_int32_t SaveInPackets; /* Packets received from peer */ - u_int32_t SaveInDiscards; /* Discards */ - u_int32_t SaveInErrors; /* Errors */ - u_int32_t SaveInOctets; /* Octets received from peer */ + u_int32_t ifOutUniPackets; /* Packets sent by me */ + u_int32_t ifOutOctets; /* Octets sent by me */ + u_int32_t ifInUniPackets; /* Packets received from peer */ + u_int32_t ifInDiscards; /* Discards */ + u_int32_t ifInErrors; /* Errors */ + u_int32_t ifInOctets; /* Octets received from peer (unused) */ struct { + u_int32_t InGoodOctets; /* Good octets received from peer */ u_int32_t OutLQRs; /* LQRs sent by me */ - u_int32_t SaveInLQRs; /* LQRs received from peer */ + u_int32_t InLQRs; /* LQRs received from peer */ + + struct lqrsavedata Save; /* Our last LQR */ + struct lqrsavedata prevSave; /* Our last-but-one LQR (analysis) */ + struct lqrdata peer; /* Last LQR from peer */ int peer_timeout; /* peers max lqr timeout */ int resent; /* Resent last packet `resent' times */ diff --git a/usr.sbin/ppp/link.c b/usr.sbin/ppp/link.c index d5aaca3dd3ef..1667e8a8b661 100644 --- a/usr.sbin/ppp/link.c +++ b/usr.sbin/ppp/link.c @@ -147,6 +147,34 @@ link_QueueBytes(struct link *l) return bytes; } +void +link_PendingLowPriorityData(struct link *l, size_t *pkts, size_t *octets) +{ + struct mqueue *queue, *highest; + struct mbuf *m; + size_t len; + + /* + * This is all rfc1989 stuff... because our LQR packet is going to bypass + * everything that's not in the highest priority queue, we must be able to + * subtract that data from our outgoing packet/octet counts. However, + * we've already async-encoded our data at this point, but the async + * encodings MUSTn't be a part of the LQR-reported payload :( So, we have + * the async layer record how much it's padded the packet in the mbuf's + * priv field, and when we calculate our outgoing LQR values we subtract + * this value for each packet from the octet count sent. + */ + + highest = LINK_HIGHQ(l); + *pkts = *octets = 0; + for (queue = l->Queue; queue < highest; queue++) { + len = queue->len; + *pkts += len; + for (m = queue->top; len--; m = m->m_nextpkt) + *octets += m_length(m) - m->priv; + } +} + struct mbuf * link_Dequeue(struct link *l) { @@ -232,6 +260,7 @@ link_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri, if(pri < 0 || pri >= LINK_QUEUES(l)) pri = 0; + bp->priv = 0; /* Adjusted by the async layer ! */ for (layer = l->nlayers; layer && bp; layer--) if (l->layer[layer - 1]->push != NULL) bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto); @@ -360,7 +389,7 @@ Despatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto) bp = m_pullup(proto_Prepend(bp, proto, 0, 0)); lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->m_len); if (p) { - p->hdlc.lqm.SaveInDiscards++; + p->hdlc.lqm.ifInDiscards++; p->hdlc.stats.unknownproto++; } m_freem(bp); diff --git a/usr.sbin/ppp/link.h b/usr.sbin/ppp/link.h index 89b6230268b1..822474b78992 100644 --- a/usr.sbin/ppp/link.h +++ b/usr.sbin/ppp/link.h @@ -65,6 +65,7 @@ extern void link_SequenceQueue(struct link *); extern void link_DeleteQueue(struct link *); extern size_t link_QueueLen(struct link *); extern size_t link_QueueBytes(struct link *); +extern void link_PendingLowPriorityData(struct link *, size_t *, size_t *); extern struct mbuf *link_Dequeue(struct link *); extern void link_PushPacket(struct link *, struct mbuf *, struct bundle *, diff --git a/usr.sbin/ppp/lqr.c b/usr.sbin/ppp/lqr.c index f72c899c44d5..073379a0eb85 100644 --- a/usr.sbin/ppp/lqr.c +++ b/usr.sbin/ppp/lqr.c @@ -146,6 +146,14 @@ SendLqrData(struct lcp *lcp) bp = m_get(sizeof(struct lqrdata) + extra, MB_LQROUT); bp->m_len -= extra; bp->m_offset += extra; + + /* + * Send on the highest priority queue. We send garbage - the real data + * is written by lqr_LayerPush() where we know how to fill in all the + * fields. Note, lqr_LayerPush() ``knows'' that we're pushing onto the + * highest priority queue, and factors out packet & octet values from + * other queues! + */ link_PushPacket(lcp->fsm.link, bp, lcp->fsm.bundle, LINK_QUEUES(lcp->fsm.link) - 1, PROTO_LQR); } @@ -202,8 +210,6 @@ lqr_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) return NULL; } - p->hdlc.lqm.lqr.SaveInLQRs++; - len = m_length(bp); if (len != sizeof(struct lqrdata)) log_Printf(LogWARN, "lqr_Input: Got packet size %d, expecting %ld !\n", @@ -213,7 +219,6 @@ lqr_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) lcp_SendProtoRej(lcp, MBUF_CTOP(bp), bp->m_len); } else { struct lqrdata *lqr; - u_int32_t lastLQR; bp = m_pullup(bp); lqr = (struct lqrdata *)MBUF_CTOP(bp); @@ -222,27 +227,32 @@ lqr_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) " expecting 0x%08lx\n", (u_long)ntohl(lqr->MagicNumber), (u_long)lcp->his_magic); else { - /* - * Remember our PeerInLQRs, then convert byte order and save - */ - lastLQR = p->hdlc.lqm.lqr.peer.PeerInLQRs; + struct lqrdata lastlqr; + memcpy(&lastlqr, &p->hdlc.lqm.lqr.peer, sizeof lastlqr); lqr_ChangeOrder(lqr, &p->hdlc.lqm.lqr.peer); lqr_Dump(l->name, "Input", &p->hdlc.lqm.lqr.peer); - /* we have received an LQR from peer */ + /* we have received an LQR from our peer */ p->hdlc.lqm.lqr.resent = 0; + /* Snapshot our state when the LQR packet was received */ + memcpy(&p->hdlc.lqm.lqr.prevSave, &p->hdlc.lqm.lqr.Save, + sizeof p->hdlc.lqm.lqr.prevSave); + p->hdlc.lqm.lqr.Save.InLQRs = ++p->hdlc.lqm.lqr.InLQRs; + p->hdlc.lqm.lqr.Save.InPackets = p->hdlc.lqm.ifInUniPackets; + p->hdlc.lqm.lqr.Save.InDiscards = p->hdlc.lqm.ifInDiscards; + p->hdlc.lqm.lqr.Save.InErrors = p->hdlc.lqm.ifInErrors; + p->hdlc.lqm.lqr.Save.InOctets = p->hdlc.lqm.lqr.InGoodOctets; + + lqr_Analyse(&p->hdlc, &lastlqr, &p->hdlc.lqm.lqr.peer); + /* * Generate an LQR response if we're not running an LQR timer OR - * two successive LQR's PeerInLQRs are the same OR we're not going to - * send our next one before the peers max timeout. + * two successive LQR's PeerInLQRs are the same. */ - if (p->hdlc.lqm.timer.load == 0 || - !(p->hdlc.lqm.method & LQM_LQR) || - (lastLQR && lastLQR == p->hdlc.lqm.lqr.peer.PeerInLQRs) || - (p->hdlc.lqm.lqr.peer_timeout && - p->hdlc.lqm.timer.rest * 100 / SECTICKS > - p->hdlc.lqm.lqr.peer_timeout)) + if (p->hdlc.lqm.timer.load == 0 || !(p->hdlc.lqm.method & LQM_LQR) || + (lastlqr.PeerInLQRs && + lastlqr.PeerInLQRs == p->hdlc.lqm.lqr.peer.PeerInLQRs)) SendLqrData(lcp); } } @@ -355,12 +365,57 @@ lqr_Dump(const char *link, const char *message, const struct lqrdata *lqr) } } +void +lqr_Analyse(const struct hdlc *hdlc, const struct lqrdata *oldlqr, + const struct lqrdata *newlqr) +{ + u_int32_t LQRs, transitLQRs, pkts, octets, disc, err; + + if (!newlqr->PeerInLQRs) /* No analysis possible yet! */ + return; + + log_Printf(LogLQM, "Analysis:\n"); + + LQRs = (newlqr->LastOutLQRs - oldlqr->LastOutLQRs) - + (newlqr->PeerInLQRs - oldlqr->PeerInLQRs); + transitLQRs = hdlc->lqm.lqr.OutLQRs - newlqr->LastOutLQRs; + pkts = (newlqr->LastOutPackets - oldlqr->LastOutPackets) - + (newlqr->PeerInPackets - oldlqr->PeerInPackets); + octets = (newlqr->LastOutOctets - oldlqr->LastOutOctets) - + (newlqr->PeerInOctets - oldlqr->PeerInOctets); + log_Printf(LogLQM, " Outbound lossage: %d LQR%s (%d en route), %d packet%s," + " %d octet%s\n", (int)LQRs, LQRs == 1 ? "" : "s", (int)transitLQRs, + (int)pkts, pkts == 1 ? "" : "s", + (int)octets, octets == 1 ? "" : "s"); + + pkts = (newlqr->PeerOutPackets - oldlqr->PeerOutPackets) - + (hdlc->lqm.lqr.Save.InPackets - hdlc->lqm.lqr.prevSave.InPackets); + octets = (newlqr->PeerOutOctets - oldlqr->PeerOutOctets) - + (hdlc->lqm.lqr.Save.InOctets - hdlc->lqm.lqr.prevSave.InOctets); + log_Printf(LogLQM, " Inbound lossage: %d packet%s, %d octet%s\n", + (int)pkts, pkts == 1 ? "" : "s", + (int)octets, octets == 1 ? "" : "s"); + + disc = newlqr->PeerInDiscards - oldlqr->PeerInDiscards; + err = newlqr->PeerInErrors - oldlqr->PeerInErrors; + if (disc && err) + log_Printf(LogLQM, " Likely due to both peer congestion" + " and physical errors\n"); + else if (disc) + log_Printf(LogLQM, " Likely due to peer congestion\n"); + else if (err) + log_Printf(LogLQM, " Likely due to physical errors\n"); + else if (pkts) + log_Printf(LogLQM, " Likely due to transport " + "congestion\n"); +} + static struct mbuf * lqr_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, int pri, u_short *proto) { struct physical *p = link2physical(l); - int len; + int len, layer, extra_async_bytes; if (!p) { /* Oops - can't happen :-] */ @@ -368,7 +423,10 @@ lqr_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, return NULL; } - /* + bp = m_pullup(bp); + len = m_length(bp); + + /*- * From rfc1989: * * All octets which are included in the FCS calculation MUST be counted, @@ -377,50 +435,72 @@ lqr_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, * MUST be counted. All other octets (such as additional flag * sequences, and escape bits or octets) MUST NOT be counted. * - * As we're stacked before the HDLC layer (otherwise HDLC wouldn't be + * As we're stacked higher than the HDLC layer (otherwise HDLC wouldn't be * able to calculate the FCS), we must not forget about these additional * bytes when we're asynchronous. * - * We're also expecting to be stacked *before* the proto and acf layers. - * If we were after these, it makes alignment more of a pain, and we - * don't do LQR without these layers. + * We're also expecting to be stacked *before* the likes of the proto and + * acf layers (to avoid alignment issues), so deal with this too. */ - bp = m_pullup(bp); - len = m_length(bp); - - if (!physical_IsSync(p)) - p->hdlc.lqm.OutOctets += hdlc_WrapperOctets(&l->lcp, *proto); - p->hdlc.lqm.OutOctets += acf_WrapperOctets(&l->lcp, *proto) + - proto_WrapperOctets(&l->lcp, *proto) + len + 1; - p->hdlc.lqm.OutPackets++; + extra_async_bytes = 0; + p->hdlc.lqm.ifOutUniPackets++; + p->hdlc.lqm.ifOutOctets += len + 1; /* plus 1 flag octet! */ + for (layer = 0; layer < l->nlayers; layer++) + switch (l->layer[layer]->type) { + case LAYER_ACF: + p->hdlc.lqm.ifOutOctets += acf_WrapperOctets(&l->lcp, *proto); + break; + case LAYER_ASYNC: + /* Not included - see rfc1989 */ + break; + case LAYER_HDLC: + p->hdlc.lqm.ifOutOctets += hdlc_WrapperOctets(&l->lcp, *proto); + break; + case LAYER_LQR: + layer = l->nlayers; + break; + case LAYER_PROTO: + p->hdlc.lqm.ifOutOctets += proto_WrapperOctets(&l->lcp, *proto); + break; + case LAYER_SYNC: + /* Nothing to add on */ + break; + default: + log_Printf(LogWARN, "Oops, don't know how to do octets for %s layer\n", + l->layer[layer]->name); + break; + } if (*proto == PROTO_LQR) { /* Overwrite the entire packet (created in SendLqrData()) */ struct lqrdata lqr; + size_t pending_pkts, pending_octets; + p->hdlc.lqm.lqr.OutLQRs++; + + /* + * We need to compensate for the fact that we're pushing our data + * onto the highest priority queue by factoring out packet & octet + * values from other queues! + */ + link_PendingLowPriorityData(l, &pending_pkts, &pending_octets); + + memset(&lqr, '\0', sizeof lqr); lqr.MagicNumber = p->link.lcp.want_magic; lqr.LastOutLQRs = p->hdlc.lqm.lqr.peer.PeerOutLQRs; lqr.LastOutPackets = p->hdlc.lqm.lqr.peer.PeerOutPackets; lqr.LastOutOctets = p->hdlc.lqm.lqr.peer.PeerOutOctets; - lqr.PeerInLQRs = p->hdlc.lqm.lqr.SaveInLQRs; - lqr.PeerInPackets = p->hdlc.lqm.SaveInPackets; - lqr.PeerInDiscards = p->hdlc.lqm.SaveInDiscards; - lqr.PeerInErrors = p->hdlc.lqm.SaveInErrors; - lqr.PeerInOctets = p->hdlc.lqm.SaveInOctets; - lqr.PeerOutPackets = p->hdlc.lqm.OutPackets; - lqr.PeerOutOctets = p->hdlc.lqm.OutOctets; - if (p->hdlc.lqm.lqr.peer.LastOutLQRs == p->hdlc.lqm.lqr.OutLQRs) { - /* - * only increment if it's the first time or we've got a reply - * from the last one - */ - lqr.PeerOutLQRs = ++p->hdlc.lqm.lqr.OutLQRs; - lqr_Dump(l->name, "Output", &lqr); - } else { - lqr.PeerOutLQRs = p->hdlc.lqm.lqr.OutLQRs; - lqr_Dump(l->name, "Output (again)", &lqr); - } + lqr.PeerInLQRs = p->hdlc.lqm.lqr.Save.InLQRs; + lqr.PeerInPackets = p->hdlc.lqm.lqr.Save.InPackets; + lqr.PeerInDiscards = p->hdlc.lqm.lqr.Save.InDiscards; + lqr.PeerInErrors = p->hdlc.lqm.lqr.Save.InErrors; + lqr.PeerInOctets = p->hdlc.lqm.lqr.Save.InOctets; + lqr.PeerOutLQRs = p->hdlc.lqm.lqr.OutLQRs; + lqr.PeerOutPackets = p->hdlc.lqm.ifOutUniPackets - pending_pkts; + /* Don't forget our ``flag'' octets.... */ + lqr.PeerOutOctets = p->hdlc.lqm.ifOutOctets - pending_octets - pending_pkts; + lqr_Dump(l->name, "Output", &lqr); lqr_ChangeOrder(&lqr, (struct lqrdata *)MBUF_CTOP(bp)); } @@ -431,9 +511,11 @@ static struct mbuf * lqr_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) { /* - * We mark the packet as ours but don't do anything 'till it's dispatched - * to lqr_Input() + * This is the ``Rx'' process from rfc1989, although a part of it is + * actually performed by sync_LayerPull() & hdlc_LayerPull() so that + * our octet counts are correct. */ + if (*proto == PROTO_LQR) m_settype(bp, MB_LQRIN); return bp; diff --git a/usr.sbin/ppp/lqr.h b/usr.sbin/ppp/lqr.h index 16bab3938ce9..13d378ffbe77 100644 --- a/usr.sbin/ppp/lqr.h +++ b/usr.sbin/ppp/lqr.h @@ -46,6 +46,14 @@ struct lqrdata { u_int32_t PeerOutOctets; /* Peers OutOctets (hdlc.h) */ }; +struct lqrsavedata { /* Saved on receipt of an LQR */ + u_int32_t InLQRs; /* From ifInLQRs */ + u_int32_t InPackets; /* From ifInPackets */ + u_int32_t InDiscards; /* From ifInDiscards */ + u_int32_t InErrors; /* From ifInErrors */ + u_int32_t InOctets; /* From InGoodOctets ! */ +}; + /* * We support LQR and ECHO as LQM method */ @@ -56,10 +64,13 @@ struct mbuf; struct physical; struct lcp; struct fsm; +struct hdlc; struct link; struct bundle; extern void lqr_Dump(const char *, const char *, const struct lqrdata *); +extern void lqr_Analyse(const struct hdlc *, const struct lqrdata *, + const struct lqrdata *); extern void lqr_ChangeOrder(struct lqrdata *, struct lqrdata *); extern void lqr_Start(struct lcp *); extern void lqr_reStart(struct lcp *); diff --git a/usr.sbin/ppp/mbuf.h b/usr.sbin/ppp/mbuf.h index 82a7428b7fa0..34fe6c322489 100644 --- a/usr.sbin/ppp/mbuf.h +++ b/usr.sbin/ppp/mbuf.h @@ -35,6 +35,7 @@ struct mbuf { short m_type; /* MB_* below */ struct mbuf *m_next; /* link to next mbuf */ struct mbuf *m_nextpkt; /* link to next packet */ + unsigned long priv; /* private data - holds HDLC escape count */ /* buffer space is malloc()d directly after the header */ }; diff --git a/usr.sbin/ppp/sync.c b/usr.sbin/ppp/sync.c index 9fd782aa33e0..ebace8aa4993 100644 --- a/usr.sbin/ppp/sync.c +++ b/usr.sbin/ppp/sync.c @@ -54,6 +54,7 @@ sync_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, { log_DumpBp(LogSYNC, "Write", bp); m_settype(bp, MB_SYNCOUT); + bp->priv = 0; return bp; } @@ -62,6 +63,7 @@ sync_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) { struct physical *p = link2physical(l); + int len; if (!p) log_Printf(LogERROR, "Can't Pull a sync packet from a logical link\n"); @@ -69,8 +71,10 @@ sync_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, log_DumpBp(LogSYNC, "Read", bp); /* Either done here or by the HDLC layer */ - p->hdlc.lqm.SaveInOctets += m_length(bp) + 1; - p->hdlc.lqm.SaveInPackets++; + len = m_length(bp); + p->hdlc.lqm.ifInOctets += len + 1; /* plus 1 flag octet! */ + p->hdlc.lqm.lqr.InGoodOctets += len + 1; /* plus 1 flag octet! */ + p->hdlc.lqm.ifInUniPackets++; m_settype(bp, MB_SYNCIN); }