From af1ccf93a5e4dd38a05ca4213d8184ef2cb39d1a Mon Sep 17 00:00:00 2001 From: Brian O'Connor <bocon@onlab.us> Date: Mon, 24 Nov 2014 18:00:38 -0800 Subject: [PATCH] Updating NAT class to use gateway interface Also, passing CLI args to NAT constructor fixes #437 --- bin/mn | 24 +++++++++++++++++++----- mininet/nodelib.py | 20 +++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/bin/mn b/bin/mn index 1933098b..b2bb0060 100755 --- a/bin/mn +++ b/bin/mn @@ -32,7 +32,7 @@ from mininet.nodelib import LinuxBridge from mininet.link import Link, TCLink from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo from mininet.topolib import TreeTopo, TorusTopo -from mininet.util import customConstructor +from mininet.util import customConstructor, splitArgs from mininet.util import buildTopo from functools import partial @@ -168,6 +168,17 @@ class MininetRunner( object ): # Add or modify global variable or class globals()[ name ] = value + def setNat( self, option, opt_str, value, parser ): + parser.values.nat = True + if parser.rargs and parser.rargs[ 0 ][ 0 ] != '-': #first arg, first char != '-' + value = parser.rargs.pop( 0 ) + _, args, kwargs = splitArgs( opt_str + ',' + value ) + parser.values.nat_args = args + parser.values.nat_kwargs = kwargs + else: + parser.values.nat_args = [] + parser.values.nat_kwargs = {} + def parseArgs( self ): """Parse command-line args and return options object. returns: opts parse options dict""" @@ -219,9 +230,12 @@ class MininetRunner( object ): opts.add_option( '--pin', action='store_true', default=False, help="pin hosts to CPU cores " "(requires --host cfs or --host rt)" ) - opts.add_option( '--nat', action='store_true', - default=False, help="adds a NAT to the topology " - "that connects Mininet to the physical network" ) + opts.add_option( '--nat', action='callback', callback=self.setNat, + help="adds a NAT to the topology that connects Mininet hosts" + " to the physical network." + " Warning: This may route any traffic on the machine that uses Mininet's" + " IP subnet into the Mininet network. If you need to change" + " Mininet's IP subnet, see the --ipbase option." ) opts.add_option( '--version', action='callback', callback=version, help='prints the version and exits' ) opts.add_option( '--cluster', type='string', default=None, @@ -319,7 +333,7 @@ class MininetRunner( object ): listenPort=listenPort ) if self.options.nat: - nat = mn.addNAT() + nat = mn.addNAT( *self.options.nat_args, **self.options.nat_kwargs ) nat.configDefault() if self.options.pre: diff --git a/mininet/nodelib.py b/mininet/nodelib.py index 54ec1936..f89e20ab 100644 --- a/mininet/nodelib.py +++ b/mininet/nodelib.py @@ -5,9 +5,10 @@ """ from mininet.node import Node, Switch -from mininet.log import info +from mininet.log import info, warn from mininet.moduledeps import pathCheck +import re class LinuxBridge( Switch ): "Linux Bridge (with optional spanning tree)" @@ -63,13 +64,13 @@ def setup( cls ): class NAT( Node ): """NAT: Provides connectivity to external network""" - def __init__( self, name, inetIntf='eth0', subnet='10.0/8', localIntf=None, **params): + def __init__( self, name, inetIntf=None, subnet='10.0/8', localIntf=None, **params): super( NAT, self ).__init__( name, **params ) """Start NAT/forwarding between Mininet and external network inetIntf: interface for internet access subnet: Mininet subnet (default 10.0/8)=""" - self.inetIntf = inetIntf + self.inetIntf = inetIntf if inetIntf else self.getGatewayIntf() self.subnet = subnet self.localIntf = localIntf @@ -96,7 +97,7 @@ def config( self, **params ): self.cmd( 'iptables -I FORWARD -i', self.localIntf, '-d', self.subnet, '-j DROP' ) self.cmd( 'iptables -A FORWARD -i', self.localIntf, '-s', self.subnet, '-j ACCEPT' ) self.cmd( 'iptables -A FORWARD -i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' ) - self.cmd( 'iptables -t nat -A POSTROUTING -o ', self.inetIntf, '-j MASQUERADE' ) + self.cmd( 'iptables -t nat -A POSTROUTING -o ', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' ) # Instruct the kernel to perform forwarding self.cmd( 'sysctl net.ipv4.ip_forward=1' ) @@ -108,13 +109,22 @@ def config( self, **params ): line = '\niface %s inet manual\n' % intf config = open( cfile ).read() if ( line ) not in config: - info( '*** Adding "' + line.strip() + '" to ' + cfile ) + info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' ) with open( cfile, 'a' ) as f: f.write( line ) # Probably need to restart network-manager to be safe - # hopefully this won't disconnect you self.cmd( 'service network-manager restart' ) + def getGatewayIntf( self ): + routes = self.cmd( 'ip route show' ) + match = re.search('default via \S+ dev (\S+)', routes ) + if match: + return match.group( 1 ) + else: + warn( 'There is no default route set. Using eth0 as gateway interface...\n' ) + return 'eth0' + def terminate( self ): """Stop NAT/forwarding between Mininet and external network""" # Flush any currently active rules -- GitLab