Name

Synthetic Target Ethernet Support — Allow synthetic target applications to perform ethernet I/O

Overview

The synthetic target ethernet package can provide up to four network devices, eth0 to eth3. These can be used directly by the eCos application or, more commonly, by a TCP/IP stack that is linked with the eCos application. Each eCos device can be mapped on to a real Linux network device. For example, if the Linux PC has two ethernet cards and eth1 is not currently being used by Linux itself, then one of the eCos devices can be mapped on to this Linux device. Alternatively, it is possible to map some or all of the eCos devices on to the ethertap support provided by the Linux kernel.

The ethernet package depends on the I/O auxiliary provided by the synthetic target architectural HAL package. During initialization the eCos application will attempt to instantiate the desired devices, by sending a request to the auxiliary. This will load a Tcl script ethernet.tcl that is responsible for handling the instantiation request and subsequent I/O operations, for example transmitting an ethernet packet. However, some of the low-level I/O operations cannot conveniently be done by a Tcl script so ethernet.tcl will actually run a separate program rawether to interact with the Linux network device.

On the target-side there are configuration options to control which network devices should be present. For many applications a single device will be sufficient, but if the final eCos application is something like a network bridge then the package can support multiple devices. On the host-side each eCos network device needs to be mapped on to a Linux one, either a real ethernet device or an ethertap device. This is handled by an entry in the target definition file:

synth_device ethernet {
    eth0 real eth1
    eth1 ethertap tap3 00:01:02:03:FE:05
    …
}

The ethernet package also comes with support for packet logging, and provides various facilities for use by user Tcl scripts.

Installation

Before a synthetic target eCos application can access ethernet devices it is necessary to build and install host-side support. The relevant code resides in the host subdirectory of the synthetic target ethernet package, and building it involves the standard configure, make and make install steps. The build involves a new executable rawether which must be able to access a raw Linux network device. This is achieved by installing it suid root, so the make install step has to be run with superuser privileges.

[Caution]Caution

Installing rawether suid root introduces a potential security problem. Although normally rawether is executed only by the I/O auxiliary, theoretically it can be run by any program. Effectively it gives any user the ability to monitor all ethernet traffic and to inject arbitrary packets into the network. Also, as with any suid root programs there may be as yet undiscovered exploits. Users and system administrators should consider the risks before running make install.

There are two main ways of building the host-side software. It is possible to build both the generic host-side software and all package-specific host-side software, including the ethernet support, in a single build tree. This involves using the configure script at the toplevel of the eCos repository. For more information on this, see the README.host file at the top of the repository. Note that if you have an existing build tree which does not include the synthetic target ethernet support then it will be necessary to rerun the toplevel configure script: the search for appropriate packages happens at configure time.

The alternative is to build just the host-side for this package. This requires a separate build directory, building directly in the source tree is disallowed. The configure options are much the same as for a build from the toplevel, and the README.host file can be consulted for more details. It is essential that the ethernet support be configured with the same --prefix option as other eCos host-side software, especially the I/O auxiliary provided by the architectural synthetic target HAL package, otherwise the I/O auxiliary will be unable to locate the ethernet support.

Target-side Configuration Options

The target-side code can be configured to support up to four ethernet devices, eth0 to eth3. By default eth0 is enabled if the configuration includes a TCP/IP stack, otherwise it is disabled. The other three devices are always disabled by default. If any of the devices are enabled then there will also be the usual configuration options related to building this package. Other options related to network devices, for example whether or not to use DHCP, are provided by the generic network device package.

Real Ethernet

One obvious way of providing a synthetic target eCos application with ethernet I/O is to use a real ethernet device in the PC: transmitted packets go out on a real network, and packets on the network addressed to the right MAC address are passed on to eCos. This way synthetic target networking behaves just like networking on a real target with ethernet hardware. For example, if there is a DHCP server anywhere on the network then eCos will be able to contact it during networking startup and get hold of IP address information.

Configuring the ethernet support to use a real ethernet device requires a simple entry in the target definition file:

synth_device ethernet {
    <eCos device> real <linux device>
    …
}

For example, to map the eCos network device eth0 to the Linux device eth1:

synth_device ethernet {
    eth0 real eth1
    …
}

It is not possible for an ethernet device to be shared by both the eCos TCP/IP stack and the Linux one: there would be no simple way to work out which stack incoming packets are intended for. In theory it might be possible to do some demultiplexing using distinct IP addresses, but it would be impossible to support some functionality such as DHCP. Therefore the rawether program will refuse to access any ethernet device already in use. On a typical Linux system eth0 will be used for Linux networking, and the PC will have to be equipped with additional ethernet devices for use by eCos.

The rawether program will access the hardware via the appropriate Linux device driver, so it is important that the system is set up such that the relevant module will be automatically loaded or is already loaded. The details of this will depend on the installed distribution and version, but typically it will involve an entry in /etc/modules.conf.

Ethertap

