diff --git a/examples/README b/examples/README index 80b46d425779ca9c85519ad9c15586355f0bdf82..e4ca892e8dead9e567c9d9725115c0d15c5d0fed 100644 --- a/examples/README +++ b/examples/README @@ -68,6 +68,12 @@ multitest.py: This example creates a network and runs multiple tests on it. +nat.py: + +This example shows how to connect a Mininet network to the Internet +using NAT. It also answers the eternal question "why can't I ping +google?" + popen.py: This example monitors a number of hosts using host.popen() and diff --git a/examples/nat.py b/examples/nat.py new file mode 100755 index 0000000000000000000000000000000000000000..292d2a32fa37f24980a58746386d33ba2faf95a1 --- /dev/null +++ b/examples/nat.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +""" +Example to create a Mininet topology and connect it to the internet via NAT +through eth0 on the host. + +Glen Gibb, February 2011 + +(slight modifications by BL, 5/13) +""" + +from mininet.cli import CLI +from mininet.log import lg, info +from mininet.node import Node +from mininet.topolib import TreeNet +from mininet.util import quietRun + +################################# +def startNAT( root, inetIntf='eth0', subnet='10.0/8' ): + """Start NAT/forwarding between Mininet and external network + root: node to access iptables from + inetIntf: interface for internet access + subnet: Mininet subnet (default 10.0/8)=""" + + # Identify the interface connecting to the mininet network + localIntf = root.defaultIntf() + + # Flush any currently active rules + root.cmd( 'iptables -F' ) + root.cmd( 'iptables -t nat -F' ) + + # Create default entries for unmatched traffic + root.cmd( 'iptables -P INPUT ACCEPT' ) + root.cmd( 'iptables -P OUTPUT ACCEPT' ) + root.cmd( 'iptables -P FORWARD DROP' ) + + # Configure NAT + root.cmd( 'iptables -I FORWARD -i', localIntf, '-d', subnet, '-j DROP' ) + root.cmd( 'iptables -A FORWARD -i', localIntf, '-s', subnet, '-j ACCEPT' ) + root.cmd( 'iptables -A FORWARD -i', inetIntf, '-d', subnet, '-j ACCEPT' ) + root.cmd( 'iptables -t nat -A POSTROUTING -o ', inetIntf, '-j MASQUERADE' ) + + # Instruct the kernel to perform forwarding + root.cmd( 'sysctl net.ipv4.ip_forward=1' ) + +def stopNAT( root ): + """Stop NAT/forwarding between Mininet and external network""" + # Flush any currently active rules + root.cmd( 'iptables -F' ) + root.cmd( 'iptables -t nat -F' ) + + # Instruct the kernel to stop forwarding + root.cmd( 'sysctl net.ipv4.ip_forward=0' ) + +def fixNetworkManager( root, intf ): + """Prevent network-manager from messing with our interface, + by specifying manual configuration in /etc/network/interfaces + root: a node in the root namespace (for running commands) + intf: interface name""" + cfile = '/etc/network/interfaces' + line = '\niface %s inet manual\n' % intf + config = open( cfile ).read() + if ( line ) not in config: + print '*** Adding', line.strip(), 'to', cfile + with open( cfile, 'a' ) as f: + f.write( line ) + # Probably need to restart network-manager to be safe - + # hopefully this won't disconnect you + root.cmd( 'service network-manager restart' ) + +def connectToInternet( network, switch='s1', rootip='10.254', subnet='10.0/8'): + """Connect the network to the internet + switch: switch to connect to root namespace + rootip: address for interface in root namespace + subnet: Mininet subnet""" + switch = network.get( switch ) + prefixLen = subnet.split( '/' )[ 1 ] + routes = [ subnet ] # host networks to route to + + # Create a node in root namespace + root = Node( 'root', inNamespace=False ) + + # Prevent network-manager from interfering with our interface + fixNetworkManager( root, 'root-eth0' ) + + # Create link between root NS and switch + link = network.addLink( root, switch ) + link.intf1.setIP( rootip, prefixLen ) + + # Start network that now includes link to root namespace + network.start() + + # Start NAT and establish forwarding + startNAT( root ) + + # Establish routes from end hosts + for host in network.hosts: + host.cmd( 'ip route flush root 0/0' ) + host.cmd( 'route add -net', subnet, 'dev', host.defaultIntf() ) + host.cmd( 'route add default gw', rootip ) + + return root + +if __name__ == '__main__': + lg.setLogLevel( 'info') + net = TreeNet( depth=1, fanout=4 ) + # Configure and start NATted connectivity + rootnode = connectToInternet( net ) + print "*** Hosts are running and should have internet connectivity" + print "*** Type 'exit' or control-D to shut down network" + CLI( net ) + # Shut down NAT + stopNAT( rootnode ) + net.stop()