Testing IPv6 addressing in a network simulator – Part 2

In Part 1 of this series, we performed some practical experiments to show how interfaces in an IPv6 network configure themselves with link-local IPv6 addresses when they start up. We also showed how to manually configure IPv6 addresses on a Linux system. In this post, we will use an open-source network simulator to demonstrate another method of assigning an IPv6 address to an interface: Stateless Address Auto-configuration (SLAAC).

We will use the CORE Network Emulator to set up a simple IPv6 network and then run some practical exercises to show how to set up a open-source IPv6 router to perform auto-configuration using either radvd or quagga. We’ll use open-source routing software to demonstrate real router configuration procedures and investigate how IPv6 routers and hosts communicate to assign globally unique unicast IPv6 addresses to hosts the using Stateless Address Auto-configuration and the Neighbor Discovery Protocol (NDP).

Stateless Address Auto-configuration

Stateless Address Auto-configuration (SLAAC) is an IPv6 function that simplifies network administration ((Of course, one solution always creates another challenge — We must now consider the security implications of allowing routers to automatically configure prefixes on a link and allowing hosts to accept these advertised IPv6 prefixes from routers, but that is a topic for another post.)). SLAAC is the preferred way to assign IPv6 addresses on hosts in an IPv6 network.

To enable auto-configuration, the network administrator manually enters in the router’s configuration file the prefixes that routers will advertise to the hosts on each link. Then, the router advertises that prefix to all hosts on the link via the Neighbor Discovery Protocol.

Host Interface ID

The hosts use a combination of the IPv6 network prefix learned from the router and their own interface MAC address to create a unique IPv6 address.

Router Interface ID

Routers do not allow their interface addresses to be auto-configured ((A Linux system considers itself to be an IPv6 router if the Linux kernel parameter net.ipv6.conf.all.forwarding is set to 1.)). The network administrator must manually configure IPv6 addresses on each router interface.

Default Routes on Hosts

Each host uses the Neighbor Discovery Protocol to learn about all routers attached to the same link and automatically configure default routes to the advertising routers.

When using IPv6, hosts may have multiple default routes to different routers on the same link, which may provide for more efficient routing to different destinations.

Router Advertisement Daemon (radvd)

The Router Advertisement Daemon (radvd) is open-source software that implements stateless address auto-configuration using the Neighbor Discovery Protocol (NDP). It listens for messages from hosts requesting prefix information and periodically sends out advertisement messages describing information about the router to all hosts on the link.

Default configurations and file locations

To realistically emulate SLAAC configuration procedures on a simulated Linux IPv6 router, we need to use the built-in functions of the CORE Network Emulator and some undocumented information about the virtual node configuration files.

CORE uses LXC Network Namespaces to implement virtual nodes in the simulation. The CORE GUI hides from the user the complexities involved in starting routing daemons on Linux containers using network namespaces (which is what the designers intended). To show how we would configure a router using Linux commands we will modify the configuration procedures that take into account the way CORE virtualizes nodes and starts services on the virtual nodes.

Each node in the simulation consists of a lightweight virtual machine that only isolates the network stack and a few selected files. Because the rest of the filesytem is shared between all the virtual nodes and the host Linux system, we need to know which files on the simulated nodes we can modify and which we should not. The configuration files will be in non-standard locations on the simulated nodes and, unfortunately, this is not well documented. It is better to use only Linux configuration commands and leave configuration files and startup scripts alone.

Set up the network topology

Start the CORE Network Emulator with the following commands:

$ sudo /etc/init.d/core-daemon start
$ core-gui

Load a network configuration file

We will use the same network configuration that we created and saved in Part 1 of this series. Open the *.imn file you saved. In my case, I named it IPv6-addresses.imn.

Simulated IPv6 network topology
Simulated IPv6 network topology

Configure the network initial state

If we allow it to, the CORE Network Emulator will set up IP addresses, generate the contents of configuration files, and start daemons for us. However, in a case where we wish to practise using the Linux command-line to configure each virtual node, we need to change the CORE default settings before we start the simulation.

Complete the following steps to set up the network scenario so that we can use (mostly) realistic command-line procedures to configure the nodes in the simulated network.

Determine the services we will use on each node

To keep things simple, we will start only the services we need on each node.

On router r1, we need only two services: IPForward and radvd.

On each host, h1 to h4, we do not need any services configured. Even the DefaultRoute service can be cleared because it is only useful if we configure a static IP address using the CORE GUI, and we won’t do that in this case.

Verify that no IP addresses are assigned in the CORE Network Emulator

IP addresses should not be configured on any of the interfaces because we want to configure these using Linux commands on each simulated node after starting the simulation. Since we are using a saved network scenario from Part 1 of this series, where we already cleared the IP addresses, we should already have the correct configuration. But, it never hurts to check.

Right-click on each node and select Configure from the drop-down menu. In the configuration window, ensure every IP address field is blank. If not, clear them by clicking on the trash icon next to the field and then click Apply.

Delete IP addresses by clicking on the trash icon next to each field
Delete IP addresses by clicking on the trash icon next to each field

Clear all services on each host, h1 to h4

Right-click on each host node in the CORE canvas and select Services…

Then, clear all services on the host nodes so that nothing is selected. Click on Apply to save the changes.

Clear all services on each host node
Clear all services on each host node

Enable the radvd service on the router r1

We need to enable radvd so we can manage it after we start the scenario in the CORE Network Emulator, but we do not want CORE to create a radvd configuration file for us. Because we ensured no IP addresses were assigned in CORE in Step 1 above, CORE will not automatically generate the contents of the radvd.conf.

Right-click on router r1, then select Services from the drop-down menu. Clear all services so that none are selected. Then, click on the radvd service to enable it.

Enable only the radvd service in IPv6 router
Enable only the radvd service in IPv6 router

Next, click on the small “tool” icon next to radvd in the Services window. This will open the radvd configuration window. You don’t change anything in this window. Confirm that the radvd.conf file that CORE will generate on router r1 is empty. Also note that CORE will create the file in a non-standard location: /etc/radvd/radvd.conf. This is because CORE creates a mount namespace for the new file /etc/radvd/radvd.conf so it does not affect the host computer’s configuration of the configurations of other nodes in the simulation. (Remember: all virtual nodes share the same filesystem, except where specific folders are provided with their own mount namespace by CORE Services scripts).

Check radvd.conf contents and location
Check radvd.conf contents and location

Close the radvd window. Then, click Apply on the Services window.

Verify the IPForward service configuration on router r1

When starting a simulation scenario, the CORE Network Emulator executes commands on the router that configure Linux kernel parameters to enable IP Forwarding. It does not update the /etc/sysctl.conf file because that file is not isolated to the simulated node.

Click on the “tool” icon next to the IPForward service. This will open the IPForward service configuration window. You can see the kernel parameters that will be set by this service. The CORE Network Emulator will execute the script shown when the router is started. We see the IP Forwarding configurations will enable IPv4 and IPv6 forwarding. (These configurations can be changed in this window and then saved, if you want the router to start with a different set of parameters.)

Details of the IPForward service configuration
Details of the IPForward service configuration

