IP ネットワークにおいては導通テストのためには ping をつかうことがおおい. しかし,IP がつかえない環境,あるいはネットワーク・インタフェースを直接あつかいたいときには,ping はつかえないか,または便利でない. こういうときにつかうためのかんたんなツールを掲載する. もちろん Ethernet でもつかえるが,Ethernet がつかえないときでも Linux の promiscuous mode がつかえれば,このツールをつかうことができる.
プログラムはこのページの最後にのせる.
使用法
テストしたいネットワーク (スライス) 上の各ノードでつぎのプログラムを動作させる.
./test <VNode#> <#Links>
たとえば,ネットワーク上の全ノードでいっせいに動作させる. <VNode#> はノードの番号 (端末もふくめて一意の番号をつける),<#Links> はそのノードからでるリンク数 N (eth1 ~ ethN がつかわれることを仮定).
たとえば,それぞれ 3 個の (仮想) リンクをもつ (仮想) ノード 1, 2, 3 の接続をみるには,各 ノードでつぎのようにプログラムを動作させればよい.
./test 1 3
./test 2 3
./test 3 3
出力例
"./test 3 3" を (VNode 3 で) 実行したときの出力例をしめす,つぎのようなメッセージがくりか えし表示される. (各ノードから 1 秒ごとに各リンクにパケットが出力される.)
Received from VNode 1 through eth1 (56 bytes) Received from VNode 2 through eth3 (56 bytes)
このメッセージの意味は,VNode 3 へは VNode 1 からのパケットが eth1 経由で入力され,VNode 2 からのパケットが eth3 経由で入力されたということである.
プログラム
/*** * * Non-IP Network Connection Tester * * Coded by Yasusi Kanada * Ver 0.2 2011-6-14 Initial version (for Linux promiscuous mode) * Ver 0.8 2012-5-23 Argument count updated * ***/ #include <linux/if_packet.h> #include <linux/if_ether.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/time.h> #include <stdio.h> #include <elf.h> #include <string.h> #include <fcntl.h> #define bool int32_t #define true 1 #define false 0 #define DEBUG 0 #define MAX_PACKET_SIZE 2048 // Sufficiently larger than the MTU #define FirstInterface 1 #define LastInterface 16 int32_t fd[LastInterface]; int32_t ifindex[LastInterface]; int32_t firstInterface; int32_t lastInterface; extern void _exit(int32_t); /** * Open a socket for the network interface */ int32_t open_socket(int32_t index, int32_t *rifindex) { unsigned char buf[MAX_PACKET_SIZE]; int32_t i; int32_t ifindex; struct ifreq ifr; struct sockaddr_ll sll; unsigned char interface[IFNAMSIZ]; strncpy(interface, "ethX", IFNAMSIZ); interface[3] = '0' + index; int32_t fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (fd == -1) { printf("%s - ", interface); perror("socket"); _exit(1); }; // get interface index memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, interface, IFNAMSIZ); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { printf("%s - ", interface); perror("SIOCGIFINDEX"); _exit(1); }; ifindex = ifr.ifr_ifindex; *rifindex = ifindex; // set promiscuous mode memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, interface, IFNAMSIZ); ioctl(fd, SIOCGIFFLAGS, &ifr); ifr.ifr_flags |= IFF_PROMISC; ioctl(fd, SIOCSIFFLAGS, &ifr); memset(&sll, 0xff, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_protocol = htons(ETH_P_ALL); sll.sll_ifindex = ifindex; if (bind(fd, (struct sockaddr *)&sll, sizeof(sll)) == -1) { printf("%s - ", interface); perror("bind"); _exit(1); }; /* flush all received packets. * * raw-socket receives packets from all interfaces * when the socket is not bound to an interface */ do { fd_set fds; struct timeval t; FD_ZERO(&fds); FD_SET(fd, &fds); memset(&t, 0, sizeof(t)); i = select(FD_SETSIZE, &fds, NULL, NULL, &t); if (i > 0) { recv(fd, buf, i, 0); }; printf("interface %d flushed\n", ifindex); } while (i); printf("%s opened (fd=%d interface=%d)\n", interface, fd, ifindex); return fd; } /** * Send a packet */ int32_t sendPacket(int vnodeNum) { unsigned char packet[MAX_PACKET_SIZE]; struct sockaddr_ll sll; int ifnum; packet[0] = vnodeNum; memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_protocol = htons(ETH_P_ALL); for (ifnum = firstInterface; ifnum <= lastInterface; ifnum++) { int sizein = 14; // >= ethernet packet size ! sll.sll_ifindex = ifindex[ifnum]; if (DEBUG) { printf("Send to eth%d\n", ifnum); } ssize_t sizeout = sendto(fd[ifnum], packet, sizein, 0, (struct sockaddr *)&sll, sizeof(sll)); if (sizeout < 0) { perror("sendto"); } } } /** * Main program */ int32_t main(int32_t argc, char **argv) { unsigned char packet[MAX_PACKET_SIZE]; int32_t ifnum;// interface number (different from ifindex) int32_t vnodeNum = 1; struct timeval now; struct timezone tz; gettimeofday(&now, &tz); time_t time = now.tv_sec; int32_t count = 0; if (++count < argc) { vnodeNum = atoi(argv[count]); } firstInterface = FirstInterface; lastInterface = LastInterface; if (++count < argc) { lastInterface = atoi(argv[count]); } // Open raw sockets and initialize for sending packets for (ifnum = firstInterface; ifnum <= lastInterface; ifnum++) { fd[ifnum] = open_socket(ifnum, &ifindex[ifnum]); // Set non-blocking mode: int32_t flags = fcntl(fd[ifnum], F_GETFL, 0); fcntl(fd[ifnum], F_SETFL, O_NONBLOCK | flags); } for (;;) { for (ifnum = firstInterface; ifnum <= lastInterface; ifnum++) { ssize_t sizein = recv(fd[ifnum], packet, MAX_PACKET_SIZE, 0); int senderNum = packet[0]; if (sizein >= 0) { printf("Packet received from VNode %d through eth%d (%d bytes)\n", senderNum, ifnum, sizein); } } gettimeofday(&now, &tz); time_t time1 = now.tv_sec; if (time1 > time) { sendPacket(vnodeNum); time = time1; } } }