Coding for Ethernet PHY Loopback Test - linux

I have to write a Ethernet PHY loopback test in Linux. I've never done it before and had no clue where to start. After some researching, I came up with the plan for the test, and I wonder if anyone can help me to verify it and give me some pointers to my questions.
This is a external loopback setup. It connects the TX+/- to RX+/- pins for each internal PHY's on the Ethernet switch chip.
So the loopback high level packet path is as follow:
CPU->PHY0(chip)->Ethernet switch(chip)'s internal PHY->PHY0(chip)->CPU
For this test, I plan to
configure the internal PHYs on the Ethernet switch with specific MAC addresses,
pack the Ethernet test packet using CPU's MAC address as the source address and the
MAC address configured in step 1. as the destination address,
send and wait to receive the test packet,
compare sent and received data pattern.
Any suggestions? Also, I wonder if there are functions in Linux that I can use to generate the packets for step 2, and send the packets for step 3.
Thank you very much.

Most Phys can be switched to a test mode. We used the bootloader to write directly to the
Phy and switch to testing mode.
There is also an ioctl taken from documentation/networking/phy.txt
Ethtool convenience functions.
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
The MII ioctl. Note that this function will completely screw up the state
machine if you write registers like BMCR, BMSR, ADVERTISE, etc. Best to
use this only to write registers which are not standard, and don't set off
a renegotiation.

Related

Programatically inject packets to virtual interface

We are currently developing a prototype aiming to "bridge" a local virtual interface in Linux to an API sending/receiving Ethernet packets using proprietary hardware. The idea is in the end to use standard libraries and tools transparently with this proprietary hardware.
As a first step ensuring that what we want to do is indeed possible, we made a first version of the prototype bridging a virtual interface to an actual Ethernet interface using libpcap. Here is what we did :
create a local dummy interface on PC1 with a MAC/IP address (192.168.0.1)
configure PC2 with an IP on the same network (192.168.0.2)
link PC1 and PC2 using a non-configured interface on PC1
use a simple 'bridge' program on PC1, developed with libpcap that listens on one interface and inject packets on the second one (using pcap_sendpacket), and the other way around, to bridge dummy interface and actual Ethernet interface
launch ping from PC1 to PC2
When spying on the dummy interface on PC1, we observe ICMP requests and responses, so the bridge program works OK, but the ping tool does not get the ICMP responses at application level.
I'm guessing we inject packets too late in the kernel routing process...or something.
Do you know how to do this properly? Maybe use an alternate type of virtual interface? (bridge, tun/tap...) It cannot be a full system/command line solution since in the end we want to bridge packets to a proprietary API and not to an Ethernet interface, so we need programmatic access to the packets (hence libpcap).
Thanks in advance for your help.
This is not possible with dummy module interfaces in Linux. They can only transmit packets 'downwards', from the kernel to the network hardware device. And, as in the case of dummy interfaces there is no hardware device, packets are discarded when they reach the bottom of this path (dummy_xmit function). You can treat it as a one-way sink.
Here is the call graph:
[applications]
[tcp/ip stack]
|
|
v
pcap_sendpacket -> tpacket_snd -> dev_queue_xmit -> dev_hard_start_xmit -> xmit_one -> netdev_start_xmit -> ndo_start_xmit -> dummy_xmit -> dev_kfree_skb
|
|
pcap_next <- tpacket_rcv <- prot_hook.func <- deliver_skb <-dev_queue_xmit_nit <-----
So, in your case, ping requests from ping application go into the device transmission path. They are discarded at the end of this path, but before that, they are copied and these copies are being passed into the pcap bridge listening on the interface. Bridge application forwards them to the PC2. PC2 answers ping requests and send responses back to the bridge application. The bridge application injects these responses into the device transmission path, they go downwards it and are discarded. But before that, they are copied to all pcap listeners, including tcpdump you use to spy and observe traffic, but excluding your bridge application which injected them:
++ net/core/dev.c
## void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
...
/* Never send packets back to the socket
* they originated from - MvS (miquels#drinkel.ow.org)
*/
if (skb_loop_sk(ptype, skb))
continue;
This is why you see both requests and responses. But responses are not being passed up to the kernel TCP/IP stack and ping application, because this is not possible with dummy interface. They are transmitted downwards to dummy_xmit and discarded.
Therefore, in your case, you should use either TAP interface, or, if you want to still use pcap to exchange packets, veth virtual links.

linux network drivers --- net_device_ops

so far i have only used file operational structure in device driver.
Using system call open & read , write.
How to open device driver & transmit data using net_device_ops ?
Is there reference example on net for the user program to interact with it ?
http://lnxpps.de/rpie/mcp2515_mod.c
I'm not sure I understand the question, so let me know if my answer doesn't make sense.
I see you have defined functions for .ndo_open, .ndo_stop, and .ndo_start_xmit. .ndo_open is called by the kernel when you configure the interface using ifconfig up or use ifconfig to assign an address to the interface. .ndo_stop is called by the kernel when you remove the module or if you shutdown the interface using ifconfig down.
ifconfig is described here: http://linux.die.net/man/8/ifconfig
.ndo_start_xmit is called by the kernel network stack when a socket is used to transmit a packet. So, to transmit data using .ndo_start_xmit you'll need to create a socket, assign an appropriate destination address, and send the data via the socket. If you're using IP, there are tools you can use send packets easily, such as netperf or iperf.

Linux bridge of my own making: arp request never succeeds