The Linux kernel's ethertap facility provides a virtual network interface. A Linux application, for example the rawether program, can open a special character device /dev/net/tun, perform various ioctl calls, and then write and read ethernet packets. When the device is opened the Linux kernel automatically creates a new network interface, for example tap0. The Linux TCP/IP stack can be made to use this network interface like any other interface, receiving and transmitting ethernet packets. The net effect is a virtual network connecting just the Linux and eCos TCP/IP stacks, with no other nodes attached. By default all traffic remains inside this virtual network and is never forwarded to a real network.

Support for the ethertap facility may or may not be provided automatically, depending on your Linux distribution and version. If your system does not have a device /dev/net/tun or a module tun.o then the appropriate kernel documentation should be consulted, for example /usr/src/linux-2.4/Documentation/networking/tuntap.txt. If you are using an old Linux kernel then the ethertap functionality may be missing completely. When the rawether program is configured and built, the configure script will check for a file /usr/include/linux/if_tun.h. If that file is missing then rawether will be built without ethertap functionality, and only real ethernet interfaces will be supported.

The target definition file is used to map eCos network devices on to ethertap devices. The simplest usage is:

synth_device ethernet {
    eth0 ethertap
    …
}

The Linux kernel will automatically allocate the next available tap network interface. Usually this will be tap0 but if other software is using the ethertap facility, for example to implement a VPN, then a different number may be allocated. Usually it will be better to specify the particular tap device that should be used for each eCos device, for example:

synth_device ethernet {
    eth0 ethertap tap3
    eth1 ethertap tap4
    …
}

The user now knows exactly which eCos device is mapped onto which Linux device, avoiding much potential confusion. Because the virtual devices are emulated ethernet devices, they require MAC addresses. There is no physical hardware to provide these addresses, so normally MAC addresses will be invented. That means that each time the eCos application is run it will have different MAC addresses, which makes it more difficult to compare the results of different runs. To get more deterministic behaviour it is possible to specify the MAC addresses in the target definition file:

synth_device ethernet {
    eth0 ethertap tap3 00:01:02:03:FE:05
    eth1 ethertap tap4 00:01:02:03:FE:06
    …
}

During the initialization phase the eCos application will instantiate the various network devices. This will cause the I/O auxiliary to load the ethernet.tcl script and spawn rawether processes, which in turn will open /dev/net/tun and perform the appropriate ioctl calls. On the Linux side there will now be new network interfaces such as tap3, and these can be configured like any other network interface using commands such as ifconfig. In addition, if the Linux system is set up with hotplug support then it may be possible to arrange for the network interface to become active automatically. On a Red Hat Linux system this would require files such as /etc/sysconfig/network-scripts/ifcfg-tap3, containing data like:

DEVICE="tap3"
BOOTPROTO="none"
BROADCAST=10.2.2.255
IPADDR="10.2.2.1"
NETMASK="255.255.255.0"
NETWORK=10.2.2.0
ONBOOT="no"

This gives the Linux interface the address 10.2.2.1 on the network 10.2.2.0. The eCos network device should be configured with a compatible address. One way of doing this would be to enable CYGHWR_NET_DRIVER_ETH0_ADDRS, set CYGHWR_NET_DRIVER_ETH0_ADDRS_IP to 10.2.2.2, and similarly update the NETMASK, BROADCAST, GATEWAY and SERVER configuration options.

It should be noted that the ethertap facility provides a virtual network, and any packets transmitted by the eCos application will not appear on a real network. Therefore usually there will no accessible DHCP server, and eCos cannot use DHCP or BOOTP to obtain IP address information. Instead the eCos configuration should use manual or static addresses.

When rawether exits, the tap interface is removed by the kernel. By adding the parameter persistent rawether will set the persistent flag on the tap device.

synth_device ethernet {
    eth0 ethertap tap3 00:01:02:03:FE:05
    eth1 ethertap tap4 00:01:02:03:FE:06 persistent
    …
}

With this flag set the kernel will not remove the interface when rawether exits. This means applications such as dhcpd, radvd, and tcpdump will continue to run on the interface between invocations of synthetic targets. As a result the target can dynamically obtain its IP addresses from these daemons. Note it is a good idea to specify a MAC address otherwise a different random MAC address will be used each time and the dhcpd daemon will not be able to reissue the same IP address.

Host daemons like dhcpd, ntpd, radvd etc are started at boot time. Since the tap device does not exists at this point in time it is not possible for these daemons to bind to the tap device. A simple solution is to use the program install/bin/mktap. This takes one parameter, the name of the tap device it should create. eg, tap3.

An alternative approach would be to set up the Linux box as a network bridge, using commands like brctl to connect the virtual network interface tap3 to a physical network interface such as eth0. Any packets sent by the eCos application will get forwarded automatically to the real network, and some packets on the real network will get forwarded over the virtual network to the eCos application. Note that the eCos application might also get some packets that were not intended for it, but usually those will just be discarded by the eCos TCP/IP stack. The exact details of setting up a network bridge are left as an exercise to the reader.

