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;
}
}
}
