]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pimd: improvments to mtrace
authorMladen Sablic <mladen.sablic@gmail.com>
Mon, 12 Mar 2018 20:49:13 +0000 (21:49 +0100)
committerMladen Sablic <mladen.sablic@gmail.com>
Wed, 14 Mar 2018 10:51:35 +0000 (11:51 +0100)
mtracebis has been updated, so it behaves more like the original
mtrace command.

Signed-off-by: Mladen Sablic <mladen.sablic@gmail.com>
pimd/mtracebis.c

index 337d420d345cac0e6de8aa9dc759580256304e62..5c8229175a65a7e87094a01338c72224017dd70a 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/if.h>
 #include <unistd.h>
 #include <getopt.h>
+#include <netdb.h>
 
 #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(" *");