quick pass for small cleanup within bsd nodes

This commit is contained in:
Blake J. Harnden 2017-08-03 12:44:08 -07:00
parent 1f9a8879c1
commit 78ff7f2189
4 changed files with 146 additions and 116 deletions

View file

@ -16,58 +16,82 @@ import subprocess
from core import constants
from core.misc import utils
utils.checkexec([constants.NGCTL_BIN])
utils.check_executables([constants.NGCTL_BIN])
def createngnode(type, hookstr, name=None):
def createngnode(node_type, hookstr, name=None):
"""
Create a new Netgraph node of type and optionally assign name. The
hook string hookstr should contain two names. This is a string so
other commands may be inserted after the two names.
Return the name and netgraph ID of the new node.
:param node_type: node type to create
:param hookstr: hook string
:param name: name
:return: name and id
:rtype: tuple
"""
hook1 = hookstr.split()[0]
ngcmd = "mkpeer %s %s \n show .%s" % (type, hookstr, hook1)
ngcmd = "mkpeer %s %s \n show .%s" % (node_type, hookstr, hook1)
cmd = [constants.NGCTL_BIN, "-f", "-"]
cmdid = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
cmdid = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# err will always be None
result, err = cmdid.communicate(input=ngcmd)
status = cmdid.wait()
if status > 0:
raise Exception("error creating Netgraph node %s (%s): %s" % (type, ngcmd, result))
raise Exception("error creating Netgraph node %s (%s): %s" % (node_type, ngcmd, result))
results = result.split()
ngname = results[1]
ngid = results[5]
if name:
utils.check_call([constants.NGCTL_BIN, "name", "[0x%s]:" % ngid, name])
subprocess.check_call([constants.NGCTL_BIN, "name", "[0x%s]:" % ngid, name])
return ngname, ngid
def destroyngnode(name):
""" Shutdown a Netgraph node having the given name.
"""
utils.check_call([constants.NGCTL_BIN, "shutdown", "%s:" % name])
Shutdown a Netgraph node having the given name.
:param str name: node name
:return: nothing
"""
subprocess.check_call([constants.NGCTL_BIN, "shutdown", "%s:" % name])
def connectngnodes(name1, name2, hook1, hook2):
""" Connect two hooks of two Netgraph nodes given by their names.
"""
Connect two hooks of two Netgraph nodes given by their names.
:param str name1: name one
:param str name2: name two
:param str hook1: hook one
:param str hook2: hook two
:return: nothing
"""
node1 = "%s:" % name1
node2 = "%s:" % name2
utils.check_call([constants.NGCTL_BIN, "connect", node1, node2, hook1, hook2])
subprocess.check_call([constants.NGCTL_BIN, "connect", node1, node2, hook1, hook2])
def ngmessage(name, msg):
""" Send a Netgraph message to the node named name.
"""
Send a Netgraph message to the node named name.
:param str name: node name
:param list msg: message
:return: nothing
"""
cmd = [constants.NGCTL_BIN, "msg", "%s:" % name] + msg
utils.check_call(cmd)
subprocess.check_call(cmd)
def ngloadkernelmodule(name):
""" Load a kernel module by invoking kldstat. This is needed for the
"""
Load a kernel module by invoking kldstat. This is needed for the
ng_ether module which automatically creates Netgraph nodes when loaded.
:param str name: module name
:return: nothing
"""
utils.mutecall(["kldload", name])

View file

