[ トップページ ]

« VLAN タグつきのパケットを送受信するテスト・プログラム | メイン | ソフトウェアによる Ethernet スイッチ »

ネットワーク・通信

ネットワークで IP がつかえないときの導通テスト・ツール

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

トラックバック

このエントリーのトラックバックURL:
http://www.kanadas.com/mt/mt-tb.cgi/5630

コメントを投稿

このページについて

2012-05-20 16:01 に投稿されたエントリーのページです。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Creative Commons License
このブログは、次のライセンスで保護されています。 クリエイティブ・コモンズ・ライセンス.
Powered by
Movable Type 3.36