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