@ -12,6 +12,7 @@ from the CoreNode, implementing specific node types.
"""
import socket
import subprocess
from core import constants
from core.api import coreapi
@ -25,9 +26,12 @@ from core.enumerations import LinkTypes
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.misc import ipaddress
from core.misc import log
from core.misc import utils
utils.checkexec([constants.IFCONFIG_BIN])
logger = log.get_logger(__name__)
utils.check_executables([constants.IFCONFIG_BIN])
class CoreNode(JailNode):
@ -36,13 +40,15 @@ class CoreNode(JailNode):
class PtpNet(NetgraphPipeNet):
def tonodemsg(self, flags):
""" Do not generate a Node Message for point-to-point links. They are
"""
Do not generate a Node Message for point-to-point links. They are
built using a link message instead.
"""
pass
def tolinkmsgs(self, flags):
""" Build CORE API TLVs for a point-to-point link. One Link message
"""
Build CORE API TLVs for a point-to-point link. One Link message
describes this network.
"""
tlvdata = ""
@ -74,7 +80,7 @@ class PtpNet(NetgraphPipeNet):
if if1.hwaddr:
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE1_MAC.value, if1.hwaddr)
for addr in if1.addrlist:
(ip, sep, mask) = addr.partition("/")
ip, sep, mask = addr.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = socket.AF_INET
@ -92,7 +98,7 @@ class PtpNet(NetgraphPipeNet):
if if2.hwaddr:
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.INTERFACE2_MAC.value, if2.hwaddr)
for addr in if2.addrlist:
(ip, sep, mask) = addr.partition("/")
ip, sep, mask = addr.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = socket.AF_INET
@ -131,9 +137,8 @@ class WlanNode(NetgraphNet):
linktype = LinkTypes.WIRELESS.value
policy = "DROP"
def __init__(self, session, objid=None, name=None, verbose=False,
start=True, policy=None):
NetgraphNet.__init__(self, session, objid, name, verbose, start, policy)
def __init__(self, session, objid=None, name=None, start=True, policy=None):
NetgraphNet.__init__(self, session, objid, name, start, policy)
# wireless model such as basic range
self.model = None
# mobility model such as scripted
@ -142,40 +147,42 @@ class WlanNode(NetgraphNet):
def attach(self, netif):
NetgraphNet.attach(self, netif)
if self.model:
netif.poshook = self.model._positioncallback
netif.poshook = self.model.position_callback
if netif.node is None:
return
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
def setmodel(self, model, config):
""" Mobility and wireless model.
"""
if self.verbose:
self.info("adding model %s" % model._name)
if model._type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, objid=self.objid,
verbose=self.verbose, values=config)
if self.model._positioncallback:
Mobility and wireless model.
:param core.mobility.WirelessModel.cls model: model to set
:param dict config: configuration for model
:return:
"""
logger.info("adding model %s" % model.name)
if model.config_type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, objid=self.objid, values=config)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model._positioncallback
netif.poshook = self.model.position_callback
if netif.node is not None:
(x, y, z) = netif.node.position.get()
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.setlinkparams()
elif model._type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, objid=self.objid,
verbose=self.verbose, values=config)
elif model.config_type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, objid=self.objid, values=config)
class RJ45Node(NetgraphPipeNet):
apitype = NodeTypes.RJ45.value
policy = "ACCEPT"
def __init__(self, session, objid, name, verbose, start=True):
def __init__(self, session, objid, name, start=True):
if start:
ngloadkernelmodule("ng_ether")
NetgraphPipeNet.__init__(self, session, objid, name, verbose, start)
NetgraphPipeNet.__init__(self, session, objid, name, start)
if start:
self.setpromisc(True)
@ -187,12 +194,11 @@ class RJ45Node(NetgraphPipeNet):
p = "promisc"
if not promisc:
p = "-" + p
utils.check_call([constants.IFCONFIG_BIN, self.name, "up", p])
subprocess.check_call([constants.IFCONFIG_BIN, self.name, "up", p])
def attach(self, netif):
if len(self._netif) > 0:
raise ValueError, \
"RJ45 networks support at most 1 network interface"
raise ValueError("RJ45 networks support at most 1 network interface")
NetgraphPipeNet.attach(self, netif)
connectngnodes(self.ngname, self.name, self.gethook(), "lower")

View file

