📄 mtrace.c
字号:
#define STATS_MISSING(x) ((x) == 0xFFFFFFFF) if (!STATS_MISSING(s->tr_vifout) && !STATS_MISSING(r->tr_vifout)) vhave |= OUTS; if (STATS_MISSING(s->tr_pktcnt) || STATS_MISSING(r->tr_pktcnt)) gmissing |= OUTS; if (!(*rst & BUG_NOPRINT)) ghave |= OUTS; if (have_next) { --r, --s, --rst; if (!STATS_MISSING(s->tr_vifin) && !STATS_MISSING(r->tr_vifin)) vhave |= INS; if (STATS_MISSING(s->tr_pktcnt) || STATS_MISSING(r->tr_pktcnt)) gmissing |= INS; if (!(*rst & BUG_NOPRINT)) ghave |= INS; } /* * Stats can be missing for any number of reasons: * - The hop may not be capable of collecting stats * - Traffic may be getting dropped at the previous hop * and so this hop may not have any state * * We need a stronger heuristic to tell between these * two cases; in case 1 we don't want to print the stats * and in case 2 we want to print 100% loss. We used to * err on the side of not printing, which is less useful * than printing 100% loss and dealing with it. */#if 0 /* * If both hops report as missing, then it's likely that there's just * no traffic flowing. * * If just one hop is missing, then we really don't have it. */ if (gmissing != BOTH) ghave &= ~gmissing;#endif whochar = have_next ? '^' : ' '; switch (vhave) { case BOTH: v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin)); if (v_out) v_pct = v_lost * 100 / v_out; else v_pct = 0; if (-20 < v_pct && v_pct < 101 && v_out > 10) sprintf(v_str, "%3d%%", v_pct); else if (v_pct < -900 && v_out > 10) sprintf(v_str, "%3dx", (int)(-v_pct / 100. + 1.)); else if (v_pct <= -20 && v_out > 10) sprintf(v_str, "%1.1fx", -v_pct / 100. + 1.); else memcpy(v_str, " -- ", 5); if (tunstats) printf("%6d/%-5d=%s", v_lost, v_out, v_str); else printf(" "); printf("%4d pps", v_pps); if (v_pps && badtime) printf("?"); break; case INS: v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin); v_pps = v_out / timediff; whochar = 'v'; /* Fall through */ case OUTS: if (tunstats) printf(" %c%-5d ", whochar, v_out); else printf(" %c", whochar); printf("%4d pps", v_pps); if (v_pps && badtime) printf("?"); break; case NEITHER: if (ghave != NEITHER) if (tunstats) printf(" "); else printf(" "); break; } whochar = have_next ? '^' : ' '; switch (ghave) { case BOTH: g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt)); if (g_out) g_pct = g_lost * 100 / g_out; else g_pct = 0; if (-20 < g_pct && g_pct < 101 && g_out > 10) sprintf(g_str, "%3d%%", g_pct); else if (g_pct < -900 && g_out > 10) sprintf(g_str, "%3dx", (int)(-g_pct / 100. + 1.)); else if (g_pct <= -20 && g_out > 10) sprintf(g_str, "%1.1fx", -g_pct / 100. + 1.); else memcpy(g_str, " -- ", 5); printf("%s%6d/%-5d=%s%4d pps", tunstats ? "" : " ", g_lost, g_out, g_str, g_pps); if (g_pps && badtime) printf("?"); printf("\n"); break;#if 0 case INS: g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt); g_pps = g_out / timediff; whochar = 'v'; /* Fall through */#endif case OUTS: printf("%s ?/%-5d %4d pps", tunstats ? "" : " ", g_out, g_pps); if (badtime) printf("?"); printf("\n"); break; case INS: case NEITHER: printf("\n"); break; } if (debug > 2) { printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin)); printf("v_out: %ld ", ntohl(s->tr_vifout)); printf("pkts: %ld\n", ntohl(s->tr_pktcnt)); printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin)); printf("v_out: %ld ", ntohl(r->tr_vifout)); printf("pkts: %ld\n", ntohl(r->tr_pktcnt)); printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin)); printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout)); printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt)); printf("time: %d\n", timediff); printf("\t\t\t\treset: %x hoptime: %lx\n", *rst, ntohl(s->tr_qarr)); }}/* * A fixup to check if any pktcnt has been reset, and to fix the * byteorder bugs in mrouted 3.6 on little-endian machines. * * XXX Since periodic traffic sources are likely to have their * pktcnt periodically reset, should we save old values when * the reset occurs to keep slightly better statistics over * the long term? (e.g. SAP) */voidfixup_stats(base, prev, new, bugs) struct resp_buf *base, *prev, *new; int *bugs;{ int rno = base->len; struct tr_resp *b = base->resps + rno; struct tr_resp *p = prev->resps + rno; struct tr_resp *n = new->resps + rno; int *r = bugs + rno; int res; int cleanup = 0; /* Check for byte-swappers. Only check on the first trace, * since long-running traces can wrap around and falsely trigger. */ while (--rno >= 0) {#ifdef TEST_ONLY u_int32 nvifout = ntohl(n->tr_vifout); u_int32 pvifout = ntohl(p->tr_vifout);#endif --n; --p; --b;#ifdef TEST_ONLY /*XXX this is still buggy, so disable it for release */ if ((*r & BUG_SWAP) || ((base == prev) && (nvifout - pvifout) > (byteswap(nvifout) - byteswap(pvifout)))) { if (1 || debug > 2) { printf("ip %s swaps; b %08x p %08x n %08x\n", inet_fmt(n->tr_inaddr, s1), ntohl(b->tr_vifout), pvifout, nvifout); } /* This host sends byteswapped reports; swap 'em */ if (!(*r & BUG_SWAP)) { *r |= BUG_SWAP; b->tr_qarr = byteswap(b->tr_qarr); b->tr_vifin = byteswap(b->tr_vifin); b->tr_vifout = byteswap(b->tr_vifout); b->tr_pktcnt = byteswap(b->tr_pktcnt); } n->tr_qarr = byteswap(n->tr_qarr); n->tr_vifin = byteswap(n->tr_vifin); n->tr_vifout = byteswap(n->tr_vifout); n->tr_pktcnt = byteswap(n->tr_pktcnt); }#endif /* * A missing parenthesis in mrouted 3.5-3.8's prune.c * causes extremely bogus time diff's. * One half of the time calculation was * inside an htonl() and one half wasn't. Therefore, on * a little-endian machine, both halves of the calculation * would get added together in the little end. Thus, the * low-order 2 bytes are either 0000 (no overflow) or * 0100 (overflow from the addition). * * Odds are against these particular bit patterns * happening in both prev and new for actual time values. */ if ((*r & BUG_BOGUSTIME) || (((ntohl(n->tr_qarr) & 0xfeff) == 0x0000) && ((ntohl(p->tr_qarr) & 0xfeff) == 0x0000))) { *r |= BUG_BOGUSTIME; n->tr_qarr = new->rtime; p->tr_qarr = prev->rtime; b->tr_qarr = base->rtime; } } rno = base->len; b = base->resps + rno; p = prev->resps + rno; n = new->resps + rno; r = bugs + rno; while (--rno >= 0) { --n; --p; --b; --r; /* * This hop has reset if: * - There were statistics in the base AND previous pass, AND * - There are less packets this time than the first time and * we didn't reset last time, OR * - There are less packets this time than last time, OR * - There are no statistics on this pass. * * The "and we didn't reset last time" is necessary in the * first branch of the OR because if the base is large and * we reset last time but the constant-resetter-avoidance * code kicked in so we delayed the copy of prev to base, * new could still be below base so we trigger the * constant-resetter code even though it was really only * a single reset. */ res = ((b->tr_pktcnt != 0xFFFFFFFF) && (p->tr_pktcnt != 0xFFFFFFFF) && ((!(*r & BUG_RESET) && ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) || (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)) || (n->tr_pktcnt == 0xFFFFFFFF))); if (debug > 2) { printf("\t\tip=%s, r=%d, res=%d\n", inet_fmt(b->tr_inaddr, s1), *r, res); if (res) printf("\t\tbase=%ld, prev=%ld, new=%ld\n", ntohl(b->tr_pktcnt), ntohl(p->tr_pktcnt), ntohl(n->tr_pktcnt)); } if (*r & BUG_RESET) { if (res || (*r & BUG_RESET2X)) { /* * This router appears to be a 3.4 with that nasty ol' * neighbor version bug, which causes it to constantly * reset. Just nuke the statistics for this node, and * don't even bother giving it the benefit of the * doubt from now on. */ p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt; *r |= BUG_RESET2X; } else { /* * This is simply the situation that the original * fixup_stats was meant to deal with -- that a * 3.3 or 3.4 router deleted a cache entry while * traffic was still active. */ *r &= ~BUG_RESET; cleanup = 1; } } else if (res) *r |= BUG_RESET; } if (cleanup == 0) return; /* * If some hop reset its counters and didn't continue to * reset, then we pretend that the previous * trace was the first one. */ rno = base->len; b = base->resps + rno; p = prev->resps + rno; while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt; base->qtime = prev->qtime; base->rtime = prev->rtime;}/* * Check per-source losses along path and compare with threshold. */intcheck_thresh(thresh, base, prev, new) int thresh; struct resp_buf *base, *prev, *new;{ int rno = base->len - 1; struct tr_resp *b = base->resps + rno; struct tr_resp *p = prev->resps + rno; struct tr_resp *n = new->resps + rno; int g_out, g_lost; while (TRUE) { if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_outaddr != b->tr_outaddr) || (n->tr_rmtaddr != b->tr_rmtaddr)) return 1; /* Route changed */ if (rno-- < 1) break; g_out = ntohl(n->tr_pktcnt) - ntohl(p->tr_pktcnt); b--; n--; p--; g_lost = g_out - (ntohl(n->tr_pktcnt) - ntohl(p->tr_pktcnt)); if (g_out && ((g_lost * 100 + (g_out >> 1))/ g_out) > thresh) { return TRUE; } } return FALSE;}/* * Print responses with statistics for forward path (from src to dst) */intprint_stats(base, prev, new, bugs, names) struct resp_buf *base, *prev, *new; int *bugs; char **names;{ int rtt, hop; char *ms; u_int32 smask; int rno = base->len - 1; struct tr_resp *b = base->resps + rno; struct tr_resp *p = prev->resps + rno; struct tr_resp *n = new->resps + rno; int *r = bugs + rno; u_long resptime = new->rtime; u_long qarrtime = ntohl(n->tr_qarr); u_int ttl = MaX(1, n->tr_fttl) + 1; int first = (base == prev); VAL_TO_MASK(smask, b->tr_smask); printf(" Source Response Dest "); if (tunstats) printf("Packet Statistics For Only For Traffic\n"); else printf("Overall Packet Statistics For Traffic From\n"); (void)inet_fmt(base->qhdr.tr_src, s1); printf("%-15s %-15s ", ((b->tr_inaddr & smask) == (base->qhdr.tr_src & smask)) ? s1 : " * * * ", inet_fmt(base->qhdr.tr_raddr, s2)); (void)inet_fmt(base->igmp.igmp_group.s_addr, s2); if (tunstats) printf("All Multicast Traffic From %s\n", s1); else printf("Packet %s To %s\n", s1, s2); rtt = t_diff(resptime, new->qtime); ms = scale(&rtt); printf(" %c __/ rtt%5d%s ", (first && !verbose) ? 'v' : '|', rtt, ms); if (tunstats) printf("Lost/Sent = Pct Rate To %s\n", s2); else printf(" Rate Lost/Sent = Pct Rate\n"); if (!first || verbose) { hop = t_diff(resptime, qarrtime); ms = scale(&hop); printf(" v / hop%5d%s ", hop, ms); if (tunstats) printf("--------------------- --------------------\n"); else printf("------- ---------------------\n"); } if ((b->tr_inaddr & smask) != (base->qhdr.tr_src & smask) && b->tr_rmtaddr != 0) { printf("%-15s %-14s is the previous hop\n", inet_fmt(b->tr_rmtaddr, s1), inet_name(b->tr_rmtaddr)); printf(" v ^\n"); } if (debug > 2) { printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin)); printf("v_out: %ld ", ntohl(n->tr_vifout)); printf("pkts: %ld\n", ntohl(n->tr_pktcnt)); printf("\t\t\t\tv_in: %ld ", ntohl(b->tr_vifin)); printf("v_out: %ld ", ntohl(b->tr_vifout)); printf("pkts: %ld\n", ntohl(b->tr_pktcnt)); printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin)); printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout)); printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt)); printf("\t\t\t\treset: %x hoptime: %lx\n", *r, ntohl(n->tr_qarr)); } while (TRUE) { if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_outaddr != b->tr_outaddr) || (n->tr_rmtaddr != b->tr_rmtaddr)) return 1; /* Route changed */ if ((n->tr_inaddr != n->tr_outaddr) && n->tr_inaddr) printf("%-15s\n", inet_fmt(n->tr_inaddr, s1)); printf("%-15s %-14s %s%s\n", inet_fmt(n->tr_outaddr, s1), names[rno], flag_type(n->tr_rflags), (*r & BUG_NOPRINT) ? " [reset counters]" : ""); if (rno-- < 1) break; printf(" %c ^ ttl%5d ", (first && !verbose) ? 'v' : '|', ttl); stat_line(p, n, TRUE, r); if (!first || verbose) { resptime = qarrtime; qarrtime = ntohl((n-1)->tr_qarr); hop = t_diff(resptime, qarrtime); ms = scale(&hop); printf(" v | hop%5d%s", hop, ms); if (first) printf("\n"); else stat_line(b, n, TRUE, r); } --b, --p, --n, --r; ttl = MaX(ttl, MaX(1, n->tr_fttl) + base->len - rno); } printf(" %c \\__ ttl%5d ", (first && !verbose) ? 'v' : '|', ttl); stat_line(p, n, FALSE, r); if (!first || verbose) { hop = t_diff(qarrtime, new->qtime); ms = scale(&hop); printf(" v \\ hop%5d%s", hop, ms); if (first) printf("\n"); else stat_line(b, n, FALSE, r); } printf("%-15s %s\n", inet_fmt(base->qhdr.tr_dst, s1), !passive ? inet_fmt(lcl_addr, s2) : " * * * "); printf(" Receiver Query Source\n\n"); return 0;}/* * Determine whether or not the path has changed. */intpath_changed(base, new) struct resp_buf *base, *new;{ int r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -