216 lines
7.4 KiB
Python
216 lines
7.4 KiB
Python
#
|
|
# CORE
|
|
# Copyright (c)2010-2012 the Boeing Company.
|
|
# See the LICENSE file included in this distribution.
|
|
#
|
|
# authors: core-dev@pf.itd.nrl.navy.mil
|
|
#
|
|
'''
|
|
vnet.py: NetgraphNet and NetgraphPipeNet classes that implement virtual networks
|
|
using the FreeBSD Netgraph subsystem.
|
|
'''
|
|
|
|
import sys, threading
|
|
|
|
from core.misc.utils import *
|
|
from core.constants import *
|
|
from core.coreobj import PyCoreNet, PyCoreObj
|
|
from core.bsd.netgraph import *
|
|
from core.bsd.vnode import VEth
|
|
|
|
class NetgraphNet(PyCoreNet):
|
|
ngtype = None
|
|
nghooks = ()
|
|
|
|
def __init__(self, session, objid = None, name = None, verbose = False,
|
|
start = True, policy = None):
|
|
PyCoreNet.__init__(self, session, objid, name)
|
|
if name is None:
|
|
name = str(self.objid)
|
|
if policy is not None:
|
|
self.policy = policy
|
|
self.name = name
|
|
self.ngname = "n_%s_%s" % (str(self.objid), self.session.sessionid)
|
|
self.ngid = None
|
|
self.verbose = verbose
|
|
self._netif = {}
|
|
self._linked = {}
|
|
self.up = False
|
|
if start:
|
|
self.startup()
|
|
|
|
def startup(self):
|
|
tmp, self.ngid = createngnode(type=self.ngtype, hookstr=self.nghooks,
|
|
name=self.ngname)
|
|
self.up = True
|
|
|
|
def shutdown(self):
|
|
if not self.up:
|
|
return
|
|
self.up = False
|
|
while self._netif:
|
|
k, netif = self._netif.popitem()
|
|
if netif.pipe:
|
|
pipe = netif.pipe
|
|
netif.pipe = None
|
|
pipe.shutdown()
|
|
else:
|
|
netif.shutdown()
|
|
self._netif.clear()
|
|
self._linked.clear()
|
|
del self.session
|
|
destroyngnode(self.ngname)
|
|
|
|
def attach(self, netif):
|
|
''' 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.attach(netif)
|
|
hook = "link%d" % len(self._netif)
|
|
pipe.attachnet(self, hook)
|
|
PyCoreNet.attach(self, netif)
|
|
|
|
def detach(self, netif):
|
|
if self.up:
|
|
pass
|
|
PyCoreNet.detach(self, netif)
|
|
|
|
def linked(self, netif1, netif2):
|
|
# check if the network interfaces are attached to this network
|
|
if self._netif[netif1] != netif1:
|
|
raise ValueError, "inconsistency for netif %s" % netif1.name
|
|
if self._netif[netif2] != netif2:
|
|
raise ValueError, "inconsistency for netif %s" % netif2.name
|
|
try:
|
|
linked = self._linked[netif1][netif2]
|
|
except KeyError:
|
|
linked = False
|
|
self._linked[netif1][netif2] = linked
|
|
return linked
|
|
|
|
def unlink(self, netif1, netif2):
|
|
if not self.linked(netif1, netif2):
|
|
return
|
|
msg = ["unlink", "{", "node1=0x%s" % netif1.pipe.ngid]
|
|
msg += ["node2=0x%s" % netif2.pipe.ngid, "}"]
|
|
ngmessage(self.ngname, msg)
|
|
self._linked[netif1][netif2] = False
|
|
|
|
def link(self, netif1, netif2):
|
|
if self.linked(netif1, netif2):
|
|
return
|
|
msg = ["link", "{", "node1=0x%s" % netif1.pipe.ngid]
|
|
msg += ["node2=0x%s" % netif2.pipe.ngid, "}"]
|
|
ngmessage(self.ngname, msg)
|
|
self._linked[netif1][netif2] = True
|
|
|
|
def linknet(self, net):
|
|
''' 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.
|
|
'''
|
|
if not netif.pipe:
|
|
self.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)
|
|
|
|
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)
|
|
if start:
|
|
# account for Ethernet header
|
|
ngmessage(self.ngname, ["setcfg", "{", "header_offset=14", "}"])
|
|
|
|
def attach(self, netif):
|
|
''' 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"
|
|
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)
|
|
netif.pipe = self
|
|
self._netif[netif] = netif
|
|
self._linked[netif] = {}
|
|
|
|
def attachnet(self, net, hook):
|
|
''' 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
|
|
(e.g. "lower") based on the number of connections.
|
|
'''
|
|
hooks = self.nghooks.split()
|
|
if len(self._netif) == 0:
|
|
return hooks[0]
|
|
else:
|
|
return hooks[1]
|
|
|
|
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.
|
|
'''
|
|
netif.setparam('bw', bw)
|
|
netif.setparam('delay', delay)
|
|
netif.setparam('loss', loss)
|
|
netif.setparam('duplicate', duplicate)
|
|
netif.setparam('jitter', jitter)
|
|
if not self.up:
|
|
return
|
|
params = []
|
|
upstream = []
|
|
downstream = []
|
|
if bw is not None:
|
|
if str(bw)=="0":
|
|
bw="-1"
|
|
params += ["bandwidth=%s" % bw,]
|
|
if delay is not None:
|
|
if str(delay)=="0":
|
|
delay="-1"
|
|
params += ["delay=%s" % delay,]
|
|
if loss is not None:
|
|
if str(loss)=="0":
|
|
loss="-1"
|
|
upstream += ["BER=%s" % loss,]
|
|
downstream += ["BER=%s" % loss,]
|
|
if duplicate is not None:
|
|
if str(duplicate)=="0":
|
|
duplicate="-1"
|
|
upstream += ["duplicate=%s" % duplicate,]
|
|
downstream += ["duplicate=%s" % duplicate,]
|
|
if jitter:
|
|
self.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:
|
|
setcfg += ["upstream={",] + upstream + ["}",]
|
|
if len(downstream) > 0:
|
|
setcfg += ["downstream={",] + downstream + ["}",]
|
|
setcfg += ["}",]
|
|
ngmessage(self.ngname, setcfg)
|
|
|