(mininet) Configure multiple interfaces on a host

8.2k views Asked by At

I have a scenario in which there is a server machine with two interfaces. Each of these interfaces has its own IP address. The server machine hosts an HTTP server, which should be accessible via both of the interfaces.

Full python script to reproduce this situation:

from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.topo import Topo

class TestTopology(Topo):
    def __init__(self):
        Topo.__init__(self)
        host1_id = self.addHost('h1')
        host2_id = self.addHost('h2')
        server_id = self.addHost('server')
        self.addLink(server_id, host1_id)
        self.addLink(server_id, host2_id)

def configure_network(network):
    server = network.get('server')
    server.setIP('10.0.0.10', intf='server-eth0')
    server.setMAC('00:00:00:00:00:10', intf='server-eth0')
    server.setIP('10.0.0.11', intf='server-eth1')
    server.setMAC('00:00:00:00:00:11', intf='server-eth1')
    server.cmd("python -m SimpleHTTPServer 8080 &")

# Run 'sudo python *path_to_this_script*' in mininet VM.
if __name__ == '__main__':
    setLogLevel('info')
    net = Mininet(topo=TestTopology())
    configure_network(net)
    net.pingAll()
    CLI(net)

The SimpleHTTPServer is listening on 0.0.0.0 as default.

The 'pingAll' test shows that the server is accessible by h1 (and vice versa), but it's not the case for h2. Of course, I can't wget from h2 either.

How to configure the server interfaces so that the server responds both to ping and wget commands via both of these interfaces?

/etc/network/interfaces on the server contains some configuration, but it is regarding a non-existent eth0 interface, so I assumed it is not used.

NOTE: I've already learned that for linux, a particular IP != network interface. The server responds for pings to both 10.0.0.10 and 10.0.0.11 from h1, but I would like for it to respond on both physical interfaces.

3

There are 3 answers

0
Alex Ferreira On

I see that you configured the IP address for the both interfaces correctly, but there's no ethernet link connecting the second interface on other hosts, that's why there's no connectivity on that interface. In order to configure it properly, you must:

  1. Create two intf objects and assign their specific IP addresses (10.0.0.10 and 10.0.0.11)
  2. Connect these two interfaces on a switch
  3. Attach both interfaces on the server host
  4. Set up other hosts and/or switches of your topology

I hope it helps to solve the problem...

0
Nicolas On

I'm super late to the party but this question popped up when looking up how to add multiple IPs to a host in mininet, so answering in case this helps someone else.

You're adding two IPs from the same subnet on two different interfaces. You didn't specify the prefix length/netmask so mininet assumes /8 for 10.0.0.x. You can see this when checking out the host config:

mininet> server ip a | grep 10.0.0
    inet 10.0.0.10/8 brd 10.255.255.255 scope global server-eth0
    inet 10.0.0.11/8 brd 10.255.255.255 scope global server-eth1

When you send a ping from h2 to server, it arrives on server-eth1 with a src ip of 10.0.0.2. To send the reply, server looks it up in its routing table:

mininet> server ip route
10.0.0.0/8 dev server-eth0 proto kernel scope link src 10.0.0.10
10.0.0.0/8 dev server-eth1 proto kernel scope link src 10.0.0.11