On the simulated router, after it is running in the simulation, you can verify the IP Forwarding parameter values with the following command ((If you want to see what happens when these parameters change while the simulated router is running, you can change them with the sysctl -w command. For example, if you wanted to disable IPv6 forwarding you would enter the command root@r1:~# sysctl -w net.ipv6.conf.all.forwarding=0.)):

root@r1:~# sysctl -a | grep forwarding

Run the simulation

Start the simulation by clicking on the green start the session icon in the CORE toolbar or use the menu command:

Session → Start
CORE simulation starting up
CORE simulation starting up

Configure the simulated IPv6 router

Double-click on the router r1 in the canvas. This will open a terminal window on r1.

The radvd.conf configuration file

First we create the configuration file. On this simulated Linux router, the radvd service expects the configuration file is /etc/radvd/radvd.conf.

root@r1:~# vi /etc/radvd/radvd.conf

Enter the following text to configure the prefixes we have chosen to use on each link. These are the same prefixes we used in Part 1 of this series.

interface eth0
{
        AdvSendAdvert on;
        prefix 2001:db8:0:1::/64 { };
};
interface eth1
{
        AdvSendAdvert on;
        prefix 2001:db8:0:2::/64 { };
};

There are other radvd configurations that can be entered in this file but we’ll just keep it simple for now. Unless they are explicitly configured, all other radvd parameters use their default values.

Start radvd

Now, start the radvd service ((CORE failed to start the radvd service when the simulation was first started because the configuration file was empty. After adding valid contents to the configuration file, we need to start radvd again.)). Right-click on the router r1 and select the following menu command from the contextual menu:

Services - radvd - start
Start radvd service on r1

This starts the radvd daemon. You can verify this by checking the processes running on r1 with the ps -ef command:

root@r1:~# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 23:38 ?        00:00:00 /usr/local/sbin/vnoded -v -c /tm
root        52     1  0 23:38 ?        00:00:00 /usr/lib/quagga/zebra -u root -g
root       126     1  0 23:57 pts/7    00:00:00 /bin/bash
root       191     1  0 23:58 ?        00:00:00 radvd -C /etc/radvd/radvd.conf -
root       193     1  0 23:58 ?        00:00:00 radvd -C /etc/radvd/radvd.conf -
root       195   126  0 23:58 pts/7    00:00:00 ps -ef
root@r1:~#

If radvd does not start, it is probably due to a syntax error in the configuration file.

Check IP assigned addresses

After starting radvd, we should see that the hosts have automatically configured IPv6 addresses using the prefixes we configured on the router.

We can verify this using the CORE Network Emulator’s Observer Widget tool or by entering the ip -6 addr show command on each simulated node’s terminal window. For example, on host h1, we see the link-local address with the link-local prefix fe80::/64 and a global unique address using the prefix advertised by the router 2001:db8:0:1::/64:

root@h1:~# ip -6 addr show
1: lo:  mtu 65536 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
50: eth0:  mtu 1500 qlen 1000
    inet6 2001:db8:0:1:200:ff:feaa:1/64 scope global dynamic 
       valid_lft 86400sec preferred_lft 14400sec
    inet6 fe80::200:ff:feaa:1/64 scope link 
       valid_lft forever preferred_lft forever
root@h1:~#

Checking the r1, we see that only the IPv6 link-local address is assigned, as expected. We need to manually assign IP addresses on routers.

root@r1:~# ip -6 addr show
1: lo:  mtu 65536 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
48: eth0:  mtu 1500 qlen 1000
    inet6 fe80::200:ff:feaa:0/64 scope link 
       valid_lft forever preferred_lft forever
54: eth1:  mtu 1500 qlen 1000
    inet6 fe80::200:ff:feaa:3/64 scope link 
       valid_lft forever preferred_lft forever
root@r1:~#

Router interface IP addresses

Stateless Address Auto-configuration will not assign an interface ID to the router’s interfaces — neither to the router’s own interfaces nor to interfaces on another router connected to the same IPv6 link. We need to assign IPv6 addresses on the router interfaces with the following commands:

root@h1:~# ip -6 addr add 2001:DB8:0:1::1/64 dev eth0 
root@h1:~# ip -6 addr add 2001:DB8:0:2::1/64 dev eth1 

We can verify the addresses are assigned using the ip -6 addr show command.

root@r1:~# ip -6 addr show
1: lo:  mtu 65536 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
48: eth0:  mtu 1500 qlen 1000
    inet6 2001:db8:0:1::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:feaa:0/64 scope link 
       valid_lft forever preferred_lft forever
54: eth1:  mtu 1500 qlen 1000
    inet6 2001:db8:0:2::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:feaa:3/64 scope link 
       valid_lft forever preferred_lft forever
root@r1:~# 

Network experiments

Now we can run some tests to see how stateless address auto-configuration and radvd works.

First, we will make a note of the IPv6 addresses assigned to each interface. Check the IPv6 addresses on each node with the ip -6 addr show command and write them down. In this case, the IPv6 addresses on each interface are listed in the table below:

Node name Interface MAC address IPv6 addresses
Router r1 eth0 00:00:00:aa:00:00 fe80::200:ff:feaa:0/64
2001:DB8:0:1::1/64
eth1 00:00:00:aa:00:03 fe80::200:ff:feaa:3/64
2001:DB8:0:2::1/64
Host h1 eth0 00:00:00:aa:00:01 fe80::200:ff:feaa:1/64
2001:DB8:0:1:200:ff:feaa:1/64
Host h2 eth0 00:00:00:aa:00:02 fe80::200:ff:feaa:2/64
2001:DB8:0:1:200:ff:feaa:2/64
Host h3 eth0 00:00:00:aa:00:04 fe80::200:ff:feaa:4/64
2001:DB8:0:2:200:ff:feaa:4/64
Host h4 eth0 00:00:00:aa:00:05 fe80::200:ff:feaa:5/64
2001:DB8:0:2:200:ff:feaa:5/64

Communication tests

Now, let’s verify that nodes can communicate with each other using the assigned IPv6 configurations. We can test this using the ping6 command.

For example, we ping from host h1 to host h4:

root@h1:~# ping6 2001:DB8:0:2:200:ff:feaa:5
PING 2001:DB8:0:2:200:ff:feaa:5(2001:db8:0:2:200:ff:feaa:5) 56 data bytes
64 bytes from 2001:db8:0:2:200:ff:feaa:5: icmp_seq=1 ttl=63 time=0.212 ms
64 bytes from 2001:db8:0:2:200:ff:feaa:5: icmp_seq=2 ttl=63 time=0.171 ms
64 bytes from 2001:db8:0:2:200:ff:feaa:5: icmp_seq=3 ttl=63 time=0.170 ms
64 bytes from 2001:db8:0:2:200:ff:feaa:5: icmp_seq=4 ttl=63 time=0.169 ms
^C
--- 2001:DB8:0:2:200:ff:feaa:5 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.169/0.180/0.212/0.022 ms
root@h1:~#

Inspect configuration information

Now, let’s have a look at the information on the hosts’ interfaces. Here we see the configurations that radvd makes on the host.

For example, a default address is automatically configured using information provided to the host about the router running radvd. We can see this by entering the command:

root@h1:~# ip -6 route show
2001:db8:0:1::/64 dev eth0  proto kernel  metric 256  expires 86205sec
fe80::/64 dev eth0  proto kernel  metric 256 
default via fe80::200:ff:feaa:0 dev eth0  proto ra  metric 1024  expires 1605sec
root@h1:~#  

Here we see the default route is via the address fe80::200:ff:feaa:0, which is the link-local address of router r1. We also see some other information about the route.

Next, we look at the IPv6 addresses configured on the hosts, such as h1:

root@h1:~# ip -6 addr show
1: lo:  mtu 65536 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
50: eth0:  mtu 1500 qlen 1000
    inet6 2001:db8:0:1:200:ff:feaa:1/64 scope global dynamic 
       valid_lft 85979sec preferred_lft 13979sec
    inet6 fe80::200:ff:feaa:1/64 scope link 
       valid_lft forever preferred_lft forever
root@h1:~#

Compare these address configurations to the static addresses configured on the router. We see that the automatically-configured addresses on the hosts have a expiration timers set (valid for 85,979 more seconds and preferred for 13,797 more seconds, in the example above) but the manually configured static IPv6 addresses have no expiration time set (they will remain valid “forever”):

root@r1:~# ip -6 addr show
1: lo:  mtu 65536 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
48: eth0:  mtu 1500 qlen 1000
    inet6 2001:db8:0:1::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:feaa:0/64 scope link 
       valid_lft forever preferred_lft forever
54: eth1:  mtu 1500 qlen 1000
    inet6 2001:db8:0:2::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:feaa:3/64 scope link 
       valid_lft forever preferred_lft forever
root@r1:~# 

Stop the radvd service on the router r1 (use the CORE contextual menu command). We should see that the timers of the automatically-configure IPv6 addresses on the hosts now keep counting down to zero (if we wanted to wait that long), because they no longer periodically receive Router Advertisement messages with new timer information.

Inspect the auto-configuration protocol messages

Start Wireshark on router r1 interface eth0.

Start the radvd service again.

Look at the Router Advertisement messages sent from the router to the hosts. You can see the default parameters used by radvd in each message.

Wireshark capture of Router r1 interface
Wireshark capture of Router r1 interface

As a last test, add new prefixes to the radvd.conf file. Restart the radvd service. Look at the Wireshark capture to see the new messages. Also, check the IPv6 address configuration on the hosts to see the new addresses added to each host’s interface eth0.

Configuring a real Linux router

For reference, I will describe below how to configure radvd on a real Linux router, where we are using a normal filesystem. Previously, we showed some modified procedure when working with a simulated router but we should also know the actual procedures we would use on a real router.

We will cover only the configurations that would configure a router the same way we configured our simulated router, above. We omit other real-world configuration scenarios, for now.

On a Linux router, we create the radvd configuration file and then start the radvd daemon using the service initialization scripts. Then we permanently configure the router’s interface addresses by updating the interfaces configuration file.

The radvd.conf configuration file

On a real Linux router we would first we create the radvd.conf configuration file. Check your documentation to see where the configuration file is located ((In the popular OpenWRT router, the radvd configuration is documented at http://wiki.openwrt.org/doc/uci/radvd.)). In an Ubuntu filesystem, radvd expects the configuration file is /etc/radvd.conf.

$ sudo vi /etc/radvd.conf

We would configure the prefixes we have chosen to use on each link. For example:

interface eth0
{
        AdvSendAdvert on;
        prefix 2001:db8:0:1::/64 { };
};
interface eth1
{
        AdvSendAdvert on;
        prefix 2001:db8:0:2::/64 { };
};

Next, we would ensure that the file permissions are correct. Radvd will not start unless the configuration file has secure permissions so that no other users can write to the file.

& sudo chmod 644 /etc/radvd.conf
$ ls -l /etc/radvd.conf
-rw-r--r-- 1 root root 642 Apr 26 22:57 /etc/radvd.conf

Start radvd

Now, we would start the radvd service.

$ sudo service radvd start

Then, we would permanently configure radvd to start when the system starts or reboots:

$ sudo update-rc.d radvd defaults
$ sudo update-rc.d radvd enable

Router interface IP addresses

We would assign the router’s interface IPv6 addresses. On a normal router, we would permanently configure these interfaces by adding information to the file /etc/network/interfaces. For example:

$ sudo vi /etc/network/interfaces

Then add interface configurations, such as:

iface eth0 inet6 static
address 2001:db8:0:1::1
netmask 64
iface eth1 inet6 static
address 2001:db8:0:2::1
netmask 64

Then we would restart the networking service. NOTE: we assume the Linux router is based on a minimal system and that there is no other software managing networking, such as the Ubuntu Network Manager.

$ sudo service networking restart

Or,

$ sudo /etc/init.d/networking restart

Conclusion

We practised configuring IPv6 stateless address auto-configuration (SLAAC) on a router running the radvd daemon. We learned how to configure stateless address auto-configuration on a Linux router and observed the operation of the radvd daemon. We used Wireshark to view the Router Advertisements generated by the protocol.

we also learned more about using the CORE Network Emulator. The developers of the CORE Network Emulator chose to implement a very lightweight virtualization method to maximize performance while using minimal system resources. This requires us to be aware of the practical impacts of modifying configuration files on simulated nodes. We learned more about how to work with virtual nodes in CORE and tried some procedures that support learning fundamental router configuration skills, while allowing for the way CORE implements isolation of some configuration files on the simulated nodes.

Finally, we reviewed the actual procedures one would use on a real Linux router and we saw that these procedures were similar enough to the procedures we used in the network simulation to allow us to use the simulator as a tool for demonstrating and practising configuration procedures.

 

Notes

4 thoughts on “Testing IPv6 addressing in a network simulator – Part 2”

  1. Hi,

    I cannot live capture using Wireshark as I get the error message,

    “The capture session could not be initiated (You don’t have permission to capture on that device).

    Please check to make sure you have sufficient permissions, and that you have the proper interface or pipe specified.”

    Please not that I already used the command,

    $ sudo setcap ‘CAP_NET_RAW+eip CAP_NET_ADMIN+eip’ /usr/bin/dumpcap

    and I’m using CORE 4.7 in linux mint 17. However, I can use Tshark with no issues.

    I’m be grateful if you could use your expertise and help me to fix this issue.

    Many thanks.

      1. I tried CORE 4.7 on Xubuntu 14.04 and I saw that same problem. I need to investigate some more. This will take a few days. I suspect this is a defect in CORE 4.7. I recommend you use CORE 4.6, for now.

        1. Hi Chamitha,
          This issue appears to be a bug in CORE 4.7. The developers changed the way CORE creates names for the virtual ethernet interfaces used to make links between network namespaces. But, the function that starts Wireshark and assigned the capture interface is still using the old interface naming convention, which is why it cannot find the interface. Clear the error dialogue box and then pick the virtual interface you wish to capture in Wireshark. The new naming convention is “Veth” followed by the node number (node “n3” would be veth3), followed by the ethernet interface number. Example: eth0 on node “n3” has the interface name “veth3.0”.
          –Brian

Comments are closed.

Scroll to Top