Packet Logging

The ethernet support comes with support for logging the various packets that are transferred, including a simple protocol analyser. This generates simple text output using the filter mechanisms provided by the I/O auxiliary, so it is possible to control the appearance and visibility of different types of output. For example the user might want to see IPv4 headers and all ICMPv4 and ARP operations, but not TCP headers or any of the packet data.

The protocol analyser is not intended to be a fully functional analyser with knowledge of many different TCP/IP protocols, advanced search facilities, graphical traffic displays, and so on. Functionality like that is already provided by other tools such as ethereal and tcpdump. Achieving similar levels of functionality would require a lot of work, for very little gain. It is still useful to have some protocol analysis functionality available because the output will be interleaved with other output, for example printf calls from the application. That may make it easier to understand the sequence of events.

One problem with logging ethernet traffic is that it can involve very large amounts of data. If the application is expected to run for a long time or is very I/O intensive then it is easy to end up with many megabytes. When running in graphical mode all the logging data will be held in memory, even data that is not currently visible. At some point the system will begin to run low on memory and performance will suffer. To avoid problems, the ethernet script maintains a flag that controls whether or not packet logging is active. The default is to run with logging disabled, but this can be changed in the target definition file:

synth_device ethernet {
    …
    logging 1
}

The ethernet script will add a toolbar button that allows this flag to be changed at run-time, allowing the user to capture traffic for certain periods of time while the application continues running.

The target definition file can contain the following entries for the various packet logging filters:

synth_device ethernet {
    …
    filter ether  -hide 0 -background LightBlue -foreground "#000080"
    filter arp    -hide 0 -background LightBlue -foreground "#000050"
    filter ipv4   -hide 0 -background LightBlue -foreground "#000040"
    filter ipv6   -hide 1 -background LightBlue -foreground "#000040"
    filter icmpv4 -hide 0 -background LightBlue -foreground "#000070"
    filter icmpv6 -hide 1 -background LightBlue -foreground "#000070"
    filter udp    -hide 0 -background LightBlue -foreground "#000030"
    filter tcp    -hide 0 -background LightBlue -foreground "#000020"
    filter hexdata   -hide 1 -background LightBlue -foreground "#000080"
    filter asciidata -hide 1 -background LightBlue -foreground "#000080"
}

All output will show the eCos network device, for example eth0, and the direction relative to the eCos application. Some of the filters will show packet headers, for example ether gives details of the ethernet packet header and tcp gives information about TCP headers such as whether or not the SYN flag is set. The TCP and UDP filters will also show source and destination addresses, using numerical addresses and if possible host names. However, host names will only be shown if the host appears in /etc/hosts: doing full DNS lookups while the data is being captured would add significantly to complexity and overhead. The hexdata and asciidata filters show the remainder of the packets after the ethernet, IP and TCP or UDP headers have been stripped.

Some of the filters will provide raw dumps of some of the packet data. Showing up to 1500 bytes of data for each packet would be expensive, and often the most interesting information is near the start of the packet. Therefore it is possible to set a limit on the number of bytes that will be shown using the target definition file. The default limit is 64 bytes.

synth_device ethernet {
    …
    max_show 128
}

User Interface Additions

When running in graphical mode the ethernet script extends the user interface in two ways: a button is added to the toolbar so that users can enable or disable packet logging; and an entry is added to the Help menu for the ethernet-specific documentation.

Command Line Arguments

The synthetic target ethernet support does not use any command line arguments. All configuration is handled through the target definition file.

Hooks

The ethernet support defines two hooks that can be used by other scripts, especially user scripts: ethernet_tx and ethernet_rx. The tx hook is called whenever eCos tries to transmit a packet. The rx hook is called whenever an incoming packet is passed to the eCos application. Note that this may be a little bit after the packet was actually received by the I/O auxiliary since it can buffer some packets. Both hooks are called with two arguments, the name of the network device and the packet being transferred. Typical usage might look like:

  proc my_tx_hook { arg_list } {
    set dev [lindex $arg_list 0]
    incr ::my_ethernet_tx_packets($dev)
    incr ::my_ethernet_tx_bytes($dev) [string length [lindex $arg_list 1]]
  }
  proc my_rx_hook { arg_list } {
    set dev [lindex $arg_list 0]
    incr ::my_ethernet_rx_packets($dev)
    incr ::my_ethernet_rx_bytes($dev) [string length [lindex $arg_list 1]]
  }
  synth::hook_add "ethernet_tx" my_tx_hook
  synth::hook_add "ethernet_rx" my_rx_hook

The global arrays my_ethernet_tx_packets etc. will now be updated whenever there is ethernet traffic. Other code, probably running at regular intervals by use of the Tcl after procedure, can then use this information to update a graphical monitor of some sort.

Additional Tcl Procedures

The ethernet support provides one additional Tcl procedure that can be used by other scripts;

ethernet::devices_get_list    

This procedure returns a list of the ethernet devices that have been instantiated, for example {eth0 eth1}.