Because the two interfaces are on the same subnet, you see you have two routes for the same prefix. 10.0.0.2 will match either, but the first one on the list is selected since they are equivalent. It tells Linux to send the answer to the ping on "server-eth0". But 10.0.0.2 is not on that interface... (it's on server-eth1).

You have a few options:

  1. Add a switch and connect server, h1 and h2 to it. Here you'd only need one interface on server, but an extra switch.
  2. Create a bridge on server so that eth0 and eth1 are seen as the same interface (this is similar to connecting h1, h2 and server to the same switch, but without extra hardware). Then you'd either have only one IP on server, or two IPs if you want two, but either way they'd be on the bridged interface.
  3. Segment the network into two separate subnets. Something like 10.0.10.0/24 for h1 and server ; and 10.0.11.0/24 for h2 and server.

The 3rd option probably makes the most sense, but if you want h1 and h2 to be able to talk to each other you'll have to look into routing. For a super simple setup, you could set the default route of h1 and h2 to be via server.

The first option (switch) would look like this:

self.addSwitch('s1')
self.addLink('s1', 'server')
self.addLink('s1', 'h1')
self.addLink('s1', 'h2')

The second one (bridge) like that (all on the server):

ip addr del 10.0.0.10/8 dev server-eth0
ip addr del 10.0.0.11/8 dev server-eth1
brctl addbr br0
brctl addif br0 server-eth0
brctl addif br0 server-eth1
ip link set dev br0 up
ip addr add 10.0.0.10/8 dev br0
ip addr add 10.0.0.11/8 dev br0 # You don't need two IPs

And finally the third (routing) like that - this is almost the same as you original code, just note the additional IPs and prefix lengths (/24)

from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.topo import Topo

class TestTopology(Topo):
    def __init__(self):
        Topo.__init__(self)
        host1_id = self.addHost('h1', ip='10.0.10.2/24')
        host2_id = self.addHost('h2', ip='10.0.11.2/24')
        server_id = self.addHost('server')
        self.addLink(server_id, host1_id)
        self.addLink(server_id, host2_id)

def configure_network(network):
    server = network.get('server')
    server.setIP('10.0.10.1/24', intf='server-eth0')
    server.setMAC('00:00:00:00:00:10', intf='server-eth0')
    server.setIP('10.0.11.1/24', intf='server-eth1')
    server.setMAC('00:00:00:00:00:11', intf='server-eth1')
    server.cmd("python2 -m SimpleHTTPServer 8080 &")

# Run 'sudo python *path_to_this_script*' in mininet VM.
if __name__ == '__main__':
    setLogLevel('info')
    net = Mininet(topo=TestTopology())
    configure_network(net)
    # net.pingAll()
    CLI(net)

Then you can ping or wget using the correct IP:

h1 wget -O - 10.0.10.1:8080
h2 wget -O - 10.0.11.1:8080
1
Nilesh Chaturvedi On

You can try importing custom from mininet.util

In my case, reordering the code worked.

Here is my code:

#!/usr/bin/python

from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import OVSKernelSwitch, UserSwitch
from mininet.node import IVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import TCLink, Intf, Link
from mininet.util import makeNumeric, custom
from subprocess import call

def myNetwork():
    link = custom(TCLink, bw=10)
    net = Mininet( topo=None,
                   build=False,
                   ipBase='10.0.0.0/8')

    info( '*** Adding controller\n' )
    info( '*** Add switches\n')



    s5 = net.addSwitch('s5', cls=OVSKernelSwitch, failMode='standalone')
    s2 = net.addSwitch('s2', cls=OVSKernelSwitch, failMode='standalone')
    s7 = net.addSwitch('s7', cls=OVSKernelSwitch, failMode='standalone')
    s4 = net.addSwitch('s4', cls=OVSKernelSwitch, failMode='standalone')

    r8 = net.addHost('r8', cls=Node, ip='0.0.0.0')
    r8.cmd('sysctl -w net.ipv4.ip_forward=1')
    r9 = net.addHost('r9', cls=Node, ip='0.0.0.0')
    r9.cmd('sysctl -w net.ipv4.ip_forward=1')
    r10 = net.addHost('r10', cls=Node, ip='0.0.0.0')
    r10.cmd('sysctl -w net.ipv4.ip_forward=1')

    info( '*** Add hosts\n')
    h1 = net.addHost('h1', cls=Host, ip='192.168.2.1', defaultRoute=None)
    h2 = net.addHost('h2', cls=Host, ip='192.168.3.1', defaultRoute=None)

    info( '*** Add links\n')
    net.addLink(s2, r9)
    net.addLink(s4, r10)
    net.addLink(r9, s5)
    net.addLink(s7, r8)
    net.addLink(r8, h2)
    net.addLink(s5, h2)
    net.addLink(s2, h1)
    net.addLink(s4, h1)
    net.addLink(r10, s7)

    info( '*** Starting network\n')
    net.build()
    info( '*** Starting controllers\n')
    for controller in net.controllers:
        controller.start()

    info( '*** Starting switches\n')
    net.get('s5').start([])
    net.get('s2').start([])
    net.get('s7').start([])
    net.get('s4').start([])

    info( '*** Post configure switches and hosts\n')

    CLI(net)
    net.stop()

if __name__ == '__main__':
    setLogLevel( 'info' )
    myNetwork()