@ -16,14 +16,16 @@ from core.bsd.netgraph import createngnode
from core.bsd.netgraph import destroyngnode
from core.bsd.netgraph import ngmessage
from core.coreobj import PyCoreNet
from core.misc import log
logger = log.get_logger(__name__)
class NetgraphNet(PyCoreNet):
ngtype = None
nghooks = ()
def __init__(self, session, objid=None, name=None, verbose=False,
start=True, policy=None):
def __init__(self, session, objid=None, name=None, start=True, policy=None):
PyCoreNet.__init__(self, session, objid, name)
if name is None:
name = str(self.objid)
@ -32,7 +34,6 @@ class NetgraphNet(PyCoreNet):
self.name = name
self.ngname = "n_%s_%s" % (str(self.objid), self.session.session_id)
self.ngid = None
self.verbose = verbose
self._netif = {}
self._linked = {}
self.up = False
@ -40,7 +41,7 @@ class NetgraphNet(PyCoreNet):
self.startup()
def startup(self):
tmp, self.ngid = createngnode(type=self.ngtype, hookstr=self.nghooks, name=self.ngname)
tmp, self.ngid = createngnode(node_type=self.ngtype, hookstr=self.nghooks, name=self.ngname)
self.up = True
def shutdown(self):
@ -61,12 +62,13 @@ class NetgraphNet(PyCoreNet):
destroyngnode(self.ngname)
def attach(self, netif):
""" Attach an interface to this netgraph node. Create a pipe between
"""
Attach an interface to this netgraph node. Create a pipe between
the interface and the hub/switch/wlan node.
(Note that the PtpNet subclass overrides this method.)
"""
if self.up:
pipe = self.session.addobj(cls=NetgraphPipeNet, verbose=self.verbose, start=True)
pipe = self.session.addobj(cls=NetgraphPipeNet, start=True)
pipe.attach(netif)
hook = "link%d" % len(self._netif)
pipe.attachnet(self, hook)
@ -107,17 +109,19 @@ class NetgraphNet(PyCoreNet):
self._linked[netif1][netif2] = True
def linknet(self, net):
""" Link this bridge with another by creating a veth pair and installing
"""
Link this bridge with another by creating a veth pair and installing
each device into each bridge.
"""
raise NotImplementedError
def linkconfig(self, netif, bw=None, delay=None,
loss=None, duplicate=None, jitter=None, netif2=None):
""" Set link effects by modifying the pipe connected to an interface.
"""
Set link effects by modifying the pipe connected to an interface.
"""
if not netif.pipe:
self.warn("linkconfig for %s but interface %s has no pipe" % (self.name, netif.name))
logger.warn("linkconfig for %s but interface %s has no pipe", self.name, netif.name)
return
return netif.pipe.linkconfig(netif, bw, delay, loss, duplicate, jitter, netif2)
@ -126,40 +130,39 @@ class NetgraphPipeNet(NetgraphNet):
ngtype = "pipe"
nghooks = "upper lower"
def __init__(self, session, objid=None, name=None, verbose=False,
start=True, policy=None):
NetgraphNet.__init__(self, session, objid, name, verbose, start, policy)
def __init__(self, session, objid=None, name=None, start=True, policy=None):
NetgraphNet.__init__(self, session, objid, name, start, policy)
if start:
# account for Ethernet header
ngmessage(self.ngname, ["setcfg", "{", "header_offset=14", "}"])
def attach(self, netif):
""" Attach an interface to this pipe node.
"""
Attach an interface to this pipe node.
The first interface is connected to the "upper" hook, the second
connected to the "lower" hook.
"""
if len(self._netif) > 1:
raise ValueError, \
"Netgraph pipes support at most 2 network interfaces"
raise ValueError("Netgraph pipes support at most 2 network interfaces")
if self.up:
hook = self.gethook()
connectngnodes(self.ngname, netif.localname, hook, netif.hook)
if netif.pipe:
raise ValueError, \
"Interface %s already attached to pipe %s" % \
(netif.name, netif.pipe.name)
raise ValueError("Interface %s already attached to pipe %s" % (netif.name, netif.pipe.name))
netif.pipe = self
self._netif[netif] = netif
self._linked[netif] = {}
def attachnet(self, net, hook):
""" Attach another NetgraphNet to this pipe node.
"""
Attach another NetgraphNet to this pipe node.
"""
localhook = self.gethook()
connectngnodes(self.ngname, net.ngname, localhook, hook)
def gethook(self):
""" Returns the first hook (e.g. "upper") then the second hook
"""
Returns the first hook (e.g. "upper") then the second hook
(e.g. "lower") based on the number of connections.
"""
hooks = self.nghooks.split()
@ -170,7 +173,8 @@ class NetgraphPipeNet(NetgraphNet):
def linkconfig(self, netif, bw=None, delay=None,
loss=None, duplicate=None, jitter=None, netif2=None):
""" Set link effects by sending a Netgraph setcfg message to the pipe.
"""
Set link effects by sending a Netgraph setcfg message to the pipe.
"""
netif.setparam("bw", bw)
netif.setparam("delay", delay)
@ -201,7 +205,7 @@ class NetgraphPipeNet(NetgraphNet):
upstream += ["duplicate=%s" % duplicate, ]
downstream += ["duplicate=%s" % duplicate, ]
if jitter:
self.warn("jitter parameter ignored for link %s" % self.name)
logger.warn("jitter parameter ignored for link %s", self.name)
if len(params) > 0 or len(upstream) > 0 or len(downstream) > 0:
setcfg = ["setcfg", "{", ] + params
if len(upstream) > 0:

View file

@ -20,9 +20,12 @@ from core.bsd.netgraph import createngnode
from core.bsd.netgraph import destroyngnode
from core.coreobj import PyCoreNetIf
from core.coreobj import PyCoreNode
from core.misc import log
from core.misc import utils
utils.checkexec([constants.IFCONFIG_BIN, constants.VIMAGE_BIN])
logger = log.get_logger(__name__)
utils.check_executables([constants.IFCONFIG_BIN, constants.VIMAGE_BIN])
class VEth(PyCoreNetIf):
@ -46,11 +49,10 @@ class VEth(PyCoreNetIf):
def startup(self):
hookstr = "%s %s" % (self.hook, self.hook)
ngname, ngid = createngnode(type="eiface", hookstr=hookstr,
name=self.localname)
ngname, ngid = createngnode(node_type="eiface", hookstr=hookstr, name=self.localname)
self.name = ngname
self.ngid = ngid
utils.check_call([constants.IFCONFIG_BIN, ngname, "up"])
subprocess.check_call([constants.IFCONFIG_BIN, ngname, "up"])
self.up = True
def shutdown(self):
@ -81,19 +83,18 @@ class VEth(PyCoreNetIf):
class TunTap(PyCoreNetIf):
"""TUN/TAP virtual device in TAP mode"""
"""
TUN/TAP virtual device in TAP mode
"""
def __init__(self, node, name, localname, mtu=None, net=None,
start=True):
def __init__(self, node, name, localname, mtu=None, net=None, start=True):
raise NotImplementedError
class SimpleJailNode(PyCoreNode):
def __init__(self, session, objid=None, name=None, nodedir=None,
verbose=False):
def __init__(self, session, objid=None, name=None, nodedir=None):
PyCoreNode.__init__(self, session, objid, name)
self.nodedir = nodedir
self.verbose = verbose
self.pid = None
self.up = False
self.lock = threading.RLock()
@ -101,16 +102,15 @@ class SimpleJailNode(PyCoreNode):
def startup(self):
if self.up:
raise Exception, "already up"
raise Exception("already up")
vimg = [constants.VIMAGE_BIN, "-c", self.name]
try:
os.spawnlp(os.P_WAIT, constants.VIMAGE_BIN, *vimg)
except OSError:
raise Exception, ("vimage command not found while running: %s" % \
vimg)
self.info("bringing up loopback interface")
raise Exception("vimage command not found while running: %s" % vimg)
logger.info("bringing up loopback interface")
self.cmd([constants.IFCONFIG_BIN, "lo0", "127.0.0.1"])
self.info("setting hostname: %s" % self.name)
logger.info("setting hostname: %s", self.name)
self.cmd(["hostname", self.name])
self.cmd([constants.SYSCTL_BIN, "vfs.morphing_symlinks=1"])
self.up = True
@ -134,11 +134,11 @@ class SimpleJailNode(PyCoreNode):
mode = os.P_WAIT
else:
mode = os.P_NOWAIT
tmp = utils.call([constants.VIMAGE_BIN, self.name] + args, cwd=self.nodedir)
tmp = subprocess.call([constants.VIMAGE_BIN, self.name] + args, cwd=self.nodedir)
if not wait:
tmp = None
if tmp:
self.warn("cmd exited with status %s: %s" % (tmp, str(args)))
logger.warn("cmd exited with status %s: %s", tmp, str(args))
return tmp
def cmdresult(self, args, wait=True):
@ -170,7 +170,8 @@ class SimpleJailNode(PyCoreNode):
"-title", self.name, "-e", constants.VIMAGE_BIN, self.name, sh)
def termcmdstring(self, sh="/bin/sh"):
""" We add "sudo" to the command string because the GUI runs as a
"""
We add "sudo" to the command string because the GUI runs as a
normal user.
"""
return "cd %s && sudo %s %s %s" % (self.nodedir, constants.VIMAGE_BIN, self.name, sh)
@ -183,11 +184,11 @@ class SimpleJailNode(PyCoreNode):
def mount(self, source, target):
source = os.path.abspath(source)
self.info("mounting %s at %s" % (source, target))
logger.info("mounting %s at %s", source, target)
self.addsymlink(path=target, file=None)
def umount(self, target):
self.info("unmounting %s" % target)
logger.info("unmounting %s", target)
def newveth(self, ifindex=None, ifname=None, net=None):
self.lock.acquire()
@ -204,7 +205,7 @@ class SimpleJailNode(PyCoreNode):
mtu=1500, net=net, start=self.up)
if self.up:
# install into jail
utils.check_call([constants.IFCONFIG_BIN, veth.name, "vnet", self.name])
subprocess.check_call([constants.IFCONFIG_BIN, veth.name, "vnet", self.name])
# rename from "ngeth0" to "eth0"
self.cmd([constants.IFCONFIG_BIN, veth.name, "name", ifname])
@ -223,8 +224,7 @@ class SimpleJailNode(PyCoreNode):
def sethwaddr(self, ifindex, addr):
self._netif[ifindex].sethwaddr(addr)
if self.up:
self.cmd([constants.IFCONFIG_BIN, self.ifname(ifindex), "link",
str(addr)])
self.cmd([constants.IFCONFIG_BIN, self.ifname(ifindex), "link", str(addr)])
def addaddr(self, ifindex, addr):
if self.up:
@ -232,15 +232,14 @@ class SimpleJailNode(PyCoreNode):
family = "inet6"
else:
family = "inet"
self.cmd([constants.IFCONFIG_BIN, self.ifname(ifindex), family, "alias",
str(addr)])
self.cmd([constants.IFCONFIG_BIN, self.ifname(ifindex), family, "alias", str(addr)])
self._netif[ifindex].addaddr(addr)
def deladdr(self, ifindex, addr):
try:
self._netif[ifindex].deladdr(addr)
except ValueError:
self.warn("trying to delete unknown address: %s" % addr)
logger.warn("trying to delete unknown address: %s", addr)
if self.up:
if ":" in addr:
family = "inet6"
@ -255,8 +254,7 @@ class SimpleJailNode(PyCoreNode):
addr = self.getaddr(self.ifname(ifindex), rescan=True)
for t in addrtypes:
if t not in self.valid_deladdrtype:
raise ValueError, "addr type must be in: " + \
" ".join(self.valid_deladdrtype)
raise ValueError("addr type must be in: " + " ".join(self.valid_deladdrtype))
for a in addr[t]:
self.deladdr(ifindex, a)
# update cached information
@ -297,7 +295,8 @@ class SimpleJailNode(PyCoreNode):
# return self.vnodeclient.getaddr(ifname = ifname, rescan = rescan)
def addsymlink(self, path, file):
""" Create a symbolic link from /path/name/file ->
"""
Create a symbolic link from /path/name/file ->
/tmp/pycore.nnnnn/@.conf/path.name/file
"""
dirname = path
@ -318,20 +317,15 @@ class SimpleJailNode(PyCoreNode):
os.unlink(pathname)
else:
if os.path.exists(pathname):
self.warn("did not create symlink for %s since path " \
"exists on host" % pathname)
logger.warn("did not create symlink for %s since path exists on host", pathname)
return
self.info("creating symlink %s -> %s" % (pathname, sym))
logger.info("creating symlink %s -> %s", pathname, sym)
os.symlink(sym, pathname)
class JailNode(SimpleJailNode):
def __init__(self, session, objid=None, name=None,
nodedir=None, bootsh="boot.sh", verbose=False,
start=True):
super(JailNode, self).__init__(session=session, objid=objid,
name=name, nodedir=nodedir,
verbose=verbose)
def __init__(self, session, objid=None, name=None, nodedir=None, bootsh="boot.sh", start=True):
super(JailNode, self).__init__(session=session, objid=objid, name=name, nodedir=nodedir)
self.bootsh = bootsh
if not start:
return
@ -369,8 +363,10 @@ class JailNode(SimpleJailNode):
def privatedir(self, path):
if path[0] != "/":
raise ValueError, "path not fully qualified: " + path
hostpath = os.path.join(self.nodedir,
os.path.normpath(path).strip("/").replace("/", "."))
hostpath = os.path.join(
self.nodedir,
os.path.normpath(path).strip("/").replace("/", ".")
)
try:
os.mkdir(hostpath)
except OSError:
@ -383,7 +379,7 @@ class JailNode(SimpleJailNode):
dirname, basename = os.path.split(filename)
# self.addsymlink(path=dirname, file=basename)
if not basename:
raise ValueError, "no basename for filename: " + filename
raise ValueError("no basename for filename: %s" % filename)
if dirname and dirname[0] == "/":
dirname = dirname[1:]
dirname = dirname.replace("/", ".")
@ -398,4 +394,4 @@ class JailNode(SimpleJailNode):
f.write(contents)
os.chmod(f.name, mode)
f.close()
self.info("created nodefile: %s; mode: 0%o" % (f.name, mode))
logger.info("created nodefile: %s; mode: 0%o", f.name, mode)