[Fwd: Re: Testing Dual Ethernet via Loopback]

From: Ben Greear
Date: Tue Apr 20 2004 - 11:29:59 EST


Looks like this message failed to go through the first time...


-------- Original Message --------
Subject: Re: Testing Dual Ethernet via Loopback
Date: Mon, 19 Apr 2004 18:44:27 -0700
From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
Organization: Candela Technologies
To: Nick Popoff <cryptic-lkml@xxxxxxxxxxxxxxxx>
CC: linux-kernel@xxxxxxxxxxxxxxx
References: <200404190614.21764.cryptic-lkml@xxxxxxxxxxxxxxxx>

Nick Popoff wrote:
Greetings,

I am trying to write some software to test a dual port ethernet card. I
was hoping to be able to use an ethernet cable to just connect the
ethernet board to itself and then write a program that talks to itself to
make sure that both ports are working. However, I've noticed that Linux
is smart enough to realize it is talking to its own IP address, and it
just delivers the data internally rather than use the network hardware at
all.

So what I'm wondering is if there is a way to force Linux to actually
utilize its network hardware in sending these packets to itself? In other
words, a ping or file transfer from an IP assigned to eth0 to another IP
assigned to eth1 should fail if I unplug the network cable connecting the
two. Any advice on this would be much appreciated. I'm not afraid of
reading kernel source but have no idea where to start on this one.

I'm using 2.4.22 but would use any 2.4 or 2.6 kernel that supported this
behavior. The National Semiconductor DP83815 (natsemi.o) is the ethernet chipset.

You can apply the candela* patch from http://www.candelatech.com/~greear/vlan.html
and then use SO_BINDTODEVICE with something similar to this, where dev_to_bind_to
is a local interface, like "eth2":

int createTcpSocket(unsigned int ip_addr, int ip_port, const char* dev_to_bind_to) {
LF_TRC_IN_NT;
VLOG_DBG(VLOG << "ip_addr -:" << ip_addr << ": ip_port: " << ip_port << endl);
char *opt;

int s = socket(AF_INET, SOCK_STREAM, 0);

VLOG_INF(VLOG << "createTcpSocket: ip_addr -:" << ip_addr << ": " << toStringIP(ip_addr)
<< ": ip_port: " << ip_port << " socket: " << s << endl);

if (s < 0) {
cerr << "ERROR: tcp socket: " << strerror(errno) << endl;
VLOG << "ERROR: tcp socket: " << strerror(errno) << endl;
return s;
}

if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&opt,
sizeof(opt)) < 0) {
cerr << "ERROR: setsockopt: " << strerror(errno) << endl;
LFEXIT(100);
}//if

if (dev_to_bind_to) {
// Bind to specific device.
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
dev_to_bind_to, DEV_NAME_LEN + 1)) {
VLOG_ERR(VLOG << "ERROR: tcp-connect, setsockopt (BINDTODEVICE): "
<< strerror(errno) << " Not fatal in most cases..continuing...\n");
}
}//if

struct sockaddr_in my_ip_addr;
memset(&my_ip_addr, 0, sizeof(my_ip_addr));

my_ip_addr.sin_family = AF_INET;
my_ip_addr.sin_addr.s_addr = htonl(ip_addr);
my_ip_addr.sin_port = htons(ip_port);

int r; //retval
r = bind(s, (struct sockaddr*)(&my_ip_addr), sizeof(my_ip_addr));
if (r < 0) {
//system("netstat -an");
cerr << "ERROR: tcp bind: " << strerror(errno) << endl;
VLOG_ERR(VLOG << "ERROR: tcp bind: " << strerror(errno) << " IP: "
<< toStringIP(ip_addr) << " ipPort: " << ip_port << endl);
close(s);
return r;
}
else {
VLOG_INF(VLOG << "Successfully bound to IP: " << toStringIP(ip_addr) << " port: "
<< ip_port << endl);
}

nonblock(s);
return s;
}


You will need to enable the send-to-self flag with something like this:

// Set us up to accept local-generate packets if the kernel can support
// it... (send-to-self)
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
mudlog << "ERROR: socket: " << strerror(errno) << endl;
}
else {
memset(&ifr, 0, sizeof(struct ifreq));

// query to see if we are set up for send-to-self
strcpy(ifr.ifr_name, dev_name);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(fd, 0x89a1, &ifr) < 0) {
VLOG_ERR(VLOG << "ERROR: send-to-self ioctl(0x89a1): " << strerror(errno)
<< " ifr.ifr_name -:" << ifr.ifr_name << ":-" << endl);
setSendToSelf(false);
}
else {
if (ifr.ifr_flags) {
setSendToSelf(true);
}
else {
// Try to make send_to_self true
memset(&ifr, 0, sizeof(struct ifreq));

strcpy(ifr.ifr_name, dev_name);
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_flags = 1;
if (ioctl(fd, 0x89a0, &ifr) < 0) {
VLOG_ERR(VLOG << "ERROR: send-to-self ioctl(0x89a0): "
<< strerror(errno) << " ifr.ifr_name -:"
<< ifr.ifr_name << ":-" << endl);
setSendToSelf(false);
}
else {
setSendToSelf(true);
VLOG_ERR(VLOG << "Set send-to-self bit to true for interface: "
<< ifr.ifr_name << endl);
}
}//else, try to enable send-to-self
}//else, we could read send-to-self IOCTL
close(fd);
}//else, could open socket


Hope that helps,
Ben

--
Ben Greear <greearb@xxxxxxxxxxxxxxx>
Candela Technologies Inc http://www.candelatech.com

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/