2 Private Bridge configurator.
14 class OvsException (Exception) :
15 def __init__(self, message="no message"):
16 self.message = message
21 logger.log('private bridge plugin starting up...')
23 def log_call_read(command, timeout=logger.default_timeout_minutes*60, poll=1):
24 message = " ".join(command)
25 logger.log("log_call: running command %s" % message)
26 logger.verbose("log_call: timeout=%r s" % timeout)
27 logger.verbose("log_call: poll=%r s" % poll)
28 trigger = time.time()+timeout
30 child = subprocess.Popen(
32 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
34 universal_newlines=True)
38 # see if anything can be read within the poll interval
39 (r, w, x) = select.select([child.stdout], [], [], poll)
41 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"
56 %(message, returncode))
57 return (returncode, stdout)
58 # no : still within timeout ?
59 if time.time() >= trigger:
61 logger.log("log_call:end terminating command (%s) - exceeded timeout %d s"
65 except Exception as e:
66 logger.log_exc("failed to run command %s -> %s" % (message, e))
70 ### Thierry - 23 Sept 2014
71 # regardless of this being shipped on lxc-only or on all nodes,
72 # it is safer to check for the availability of the ovs-vsctl command and just print
73 # out a warning when it's not there, instead of a nasty traceback
75 "return True if ovs-vsctl can be run"
77 child = subprocess.Popen (['ovs-vsctl', '--help'])
84 return log_call_read(["ovs-vsctl"] + args)
87 (returncode, stdout) = ovs_vsctl(["list-br"])
88 if (returncode != 0): raise OvsException("list-br")
91 def ovs_addbridge(name):
92 (returncode, stdout) = ovs_vsctl(["add-br", name])
93 if (returncode != 0): raise OvsException("add-br")
95 def ovs_listports(name):
96 (returncode, stdout) = ovs_vsctl(["list-ports", name])
97 if (returncode != 0): raise OvsException("list-ports")
100 def ovs_delbridge(name):
101 (returncode, stdout) = ovs_vsctl(["del-br", name])
102 if (returncode != 0): raise OvsException("del-br")
104 def ovs_addport(name, portname, type, remoteip, key):
105 args = ["add-port", name, portname, "--", "set", "interface", portname, "type="+type]
107 args = args + ["options:remote_ip=" + remoteip]
109 args = args + ["options:key=" + str(key)]
111 returncode, stdout = ovs_vsctl(args)
112 if (returncode != 0):
113 raise OvsException("add-port")
115 def ovs_delport(name, portname):
116 (returncode, stdout) = ovs_vsctl(["del-port", name, portname])
117 if (returncode != 0): raise OvsException("del-port")
119 def ensure_slicebridge_created(name, addr):
120 bridges = ovs_listbridge()
121 logger.log("privatebridge: current bridges = " + ",".join(bridges))
127 logger.log_call(["ifconfig", name, addr, "netmask", "255.0.0.0"])
129 def ensure_slicebridge_neighbors(name, sliver_id, neighbors):
130 ports = ovs_listports(name)
133 for neighbor in neighbors:
134 (neighbor_node_id, neighbor_ip) = neighbor.split("/")
135 neighbor_node_id = int(neighbor_node_id)
136 portname = "gre%d-%d" % (sliver_id, neighbor_node_id)
138 want_ports.append(portname)
140 if not portname in ports:
141 ovs_addport(name, portname, "gre", neighbor_ip, sliver_id)
143 for portname in ports:
144 if portname.startswith("gre") and (portname not in want_ports):
145 ovs_delport(name, portname)
147 def configure_slicebridge(sliver, attributes):
148 sliver_name = sliver['name']
149 sliver_id = sliver['slice_id']
151 slice_bridge_name = attributes["slice_bridge_name"]
153 slice_bridge_addr = attributes.get("slice_bridge_addr", None)
154 if not slice_bridge_addr:
155 logger.log("privatebridge: no slice_bridge_addr for %s" % sliver_name)
158 slice_bridge_neighbors = attributes.get("slice_bridge_neighbors", None)
159 if not slice_bridge_neighbors:
160 logger.log("privatebridge: no slice_bridge_neighbors for %s" % sliver_name)
163 slice_bridge_neighbors = [x.strip() for x in slice_bridge_neighbors.split(",")]
165 ensure_slicebridge_created(slice_bridge_name, slice_bridge_addr)
166 ensure_slicebridge_neighbors(slice_bridge_name, sliver_id, slice_bridge_neighbors)
168 def GetSlivers(data, conf = None, plc = None):
170 if not ovs_available():
171 logger.log ("privatebridge: warning, ovs-vsctl not found - exiting")
174 node_id = tools.node_id()
176 if 'slivers' not in data:
177 logger.log_missing_data("privatebridge.GetSlivers", 'slivers')
181 for sliver in data['slivers']:
182 sliver_name = sliver['name']
184 # build a dict of attributes, because it's more convenient
186 for attribute in sliver['attributes']:
187 attributes[attribute['tagname']] = attribute['value']
189 bridge_name = attributes.get('slice_bridge_name', None)
191 configure_slicebridge(sliver, attributes)
192 valid_bridges.append(bridge_name)
194 # now, delete the bridges that we don't want
195 bridges = ovs_listbridge()
196 for bridge_name in bridges:
197 if not bridge_name.startswith("br-slice-"):
198 # ignore ones we didn't create
201 if bridge_name in valid_bridges:
202 # ignore ones we want to keep
205 logger.log("privatebridge: deleting unused bridge %s" % bridge_name)
207 ovs_delbridge(bridge_name)