From 04a2eef368fb22fd8da4a27ae5e88348b112a204 Mon Sep 17 00:00:00 2001 From: Mladen Sablic Date: Mon, 12 Mar 2018 21:49:13 +0100 Subject: [PATCH] pimd: improvments to mtrace mtracebis has been updated, so it behaves more like the original mtrace command. Signed-off-by: Mladen Sablic --- pimd/mtracebis.c | 207 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 190 insertions(+), 17 deletions(-) diff --git a/pimd/mtracebis.c b/pimd/mtracebis.c index 337d420d34..5c8229175a 100644 --- a/pimd/mtracebis.c +++ b/pimd/mtracebis.c @@ -37,6 +37,7 @@ #include #include #include +#include #define MTRACEBIS_VERSION "0.1" #define MTRACE_TIMEOUT (5) @@ -56,6 +57,160 @@ static void version(void) fprintf(stderr, "%s %s\n", progname, MTRACEBIS_VERSION); } +static void print_host(struct in_addr addr) +{ + struct hostent *h; + + h = gethostbyaddr(&addr, sizeof(addr), AF_INET); + if (h == NULL) + printf("?"); + else + printf("%s", h->h_name); + printf(" (%s) ", inet_ntoa(addr)); +} + +static void print_line_no(int i) +{ + printf("%3d ", -i); +} + +static const char *rtg_proto_str(enum mtrace_rtg_proto proto) +{ + static char buf[80]; + + buf[0] = '\0'; + + switch (proto) { + case MTRACE_RTG_PROTO_DVMRP: + return "DVMRP"; + case MTRACE_RTG_PROTO_MOSPF: + return "MOSPF"; + case MTRACE_RTG_PROTO_PIM: + return "PIM"; + case MTRACE_RTG_PROTO_CBT: + return "CBT"; + case MTRACE_RTG_PROTO_PIM_SPECIAL: + return "PIM special"; + case MTRACE_RTG_PROTO_PIM_STATIC: + return "PIM static"; + case MTRACE_RTG_PROTO_DVMRP_STATIC: + return "DVMRP static"; + case MTRACE_RTG_PROTO_PIM_MBGP: + return "PIM MBGP"; + case MTRACE_RTG_PROTO_CBT_SPECIAL: + return "CBT special"; + case MTRACE_RTG_PROTO_CBT_STATIC: + return "CBT static"; + case MTRACE_RTG_PROTO_PIM_ASSERT: + return "PIM assert"; + default: + sprintf(buf, "unknown protocol (%d)", proto); + return buf; + } +} + +static void print_rtg_proto(uint32_t rtg_proto) +{ + printf("%s", rtg_proto_str(rtg_proto)); +} + +static void print_fwd_ttl(uint32_t fwd_ttl) +{ + printf("thresh^ %d", fwd_ttl); +} + +static const char *fwd_code_str(enum mtrace_fwd_code code) +{ + static char buf[80]; + + buf[0] = '\0'; + + switch (code) { + case MTRACE_FWD_CODE_NO_ERROR: + return "no error"; + case MTRACE_FWD_CODE_WRONG_IF: + return "wrong interface"; + case MTRACE_FWD_CODE_PRUNE_SENT: + return "prune sent"; + case MTRACE_FWD_CODE_PRUNE_RCVD: + return "prune received"; + case MTRACE_FWD_CODE_SCOPED: + return "scoped"; + case MTRACE_FWD_CODE_NO_ROUTE: + return "no route"; + case MTRACE_FWD_CODE_WRONG_LAST_HOP: + return "wrong last hop"; + case MTRACE_FWD_CODE_NOT_FORWARDING: + return "not forwarding"; + case MTRACE_FWD_CODE_REACHED_RP: + return "reached RP"; + case MTRACE_FWD_CODE_RPF_IF: + return "RPF interface"; + case MTRACE_FWD_CODE_NO_MULTICAST: + return "no multicast"; + case MTRACE_FWD_CODE_INFO_HIDDEN: + return "info hidden"; + case MTRACE_FWD_CODE_NO_SPACE: + return "no space"; + case MTRACE_FWD_CODE_OLD_ROUTER: + return "old router"; + case MTRACE_FWD_CODE_ADMIN_PROHIB: + return "admin. prohib."; + default: + sprintf(buf, "unknown fwd. code (%d)", code); + return buf; + } +} + +static void print_fwd_code(uint32_t fwd_code) +{ + printf("%s", fwd_code_str(fwd_code)); +} + +static void print_rsp(struct igmp_mtrace_rsp *rsp) +{ + print_host(rsp->outgoing); + if (rsp->fwd_code == 0) { + print_rtg_proto(rsp->rtg_proto); + printf(" "); + print_fwd_ttl(rsp->fwd_ttl); + } else { + print_fwd_code(rsp->fwd_code); + } + printf("\n"); +} + +static void print_dest(struct igmp_mtrace *mtrace) +{ + print_line_no(0); + print_host(mtrace->dst_addr); + printf("\n"); +} + +static void print_summary(struct igmp_mtrace *mtrace, int hops, long msec) +{ + int i; + int t = 0; + + for (i = 0; i < hops; i++) + t += mtrace->rsp[i].fwd_ttl; + + printf("Round trip time %ld ms; total ttl of %d required.\n", msec, t); +} + +static void print_responses(struct igmp_mtrace *mtrace, int hops, long msec) +{ + int i; + + print_dest(mtrace); + + for (i = 0; i < hops; i++) { + print_line_no(i + 1); + print_rsp(&mtrace->rsp[i]); + } + print_summary(mtrace, hops, msec); +} + static int send_query(int fd, struct in_addr to_addr, struct igmp_mtrace *mtrace) { @@ -88,7 +243,7 @@ static void print_query(struct igmp_mtrace *mtrace) inet_ntop(AF_INET, &mtrace->grp_addr, grp_str, sizeof(grp_str))); } -static int recv_response(int fd, long msec, int *hops) +static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer) { int recvd; char mtrace_buf[IP_AND_MTRACE_BUF_LEN]; @@ -96,7 +251,6 @@ static int recv_response(int fd, long msec, int *hops) struct igmp_mtrace *mtrace; int mtrace_len; int responses; - int i; u_short sum; recvd = recvfrom(fd, mtrace_buf, IP_AND_MTRACE_BUF_LEN, 0, NULL, 0); @@ -145,22 +299,22 @@ static int recv_response(int fd, long msec, int *hops) responses = mtrace_len - sizeof(struct igmp_mtrace); responses /= sizeof(struct igmp_mtrace_rsp); - printf("%ld ms received responses from %d hops.\n", msec, responses); + if (responses > MTRACE_MAX_HOPS) { + fprintf(stderr, "mtrace too large\n"); + return -1; + } if (hops) *hops = responses; - for (i = 0; i < responses; i++) { - struct igmp_mtrace_rsp *rsp = &mtrace->rsp[i]; - - if (rsp->fwd_code != 0) - printf("-%d fwd. code 0x%2x.\n", i, rsp->fwd_code); - } + if (mtracer) + memcpy(mtracer, mtrace, mtrace_len); return 0; } -static int wait_for_response(int fd, int *hops) +static int wait_for_response(int fd, int *hops, struct igmp_mtrace *mtrace, + long *ret_msec) { fd_set readfds; struct timeval timeout; @@ -181,11 +335,19 @@ static int wait_for_response(int fd, int *hops) return ret; rmsec = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; msec = tmsec - rmsec; - } while (recv_response(fd, msec, hops) != 0); + } while (recv_response(fd, hops, mtrace) != 0); + + if (ret_msec) + *ret_msec = msec; return ret; } +static bool check_end(struct igmp_mtrace *mtrace, int hops) +{ + return mtrace->src_addr.s_addr == mtrace->rsp[hops - 1].prev_hop.s_addr; +} + int main(int argc, char *const argv[]) { struct in_addr mc_source; @@ -193,6 +355,7 @@ int main(int argc, char *const argv[]) struct in_addr gw_addr; struct in_addr mtrace_addr; struct igmp_mtrace mtrace; + struct igmp_mtrace *mtracep; int hops = 255; int rhops; int maxhops = 255; @@ -203,9 +366,10 @@ int main(int argc, char *const argv[]) int fd = -1; int ret = -1; int c; + long msec; int i, j; char ifname[IF_NAMESIZE]; - char ip_str[INET_ADDRSTRLEN]; + char mbuf[MTRACE_BUF_LEN]; mtrace_addr.s_addr = inet_addr("224.0.1.32"); @@ -312,8 +476,10 @@ int main(int argc, char *const argv[]) goto close_fd; } printf("Querying full reverse path...\n"); - ret = wait_for_response(fd, NULL); + mtracep = (struct igmp_mtrace *)mbuf; + ret = wait_for_response(fd, &rhops, mtracep, &msec); if (ret > 0) { + print_responses(mtracep, rhops, msec); ret = 0; goto close_fd; } @@ -325,10 +491,9 @@ int main(int argc, char *const argv[]) } printf(" * "); printf("switching to hop-by-hop:\n"); - printf("%3d ? (%s)\n", 0, - inet_ntop(AF_INET, &mtrace.dst_addr, ip_str, sizeof(ip_str))); + print_dest(&mtrace); for (i = 1; i < maxhops; i++) { - printf("%3d ", -i); + print_line_no(i); mtrace.hops = i; for (j = 0; j < perhop; j++) { mtrace.qry_id++; @@ -340,12 +505,20 @@ int main(int argc, char *const argv[]) ret = EXIT_FAILURE; goto close_fd; } - ret = wait_for_response(fd, &rhops); + ret = wait_for_response(fd, &rhops, mtracep, &msec); if (ret > 0) { + if (check_end(mtracep, rhops)) { + print_rsp(&mtracep->rsp[rhops - 1]); + print_summary(mtracep, rhops, msec); + ret = 0; + goto close_fd; + } if (i > rhops) { + printf(" * ...giving up.\n"); ret = 0; goto close_fd; } + print_rsp(&mtracep->rsp[rhops - 1]); break; } printf(" *"); -- 2.39.5