mininet / mininet / nodelib.py @ ab8c4e91
History | View | Annotate | Download (5.09 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 |
|
11 |
import re |
12 |
|
13 |
class LinuxBridge( Switch ): |
14 |
"Linux Bridge (with optional spanning tree)"
|
15 |
|
16 |
nextPrio = 100 # next bridge priority for spanning tree |
17 |
|
18 |
def __init__( self, name, stp=False, prio=None, **kwargs ): |
19 |
"""stp: use spanning tree protocol? (default False)
|
20 |
prio: optional explicit bridge priority for STP"""
|
21 |
self.stp = stp
|
22 |
if prio:
|
23 |
self.prio = prio
|
24 |
else:
|
25 |
self.prio = LinuxBridge.nextPrio
|
26 |
LinuxBridge.nextPrio += 1
|
27 |
Switch.__init__( self, name, **kwargs )
|
28 |
|
29 |
def connected( self ): |
30 |
"Are we forwarding yet?"
|
31 |
if self.stp: |
32 |
return 'forwarding' in self.cmd( 'brctl showstp', self ) |
33 |
else:
|
34 |
return True |
35 |
|
36 |
def start( self, _controllers ): |
37 |
"Start Linux bridge"
|
38 |
self.cmd( 'ifconfig', self, 'down' ) |
39 |
self.cmd( 'brctl delbr', self ) |
40 |
self.cmd( 'brctl addbr', self ) |
41 |
if self.stp: |
42 |
self.cmd( 'brctl setbridgeprio', self.prio ) |
43 |
self.cmd( 'brctl stp', self, 'on' ) |
44 |
for i in self.intfList(): |
45 |
if self.name in i.name: |
46 |
self.cmd( 'brctl addif', self, i ) |
47 |
self.cmd( 'ifconfig', self, 'up' ) |
48 |
|
49 |
def stop( self, deleteIntfs=True ): |
50 |
"""Stop Linux bridge
|
51 |
deleteIntfs: delete interfaces? (True)"""
|
52 |
self.cmd( 'ifconfig', self, 'down' ) |
53 |
self.cmd( 'brctl delbr', self ) |
54 |
super( LinuxBridge, self ).stop( deleteIntfs ) |
55 |
|
56 |
def dpctl( self, *args ): |
57 |
"Run brctl command"
|
58 |
return self.cmd( 'brctl', *args ) |
59 |
|
60 |
@classmethod
|
61 |
def setup( cls ): |
62 |
"Make sure our class dependencies are available"
|
63 |
pathCheck( 'brctl', moduleName='bridge-utils' ) |
64 |
|
65 |
|
66 |
class NAT( Node ): |
67 |
"NAT: Provides connectivity to external network"
|
68 |
|
69 |
def __init__( self, name, inetIntf=None, subnet='10.0/8', |
70 |
localIntf=None, **params):
|
71 |
"""Start NAT/forwarding between Mininet and external network
|
72 |
inetIntf: interface for internet access
|
73 |
subnet: Mininet subnet (default 10.0/8)="""
|
74 |
super( NAT, self ).__init__( name, **params ) |
75 |
|
76 |
self.inetIntf = inetIntf if inetIntf else self.getGatewayIntf() |
77 |
self.subnet = subnet
|
78 |
self.localIntf = localIntf
|
79 |
|
80 |
def config( self, **params ): |
81 |
"""Configure the NAT and iptables"""
|
82 |
super( NAT, self).config( **params ) |
83 |
|
84 |
if not self.localIntf: |
85 |
self.localIntf = self.defaultIntf() |
86 |
|
87 |
self.cmd( 'sysctl net.ipv4.ip_forward=0' ) |
88 |
|
89 |
# Flush any currently active rules
|
90 |
# TODO: is this safe?
|
91 |
self.cmd( 'iptables -F' ) |
92 |
self.cmd( 'iptables -t nat -F' ) |
93 |
|
94 |
# Create default entries for unmatched traffic
|
95 |
self.cmd( 'iptables -P INPUT ACCEPT' ) |
96 |
self.cmd( 'iptables -P OUTPUT ACCEPT' ) |
97 |
self.cmd( 'iptables -P FORWARD DROP' ) |
98 |
|
99 |
# Configure NAT
|
100 |
self.cmd( 'iptables -I FORWARD', |
101 |
'-i', self.localIntf, '-d', self.subnet, '-j DROP' ) |
102 |
self.cmd( 'iptables -A FORWARD', |
103 |
'-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' ) |
104 |
self.cmd( 'iptables -A FORWARD', |
105 |
'-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' ) |
106 |
self.cmd( 'iptables -t nat -A POSTROUTING', |
107 |
'-o', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' ) |
108 |
|
109 |
# Instruct the kernel to perform forwarding
|
110 |
self.cmd( 'sysctl net.ipv4.ip_forward=1' ) |
111 |
|
112 |
# Prevent network-manager from messing with our interface
|
113 |
# by specifying manual configuration in /etc/network/interfaces
|
114 |
intf = self.localIntf
|
115 |
cfile = '/etc/network/interfaces'
|
116 |
line = '\niface %s inet manual\n' % intf
|
117 |
config = open( cfile ).read()
|
118 |
if ( line ) not in config: |
119 |
info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' ) |
120 |
with open( cfile, 'a' ) as f: |
121 |
f.write( line ) |
122 |
# Probably need to restart network-manager to be safe -
|
123 |
# hopefully this won't disconnect you
|
124 |
self.cmd( 'service network-manager restart' ) |
125 |
|
126 |
def getGatewayIntf( self, fallback='eth0' ): |
127 |
"""Return gateway interface name
|
128 |
fallback: default device to fall back to"""
|
129 |
routes = self.cmd( 'ip route show' ) |
130 |
match = re.search( r'default via \S+ dev (\S+)', routes )
|
131 |
if match:
|
132 |
return match.group( 1 ) |
133 |
else:
|
134 |
warn( 'There is no default route set.',
|
135 |
'Using', fallback, 'as gateway interface...\n' ) |
136 |
return fallback
|
137 |
|
138 |
def terminate( self ): |
139 |
"""Stop NAT/forwarding between Mininet and external network"""
|
140 |
# Flush any currently active rules
|
141 |
# TODO: is this safe?
|
142 |
self.cmd( 'iptables -F' ) |
143 |
self.cmd( 'iptables -t nat -F' ) |
144 |
|
145 |
# Instruct the kernel to stop forwarding
|
146 |
self.cmd( 'sysctl net.ipv4.ip_forward=0' ) |
147 |
|
148 |
super( NAT, self ).terminate() |