I wrote a bridge (layer 2 switch) using my Boost.Asio extension. We can easily make additional sockets, endpoints and protocols which meet their type requirements. And my extension uses linux packet socket with AF_PACKET, SOCK_RAW and htons(ETH_P_ALL) (See man 7 packet for more information about packet socket).
Here's an example for explaining how my bridge works:
[PC1] <----> IF1[PC2]IF2 <----> [PC3]
Bridge connects the network interfaces(e.g. eth0) IF1 and IF2 so PC1 can communicate with PC3 via bridge running on PC2. The way to connect interfaces is sending packets received from IF1 to IF2 (and vice versa)
My bridge works under the wired connections as expected, but it doesn't work under the wireless connections. So I tried to find what causes this problem and I found that ARP request never succeeded.
The actual environment which causes this problem is:
[PC1] <--wired--> eth0[PC2]wlan0 <--wireless(802.11g)--> [router1]
Under the environment above, for example, now PC1 tries to send ping(ICMP) packet to router1. To send it to PC3, PC1 has to know the MAC address of router1 so PC1 sends ARP request to FF:FF:FF:FF:FF:FF And my bridge running on PC2 receives it from eth0 and send it to wlan0, but router1 never sends arp reply to PC1.
note: SOCK_RAW packets are passed to and from the device driver without any changes in the packet data. (quoted from man page of packet)
What should I do to allow PC1 to communicate with router1?
Thank you.
Edit:
Here is my Boost.Asio extension.
github: pfpacket/libarex
And this is my bridge using above.
libarex/example/layer2_switch/interface_bridge.cpp
I'm writing up what we discussed in the comments.
It is a common problem that wireless bridging is problematic (under linux at least, I don't know for others). Investigation has shown that most probably the wireless driver or chipset of the hardware used as bridge is incapable of doing bridging operations (brctl failing supports this assumption).
Other possible reasons, as explained in the link above, may be the AP dropping packets with unassociated MAC adresses or the likes.
Additionally, the code works fine for wired interfaces, so it is a hardware problem on some layer. Not much more to say about it.

How create a virtual io device in Linux that proxies data to real device?

I have an interesting problem. I am working on an embedded box with multiple instances of Linux running each on an ARM processor. They are connected over internal 1GBps network. I have a serial port device node attached to processor A (Lets say Linux-A running on it). I have a program running on processor B (Lets say on Linux-B) access the serial port device as if it is attached to Linux-B locally.
My program invokes term i/o type api calls on device node to control tty echo, character mode input. What I am wondering is if there is a way to create a virtual serial device that is available on Linux-B somehow talking to real serial device on Linux-A over internal network.
I am thinking something along the lines of:
Linux-B has /dev/ttyvirtual. Anything that gets written to it gets transported over network socket to Linux-A serialserver. The serial server exrcises the api calls on real device lets say /dev/ttys0.
Any data waiting on ttys0 gets transported back to /dev/ttyvirtual.
What are all the things involved to get this done fast?
Thanks
Videoguy
Update:
I found a discussion at
http://fixunix.com/bsd/261068-network-socket-serial-port-question.html with great pointers.
Another useful link is http://blog.philippklaus.de/2011/08/make-rs232-serial-devices-accessible-via-ethernet/
Take a look at openpty(3). This lets you create a pseudo-TTY (like /dev/pts/0, the sort that ssh connections use), which will respond as a normal TTY would, but give you direct programmatic control over the connections.
This way you can host a serial device (eg. /dev/pts/5) that you forward data between a network connection, and then other apps can perform serial operations on it without knowing about the underlying network bridge.
I ended up using socat
Examples can be found here: socat examples
You socat back to back on both the machines. One listens on a tcp port and forwards data to local virtual port or pty. The socat on other box uses real device as input and forwards any data to tcp port.

bond on software-bridge connection issue

What you have:
bond (bond0) interface (all modes except 4) with at least 2 ifaces (say eth0 / eth1) connected on the same external switch
bond0 interface joined on a software bridge (br0)
virtual machine (vm0) (eg LibVirt::LXC) with an interface on br0
What you get:
vm0 is not able to connect to (most) IP addresses via bond0 over br0
"bond0: received packet with own address as source address" in syslog
Why you get this:
When vm0 wants to contact an external IP address it will send out an ARP request. This L2 broadcast with the source mac of vm0 will leave through (depending on bonding mode) eg eth0, but via the external switch, re-enter through eth1 and thus bond0. Hence the switch br0 will learn the mac-address of vm0 on the port connected to bond0. As a consequence the ARP-reply is never received by vm0.
What can you do to resolve:
The reason I post this, next to sharing the info, is that I wasn't able to figure out a good enough solution. Those I did find are:
On vm0 set static ARP entry
Use bond0 mode=4 but your external switch must support this
Configure your external siwtch to use private VLAN on eth0/eth1 but only works in some use-cases and adds complexity
Add both physical interfaces to the bridge with spanning tree enabled, instead of using bond driver
Statically configuring the MAC of vm0 on the correct port of br0 is not an option on Linux (works on OpenBSD though)
I'm really hoping for a more elegant solution here... Anyone?
Thanks
I've got the same problem and I come up with the same analysis.
The only non-invasive/scalable solution I've found is to use the active/backup bonding (mode 1). The tradeoff is that you lose the aggregation.
IMO, the best solution is to use 802.3ad, but I can't always use it because I'm limited with 6 port-channels on most of my switches.
Try these options in bridge:
brigde_fd 0
bridge_stp off # switch on with more system like this
bridge_maxage 0
bridge_ageing 0
bridge_maxwait 0
Taken from this thread:
kvm bridge also in proxmox

Resources