Added support for auxiliary control networks. Some refactoring.

This commit is contained in:
tgoff0 2015-05-22 00:53:43 +00:00
parent cd479193fc
commit 06fe91ea86

View file

@ -608,6 +608,7 @@ class Session(object):
of various managers and boot the nodes. Validate nodes and check
for transition to the runtime state.
'''
self.writeobjs()
# controlnet may be needed by some EMANE models
self.addremovectrlif(node=None, remove=False)
@ -686,7 +687,12 @@ class Session(object):
self.services.stopnodeservices(obj)
self.emane.shutdown()
self.updatectrlifhosts(remove=True)
# Remove all four possible control networks. Does nothing if ctrlnet is not installed.
self.addremovectrlif(node=None, remove=True)
self.addremovectrlif(node=None, netidx=1, remove=True)
self.addremovectrlif(node=None, netidx=2, remove=True)
self.addremovectrlif(node=None, netidx=3, remove=True)
# self.checkshutdown() is currently invoked from node delete handler
def checkshutdown(self):
@ -774,24 +780,59 @@ class Session(object):
continue
n.validate()
def addremovectrlnet(self, remove=False, conf_reqd=True):
def getctrlnetprefixes(self):
p = getattr(self.options, 'controlnet', self.cfg.get('controlnet'))
p0 = getattr(self.options, 'controlnet0', self.cfg.get('controlnet0'))
p1 = getattr(self.options, 'controlnet1', self.cfg.get('controlnet1'))
p2 = getattr(self.options, 'controlnet2', self.cfg.get('controlnet2'))
p3 = getattr(self.options, 'controlnet3', self.cfg.get('controlnet3'))
if not p0 and p:
p0 = p
return [p0,p1,p2,p3]
def getctrlnetserverintf(self):
d0 = self.cfg.get('controlnetif0')
if d0:
self.warn("controlnet0 cannot be assigned with a host interface")
d1 = self.cfg.get('controlnetif1')
d2 = self.cfg.get('controlnetif2')
d3 = self.cfg.get('controlnetif3')
return [None,d1,d2,d3]
def getctrlnetidx(self, dev):
if dev[0:4] == 'ctrl' and int(dev[4]) in [0,1,2,3]:
idx = int(dev[4])
if idx < 4 and self.getctrlnetprefixes()[idx] is not None:
return idx
else:
return -1
def getctrlnetobj(self, netidx):
oid = "ctrl%dnet" % netidx
return self.obj(oid)
def addremovectrlnet(self, netidx, remove=False, conf_reqd=True):
''' Create a control network bridge as necessary.
When the remove flag is True, remove the bridge that connects control
interfaces. The conf_reqd flag, when False, causes a control network
bridge to be added even if one has not been configured.
'''
prefix = self.cfg.get('controlnet')
prefix = getattr(self.options, 'controlnet', prefix)
if not prefix:
prefixspeclist = self.getctrlnetprefixes()
prefixspec = prefixspeclist[netidx]
if not prefixspec:
if conf_reqd:
return None # no controlnet needed
else:
prefix = nodes.CtrlNet.DEFAULT_PREFIX
prefixspec = nodes.CtrlNet.DEFAULT_PREFIX_LIST[netidx]
serverintf = self.getctrlnetserverintf()[netidx]
# return any existing controlnet bridge
id = "ctrlnet"
try:
ctrlnet = self.obj(id)
ctrlnet = self.getctrlnetobj(netidx)
if remove:
self.delobj(ctrlnet.objid)
return None
@ -801,7 +842,11 @@ class Session(object):
return None
# build a new controlnet bridge
oid = "ctrl%dnet" % netidx
# use the updown script for control net 0 only.
updown_script = None
if netidx == 0:
try:
if self.cfg['controlnet_updown_script']:
updown_script = self.cfg['controlnet_updown_script']
@ -813,14 +858,18 @@ class Session(object):
if new_uds:
updown_script = new_uds
prefixes = prefix.split()
prefixes = prefixspec.split()
if len(prefixes) > 1:
# A list of per-host prefixes is provided
assign_address = True
if self.master:
try:
# split first (master) entry into server and prefix
prefix = prefixes[0].split(':', 1)[1]
except IndexError:
prefix = prefixes[0] # possibly only one server
# no server name. possibly only one server
prefix = prefixes[0]
else:
# slave servers have their name and localhost in the serverlist
servers = self.broker.getserverlist()
@ -828,11 +877,14 @@ class Session(object):
prefix = None
for server_prefix in prefixes:
try:
# split each entry into server and prefix
server, p = server_prefix.split(':')
except ValueError:
server = ""
p = None
if server == servers[0]:
# the server name in the list matches this server
prefix = p
break
if not prefix:
@ -845,32 +897,37 @@ class Session(object):
prefix = prefixes[0].split(':', 1)[1]
except IndexError:
prefix = prefixes[0]
else:
else: # len(prefixes) == 1
# TODO: can we get the server name from the servers.conf or from the node assignments?
# with one prefix, only master gets a ctrlnet address
assign_address = self.master
ctrlnet = self.addobj(cls=nodes.CtrlNet, objid=id, prefix=prefix,
prefix = prefixes[0]
ctrlnet = self.addobj(cls=nodes.CtrlNet, objid=oid, prefix=prefix,
assign_address=assign_address,
updown_script=updown_script)
updown_script=updown_script, serverintf=serverintf)
# tunnels between controlnets will be built with Broker.addnettunnels()
self.broker.addnet(id)
self.broker.addnet(oid)
for server in self.broker.getserverlist():
self.broker.addnodemap(server, id)
self.broker.addnodemap(server, oid)
return ctrlnet
def addremovectrlif(self, node, remove=False, conf_reqd=True):
def addremovectrlif(self, node, netidx=0, remove=False, conf_reqd=True):
''' Add a control interface to a node when a 'controlnet' prefix is
listed in the config file or session options. Uses
addremovectrlnet() to build or remove the control bridge.
If conf_reqd is False, the control network may be built even
when the user has not configured one (e.g. for EMANE.)
'''
ctrlnet = self.addremovectrlnet(remove, conf_reqd)
ctrlnet = self.addremovectrlnet(netidx, remove, conf_reqd)
if ctrlnet is None:
return
if node is None:
return
if node.netif(ctrlnet.CTRLIF_IDX_BASE):
return # ctrl0 already exists
if node.netif(ctrlnet.CTRLIF_IDX_BASE + netidx):
return # ctrl# already exists
ctrlip = node.objid
try:
addrlist = ["%s/%s" % (ctrlnet.prefix.addr(ctrlip),
@ -882,19 +939,19 @@ class Session(object):
node.exception(coreapi.CORE_EXCP_LEVEL_ERROR,
"Session.addremovectrlif()", msg)
return
ifi = node.newnetif(net = ctrlnet, ifindex = ctrlnet.CTRLIF_IDX_BASE,
ifname = "ctrl0", hwaddr = MacAddr.random(),
ifi = node.newnetif(net = ctrlnet, ifindex = ctrlnet.CTRLIF_IDX_BASE + netidx,
ifname = "ctrl%d" % netidx, hwaddr = MacAddr.random(),
addrlist = addrlist)
node.netif(ifi).control = True
def updatectrlifhosts(self, remove=False):
def updatectrlifhosts(self, netidx=0, remove=False):
''' Add the IP addresses of control interfaces to the /etc/hosts file.
'''
if not self.getcfgitembool('update_etc_hosts', False):
return
id = "ctrlnet"
try:
ctrlnet = self.obj(id)
ctrlnet = self.getctrlnetobj(netidx)
except KeyError:
return
header = "CORE session %s host entries" % self.sessionid