3 """ Private Bridge configurator. """
13 from threading import Thread
19 class OvsException (Exception) :
20 def __init__ (self, message="no message"):
22 def __repr__ (self): return message
25 logger.log('private bridge plugin starting up...')
27 def log_call_read(command,timeout=logger.default_timeout_minutes*60,poll=1):
28 message=" ".join(command)
29 logger.log("log_call: running command %s" % message)
30 logger.verbose("log_call: timeout=%r s" % timeout)
31 logger.verbose("log_call: poll=%r s" % poll)
32 trigger=time.time()+timeout
34 child = subprocess.Popen(command, bufsize=1,
35 stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
39 # see if anything can be read within the poll interval
40 (r,w,x)=select.select([child.stdout],[],[],poll)
41 if r: stdout = stdout + child.stdout.read(1)
43 returncode=child.poll()
45 if returncode != None:
46 stdout = stdout + child.stdout.read()
47 # child is done and return 0
49 logger.log("log_call:end command (%s) completed" % message)
51 logger.log("log_call:stdout: %s" % stdout)
52 return (returncode, stdout)
55 log("log_call:end command (%s) returned with code %d" %(message,returncode))
56 return (returncode, stdout)
57 # no : still within timeout ?
58 if time.time() >= trigger:
60 logger.log("log_call:end terminating command (%s) - exceeded timeout %d s"%(message,timeout))
63 except Exception as e:
64 logger.log_exc("failed to run command %s -> %s" % (message,e))
68 ### Thierry - 23 Sept 2014
69 # regardless of this being shipped on lxc-only or on all nodes,
70 # it is safer to check for the availability of the ovs-vsctl command and just print
71 # out a warning when it's not there, instead of a nasty traceback
73 "return True if ovs-vsctl can be run"
75 child = subprocess.Popen (['ovs-ovsctl', '--help'])
82 return log_call_read(["ovs-vsctl"] + args)
85 (returncode, stdout) = ovs_vsctl(["list-br"])
86 if (returncode != 0): raise OvsException("list-br")
89 def ovs_addbridge(name):
90 (returncode, stdout) = ovs_vsctl(["add-br",name])
91 if (returncode != 0): raise OvsException("add-br")
93 def ovs_listports(name):
94 (returncode, stdout) = ovs_vsctl(["list-ports", name])
95 if (returncode != 0): raise OvsException("list-ports")
98 def ovs_delbridge(name):
99 (returncode, stdout) = ovs_vsctl(["del-br",name])
100 if (returncode != 0): raise OvsException("del-br")
102 def ovs_addport(name, portname, type, remoteip, key):
103 args = ["add-port", name, portname, "--", "set", "interface", portname, "type="+type]
105 args = args + ["options:remote_ip=" + remoteip]
107 args = args + ["options:key=" + str(key)]
109 (returncode, stdout) = ovs_vsctl(args)
110 if (returncode != 0): raise OvsException("add-port")
112 def ovs_delport(name, portname):
113 (returncode, stdout) = ovs_vsctl(["del-port",name,portname])
114 if (returncode != 0): raise OvsException("del-port")
116 def ensure_slicebridge_created(name, addr):
117 bridges = ovs_listbridge()
118 logger.log("privatebridge: current bridges = " + ",".join(bridges))
124 logger.log_call(["ifconfig", name, addr, "netmask", "255.0.0.0"])
126 def ensure_slicebridge_neighbors(name, sliver_id, neighbors):
127 ports = ovs_listports(name)
130 for neighbor in neighbors:
131 (neighbor_node_id, neighbor_ip) = neighbor.split("/")
132 neighbor_node_id = int(neighbor_node_id)
133 portname = "gre%d-%d" % (sliver_id, neighbor_node_id)
135 want_ports.append(portname)
137 if not portname in ports:
138 ovs_addport(name, portname, "gre", neighbor_ip, sliver_id)
140 for portname in ports:
141 if portname.startswith("gre") and (portname not in want_ports):
142 ovs_delport(name, portname)
144 def configure_slicebridge(sliver, attributes):
145 sliver_name = sliver['name']
146 sliver_id = sliver['slice_id']
148 slice_bridge_name = attributes["slice_bridge_name"]
150 slice_bridge_addr = attributes.get("slice_bridge_addr", None)
151 if not slice_bridge_addr:
152 logger.log("privatebridge: no slice_bridge_addr for %s" % sliver_name)
155 slice_bridge_neighbors = attributes.get("slice_bridge_neighbors", None)
156 if not slice_bridge_neighbors:
157 logger.log("privatebridge: no slice_bridge_neighbors for %s" % sliver_name)
160 slice_bridge_neighbors = [x.strip() for x in slice_bridge_neighbors.split(",")]
162 ensure_slicebridge_created(slice_bridge_name, slice_bridge_addr)
163 ensure_slicebridge_neighbors(slice_bridge_name, sliver_id, slice_bridge_neighbors)
165 def GetSlivers(data, conf = None, plc = None):
167 if not ovs_available():
168 logger.log ("privatebridge: warning, ovs-vsctl not found - exiting")
171 node_id = tools.node_id()
173 if 'slivers' not in data:
174 logger.log_missing_data("privatebridge.GetSlivers",'slivers')
178 for sliver in data['slivers']:
179 sliver_name = sliver['name']
181 # build a dict of attributes, because it's more convenient
183 for attribute in sliver['attributes']:
184 attributes[attribute['tagname']] = attribute['value']
186 bridge_name = attributes.get('slice_bridge_name',None)
188 configure_slicebridge(sliver, attributes)
189 valid_bridges.append(bridge_name)
191 # now, delete the bridges that we don't want
192 bridges = ovs_listbridge()
193 for bridge_name in bridges:
194 if not bridge_name.startswith("br-slice-"):
195 # ignore ones we didn't create
198 if bridge_name in valid_bridges:
199 # ignore ones we want to keep
202 logger.log("privatebridge: deleting unused bridge %s" % bridge_name)
204 ovs_delbridge(bridge_name)