Statistics
| Branch: | Tag: | Revision:

mininet / mininet / nodelib.py @ 5f68be22

History | View | Annotate | Download (5.86 KB)

1
"""
2
Node Library for Mininet
3

4
This contains additional Node types which you may find to be useful.
5
"""
6

    
7
from mininet.node import Node, Switch
8
from mininet.log import info, warn
9
from mininet.moduledeps import pathCheck
10
from mininet.util import quietRun
11

    
12
import re
13

    
14
class LinuxBridge( Switch ):
15
    "Linux Bridge (with optional spanning tree)"
16

    
17
    nextPrio = 100  # next bridge priority for spanning tree
18

    
19
    def __init__( self, name, stp=False, prio=None, **kwargs ):
20
        """stp: use spanning tree protocol? (default False)
21
           prio: optional explicit bridge priority for STP"""
22
        self.stp = stp
23
        if prio:
24
            self.prio = prio
25
        else:
26
            self.prio = LinuxBridge.nextPrio
27
            LinuxBridge.nextPrio += 1
28
        Switch.__init__( self, name, **kwargs )
29

    
30
    def connected( self ):
31
        "Are we forwarding yet?"
32
        if self.stp:
33
            return 'forwarding' in self.cmd( 'brctl showstp', self )
34
        else:
35
            return True
36

    
37
    def start( self, _controllers ):
38
        "Start Linux bridge"
39
        self.cmd( 'ifconfig', self, 'down' )
40
        self.cmd( 'brctl delbr', self )
41
        self.cmd( 'brctl addbr', self )
42
        if self.stp:
43
            self.cmd( 'brctl setbridgeprio', self.prio )
44
            self.cmd( 'brctl stp', self, 'on' )
45
        for i in self.intfList():
46
            if self.name in i.name:
47
                self.cmd( 'brctl addif', self, i )
48
        self.cmd( 'ifconfig', self, 'up' )
49

    
50
    def stop( self, deleteIntfs=True ):
51
        """Stop Linux bridge
52
           deleteIntfs: delete interfaces? (True)"""
53
        self.cmd( 'ifconfig', self, 'down' )
54
        self.cmd( 'brctl delbr', self )
55
        super( LinuxBridge, self ).stop( deleteIntfs )
56

    
57
    def dpctl( self, *args ):
58
        "Run brctl command"
59
        return self.cmd( 'brctl', *args )
60

    
61
    @classmethod
62
    def setup( cls ):
63
        "Check dependencies and warn about firewalling"
64
        pathCheck( 'brctl', moduleName='bridge-utils' )
65
        # Disable Linux bridge firewalling so that traffic can flow!
66
        for table in 'arp', 'ip', 'ip6':
67
            cmd = 'sysctl net.bridge.bridge-nf-call-%stables' % table
68
            out = quietRun( cmd ).strip()
69
            if out.endswith( '1' ):
70
                warn( 'Warning: Linux bridge may not work with', out, '\n' )
71

    
72

    
73
class NAT( Node ):
74
    "NAT: Provides connectivity to external network"
75

    
76
    def __init__( self, name, inetIntf=None, subnet='10.0/8',
77
                  localIntf=None, flush=False, **params):
78
        """Start NAT/forwarding between Mininet and external network
79
           inetIntf: interface for internet access
80
           subnet: Mininet subnet (default 10.0/8)
81
           flush: flush iptables before installing NAT rules"""
82
        super( NAT, self ).__init__( name, **params )
83

    
84
        self.inetIntf = inetIntf if inetIntf else self.getGatewayIntf()
85
        self.subnet = subnet
86
        self.localIntf = localIntf
87
        self.flush = flush
88

    
89
    def config( self, **params ):
90
        """Configure the NAT and iptables"""
91
        super( NAT, self).config( **params )
92

    
93
        if not self.localIntf:
94
            self.localIntf = self.defaultIntf()
95

    
96
        self.cmd( 'sysctl net.ipv4.ip_forward=0' )
97

    
98
        if self.flush:
99
            self.cmd( 'iptables -F' )
100
            self.cmd( 'iptables -t nat -F' )
101
            # Create default entries for unmatched traffic
102
            self.cmd( 'iptables -P INPUT ACCEPT' )
103
            self.cmd( 'iptables -P OUTPUT ACCEPT' )
104
            self.cmd( 'iptables -P FORWARD DROP' )
105

    
106
        # Install NAT rules
107
        self.cmd( 'iptables -I FORWARD',
108
                  '-i', self.localIntf, '-d', self.subnet, '-j DROP' )
109
        self.cmd( 'iptables -A FORWARD',
110
                  '-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
111
        self.cmd( 'iptables -A FORWARD',
112
                  '-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' )
113
        self.cmd( 'iptables -t nat -A POSTROUTING',
114
                  '-o', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' )
115

    
116
        # Instruct the kernel to perform forwarding
117
        self.cmd( 'sysctl net.ipv4.ip_forward=1' )
118

    
119
        # Prevent network-manager from messing with our interface
120
        # by specifying manual configuration in /etc/network/interfaces
121
        intf = self.localIntf
122
        cfile = '/etc/network/interfaces'
123
        line = '\niface %s inet manual\n' % intf
124
        config = open( cfile ).read()
125
        if ( line ) not in config:
126
            info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' )
127
            with open( cfile, 'a' ) as f:
128
                f.write( line )
129
        # Probably need to restart network-manager to be safe -
130
        # hopefully this won't disconnect you
131
        self.cmd( 'service network-manager restart' )
132

    
133
    def getGatewayIntf( self, fallback='eth0' ):
134
        """Return gateway interface name
135
           fallback: default device to fall back to"""
136
        routes = self.cmd( 'ip route show' )
137
        match = re.search( r'default via \S+ dev (\S+)', routes )
138
        if match:
139
            return match.group( 1 )
140
        else:
141
            warn( 'There is no default route set.',
142
                  'Using', fallback, 'as gateway interface...\n' )
143
            return fallback
144

    
145
    def terminate( self ):
146
        "Stop NAT/forwarding between Mininet and external network"
147
        # Remote NAT rules
148
        self.cmd( 'iptables -D FORWARD',
149
                   '-i', self.localIntf, '-d', self.subnet, '-j DROP' )
150
        self.cmd( 'iptables -D FORWARD',
151
                  '-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
152
        self.cmd( 'iptables -D FORWARD',
153
                   '-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' )
154
        self.cmd( 'iptables -t nat -D POSTROUTING',
155
                   '-o', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' )
156
        # Instruct the kernel to stop forwarding
157
        self.cmd( 'sysctl net.ipv4.ip_forward=0' )
158
        super( NAT, self ).terminate()