Merge branch 'develop' into pydocupdates

This commit is contained in:
Huy Pham 2019-09-12 10:24:23 -07:00
commit 2bfcc9ef24
100 changed files with 5340 additions and 3488 deletions

View file

@ -11,17 +11,14 @@ import signal
import socket
import string
import threading
from builtins import range
from socket import AF_INET, AF_INET6
from builtins import range
from core import CoreCommandError, utils
from core import constants
from core.emulator.data import NodeData, LinkData
from core.emulator.enumerations import NodeTypes, LinkTypes
from core.nodes import client, nodeutils, ipaddress
from core.nodes.interface import TunTap, CoreInterface
from core.nodes.interface import Veth
from core import CoreCommandError, constants, utils
from core.emulator.data import LinkData, NodeData
from core.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes import client, ipaddress, nodeutils
from core.nodes.interface import CoreInterface, TunTap, Veth
_DEFAULT_MTU = 1500
@ -32,6 +29,7 @@ class NodeBase(object):
"""
Base class for CORE nodes (nodes and networks)
"""
apitype = None
# TODO: appears start has no usage, verify and remove
@ -199,7 +197,7 @@ class NodeBase(object):
altitude=alt,
model=model,
emulation_server=emulation_server,
services=services
services=services,
)
return node_data
@ -236,16 +234,6 @@ class CoreNodeBase(NodeBase):
self.nodedir = None
self.tmpnodedir = False
def addservice(self, service):
"""
Add a services to the service list.
:param core.services.coreservices.CoreService service: service to add
:return: nothing
"""
if service is not None:
self.services.append(service)
def makenodedir(self):
"""
Create the node directory.
@ -418,10 +406,13 @@ class CoreNode(CoreNodeBase):
"""
Provides standard core node logic.
"""
apitype = NodeTypes.DEFAULT.value
valid_address_types = {"inet", "inet6", "inet6link"}
def __init__(self, session, _id=None, name=None, nodedir=None, bootsh="boot.sh", start=True):
def __init__(
self, session, _id=None, name=None, nodedir=None, bootsh="boot.sh", start=True
):
"""
Create a CoreNode instance.
@ -434,7 +425,9 @@ class CoreNode(CoreNodeBase):
"""
super(CoreNode, self).__init__(session, _id, name, start)
self.nodedir = nodedir
self.ctrlchnlname = os.path.abspath(os.path.join(self.session.session_dir, self.name))
self.ctrlchnlname = os.path.abspath(
os.path.join(self.session.session_dir, self.name)
)
self.client = None
self.pid = None
self.up = False
@ -475,9 +468,12 @@ class CoreNode(CoreNodeBase):
vnoded = [
constants.VNODED_BIN,
"-v",
"-c", self.ctrlchnlname,
"-l", self.ctrlchnlname + ".log",
"-p", self.ctrlchnlname + ".pid"
"-c",
self.ctrlchnlname,
"-l",
self.ctrlchnlname + ".log",
"-p",
self.ctrlchnlname + ".pid",
]
if self.nodedir:
vnoded += ["-C", self.nodedir]
@ -612,7 +608,9 @@ class CoreNode(CoreNodeBase):
"""
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % 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("/", ".")
)
os.mkdir(hostpath)
self.mount(hostpath, path)
@ -626,8 +624,13 @@ class CoreNode(CoreNodeBase):
:raises CoreCommandError: when a non-zero exit status occurs
"""
source = os.path.abspath(source)
logging.info("node(%s) mounting: %s at %s", self.name, source, target)
cmd = 'mkdir -p "%s" && %s -n --bind "%s" "%s"' % (target, constants.MOUNT_BIN, source, target)
logging.debug("node(%s) mounting: %s at %s", self.name, source, target)
cmd = 'mkdir -p "%s" && %s -n --bind "%s" "%s"' % (
target,
constants.MOUNT_BIN,
source,
target,
)
status, output = self.client.shcmd_result(cmd)
if status:
raise CoreCommandError(status, cmd, output)
@ -674,12 +677,20 @@ class CoreNode(CoreNodeBase):
if len(name) >= 16:
raise ValueError("interface name (%s) too long" % name)
veth = Veth(node=self, name=name, localname=localname, net=net, start=self.up)
veth = Veth(
node=self, name=name, localname=localname, net=net, start=self.up
)
if self.up:
utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)])
self.network_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
self.network_cmd([constants.ETHTOOL_BIN, "-K", ifname, "rx", "off", "tx", "off"])
utils.check_cmd(
[constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)]
)
self.network_cmd(
[constants.IP_BIN, "link", "set", veth.name, "name", ifname]
)
self.network_cmd(
[constants.ETHTOOL_BIN, "-K", ifname, "rx", "off", "tx", "off"]
)
veth.name = ifname
@ -725,7 +736,9 @@ class CoreNode(CoreNodeBase):
sessionid = self.session.short_session_id()
localname = "tap%s.%s.%s" % (self.id, ifindex, sessionid)
name = ifname
tuntap = TunTap(node=self, name=name, localname=localname, net=net, start=self.up)
tuntap = TunTap(
node=self, name=name, localname=localname, net=net, start=self.up
)
try:
self.addnetif(tuntap, ifindex)
@ -747,7 +760,15 @@ class CoreNode(CoreNodeBase):
"""
self._netif[ifindex].sethwaddr(addr)
if self.up:
args = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]
args = [
constants.IP_BIN,
"link",
"set",
"dev",
self.ifname(ifindex),
"address",
str(addr),
]
self.network_cmd(args)
def addaddr(self, ifindex, addr):
@ -761,10 +782,26 @@ class CoreNode(CoreNodeBase):
if self.up:
# check if addr is ipv6
if ":" in str(addr):
args = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]
args = [
constants.IP_BIN,
"addr",
"add",
str(addr),
"dev",
self.ifname(ifindex),
]
self.network_cmd(args)
else:
args = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)]
args = [
constants.IP_BIN,
"addr",
"add",
str(addr),
"broadcast",
"+",
"dev",
self.ifname(ifindex),
]
self.network_cmd(args)
self._netif[ifindex].addaddr(addr)
@ -784,7 +821,16 @@ class CoreNode(CoreNodeBase):
logging.exception("trying to delete unknown address: %s" % addr)
if self.up:
self.network_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
self.network_cmd(
[
constants.IP_BIN,
"addr",
"del",
str(addr),
"dev",
self.ifname(ifindex),
]
)
def delalladdr(self, ifindex, address_types=None):
"""
@ -803,7 +849,9 @@ class CoreNode(CoreNodeBase):
for address_type in address_types:
if address_type not in self.valid_address_types:
raise ValueError("addr type must be in: %s" % " ".join(self.valid_address_types))
raise ValueError(
"addr type must be in: %s" % " ".join(self.valid_address_types)
)
for address in addresses[address_type]:
self.deladdr(ifindex, address)
@ -818,7 +866,9 @@ class CoreNode(CoreNodeBase):
:return: nothing
"""
if self.up:
self.network_cmd([constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"])
self.network_cmd(
[constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"]
)
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
"""
@ -874,18 +924,41 @@ class CoreNode(CoreNodeBase):
:return: nothing
"""
tmplen = 8
tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in range(tmplen)])
tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in range(tmplen)])
utils.check_cmd([constants.IP_BIN, "link", "add", "name", tmp1, "type", "veth", "peer", "name", tmp2])
tmp1 = "tmp." + "".join(
[random.choice(string.ascii_lowercase) for _ in range(tmplen)]
)
tmp2 = "tmp." + "".join(
[random.choice(string.ascii_lowercase) for _ in range(tmplen)]
)
utils.check_cmd(
[
constants.IP_BIN,
"link",
"add",
"name",
tmp1,
"type",
"veth",
"peer",
"name",
tmp2,
]
)
utils.check_cmd([constants.IP_BIN, "link", "set", tmp1, "netns", str(self.pid)])
self.network_cmd([constants.IP_BIN, "link", "set", tmp1, "name", ifname])
interface = CoreInterface(node=self, name=ifname, mtu=_DEFAULT_MTU)
self.addnetif(interface, self.newifindex())
utils.check_cmd([constants.IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)])
othernode.network_cmd([constants.IP_BIN, "link", "set", tmp2, "name", otherifname])
other_interface = CoreInterface(node=othernode, name=otherifname, mtu=_DEFAULT_MTU)
utils.check_cmd(
[constants.IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)]
)
othernode.network_cmd(
[constants.IP_BIN, "link", "set", tmp2, "name", otherifname]
)
other_interface = CoreInterface(
node=othernode, name=otherifname, mtu=_DEFAULT_MTU
)
othernode.addnetif(other_interface, othernode.newifindex())
def addfile(self, srcname, filename):
@ -948,7 +1021,9 @@ class CoreNode(CoreNodeBase):
with self.opennodefile(filename, "w") as open_file:
open_file.write(contents)
os.chmod(open_file.name, mode)
logging.info("node(%s) added file: %s; mode: 0%o", self.name, open_file.name, mode)
logging.debug(
"node(%s) added file: %s; mode: 0%o", self.name, open_file.name, mode
)
def nodefilecopy(self, filename, srcfilename, mode=None):
"""
@ -964,13 +1039,16 @@ class CoreNode(CoreNodeBase):
shutil.copy2(srcfilename, hostfilename)
if mode is not None:
os.chmod(hostfilename, mode)
logging.info("node(%s) copied file: %s; mode: %s", self.name, hostfilename, mode)
logging.info(
"node(%s) copied file: %s; mode: %s", self.name, hostfilename, mode
)
class CoreNetworkBase(NodeBase):
"""
Base class for networks
"""
linktype = LinkTypes.WIRED.value
def __init__(self, session, _id, name, start=True):
@ -1048,9 +1126,9 @@ class CoreNetworkBase(NodeBase):
linked_node = netif.othernet
if linked_node.id == self.id:
continue
netif.swapparams('_params_up')
netif.swapparams("_params_up")
upstream_params = netif.getparams()
netif.swapparams('_params_up')
netif.swapparams("_params_up")
if netif.getparams() != upstream_params:
uni = True
@ -1092,7 +1170,7 @@ class CoreNetworkBase(NodeBase):
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter"),
per=netif.getparam("loss")
per=netif.getparam("loss"),
)
all_links.append(link_data)
@ -1100,7 +1178,7 @@ class CoreNetworkBase(NodeBase):
if not uni:
continue
netif.swapparams('_params_up')
netif.swapparams("_params_up")
link_data = LinkData(
message_type=0,
node1_id=linked_node.id,
@ -1110,9 +1188,9 @@ class CoreNetworkBase(NodeBase):
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter"),
per=netif.getparam("loss")
per=netif.getparam("loss"),
)
netif.swapparams('_params_up')
netif.swapparams("_params_up")
all_links.append(link_data)

View file

@ -6,11 +6,9 @@ The control channel can be accessed via calls using the vcmd shell.
import logging
import os
from subprocess import PIPE, Popen
from subprocess import Popen, PIPE
from core import CoreCommandError, utils
from core import constants
from core import CoreCommandError, constants, utils
class VnodeClient(object):
@ -137,7 +135,15 @@ class VnodeClient(object):
:rtype: int
"""
args = utils.split_args(args)
return os.spawnlp(os.P_WAIT, constants.VCMD_BIN, constants.VCMD_BIN, "-c", self.ctrlchnlname, "--", *args)
return os.spawnlp(
os.P_WAIT,
constants.VCMD_BIN,
constants.VCMD_BIN,
"-c",
self.ctrlchnlname,
"--",
*args
)
def redircmd(self, infd, outfd, errfd, args, wait=True):
"""
@ -177,11 +183,27 @@ class VnodeClient(object):
:return: terminal command result
:rtype: int
"""
args = ("xterm", "-ut", "-title", self.name, "-e", constants.VCMD_BIN, "-c", self.ctrlchnlname, "--", sh)
args = (
"xterm",
"-ut",
"-title",
self.name,
"-e",
constants.VCMD_BIN,
"-c",
self.ctrlchnlname,
"--",
sh,
)
if "SUDO_USER" in os.environ:
args = ("su", "-s", "/bin/sh", "-c",
"exec " + " ".join(map(lambda x: "'%s'" % x, args)),
os.environ["SUDO_USER"])
args = (
"su",
"-s",
"/bin/sh",
"-c",
"exec " + " ".join(map(lambda x: "'%s'" % x, args)),
os.environ["SUDO_USER"],
)
return os.spawnvp(os.P_NOWAIT, args[0], args)
def termcmdstring(self, sh="/bin/sh"):

View file

@ -2,7 +2,7 @@ import json
import logging
import os
from core import utils, CoreCommandError
from core import CoreCommandError, utils
from core.emulator.enumerations import NodeTypes
from core.nodes.base import CoreNode
@ -250,7 +250,7 @@ class DockerNode(CoreNode):
:param str path: path to create
:return: nothing
"""
logging.info("creating node dir: %s", path)
logging.debug("creating node dir: %s", path)
args = "mkdir -p {path}".format(path=path)
self.check_cmd(args)
@ -263,7 +263,7 @@ class DockerNode(CoreNode):
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
logging.info("mounting source(%s) target(%s)", source, target)
logging.debug("mounting source(%s) target(%s)", source, target)
raise Exception("not supported")
def nodefile(self, filename, contents, mode=0o644):
@ -275,8 +275,8 @@ class DockerNode(CoreNode):
:param int mode: mode for file
:return: nothing
"""
logging.info("node dir(%s) ctrlchannel(%s)", self.nodedir, self.ctrlchnlname)
logging.info("nodefile filename(%s) mode(%s)", filename, mode)
logging.debug("node dir(%s) ctrlchannel(%s)", self.nodedir, self.ctrlchnlname)
logging.debug("nodefile filename(%s) mode(%s)", filename, mode)
file_path = os.path.join(self.nodedir, filename)
with open(file_path, "w") as f:
os.chmod(f.name, mode)

View file

@ -4,11 +4,9 @@ virtual ethernet classes that implement the interfaces available under Linux.
import logging
import time
from builtins import int
from builtins import range
from builtins import int, range
from core import CoreCommandError, utils
from core import constants
from core import CoreCommandError, constants, utils
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
@ -221,8 +219,20 @@ class Veth(CoreInterface):
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
utils.check_cmd([constants.IP_BIN, "link", "add", "name", self.localname,
"type", "veth", "peer", "name", self.name])
utils.check_cmd(
[
constants.IP_BIN,
"link",
"add",
"name",
self.localname,
"type",
"veth",
"peer",
"name",
self.name,
]
)
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
@ -237,7 +247,9 @@ class Veth(CoreInterface):
if self.node:
try:
self.node.network_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
self.node.network_cmd(
[constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]
)
except CoreCommandError:
logging.exception("error shutting down interface")
@ -298,7 +310,9 @@ class TunTap(CoreInterface):
return
try:
self.node.network_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
self.node.network_cmd(
[constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]
)
except CoreCommandError:
logging.exception("error shutting down tunnel tap")
@ -396,8 +410,12 @@ class TunTap(CoreInterface):
"""
self.waitfordevicelocal()
netns = str(self.node.pid)
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "netns", netns])
self.node.network_cmd([constants.IP_BIN, "link", "set", self.localname, "name", self.name])
utils.check_cmd(
[constants.IP_BIN, "link", "set", self.localname, "netns", netns]
)
self.node.network_cmd(
[constants.IP_BIN, "link", "set", self.localname, "name", self.name]
)
self.node.network_cmd([constants.IP_BIN, "link", "set", self.name, "up"])
def setaddrs(self):
@ -408,7 +426,9 @@ class TunTap(CoreInterface):
"""
self.waitfordevicenode()
for addr in self.addrlist:
self.node.network_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
self.node.network_cmd(
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.name]
)
class GreTap(CoreInterface):
@ -418,9 +438,19 @@ class GreTap(CoreInterface):
having a MAC address. The MAC address is required for bridging.
"""
def __init__(self, node=None, name=None, session=None, mtu=1458,
remoteip=None, _id=None, localip=None, ttl=255,
key=None, start=True):
def __init__(
self,
node=None,
name=None,
session=None,
mtu=1458,
remoteip=None,
_id=None,
localip=None,
ttl=255,
key=None,
start=True,
):
"""
Creates a GreTap instance.
@ -440,7 +470,7 @@ class GreTap(CoreInterface):
self.session = session
if _id is None:
# from PyCoreObj
_id = ((id(self) >> 16) ^ (id(self) & 0xffff)) & 0xffff
_id = ((id(self) >> 16) ^ (id(self) & 0xFFFF)) & 0xFFFF
self.id = _id
sessionid = self.session.short_session_id()
# interface name on the local host machine
@ -452,8 +482,16 @@ class GreTap(CoreInterface):
if remoteip is None:
raise ValueError("missing remote IP required for GRE TAP device")
args = [constants.IP_BIN, "link", "add", self.localname, "type", "gretap",
"remote", str(remoteip)]
args = [
constants.IP_BIN,
"link",
"add",
self.localname,
"type",
"gretap",
"remote",
str(remoteip),
]
if localip:
args += ["local", str(localip)]
if ttl:

View file

@ -6,10 +6,8 @@ import logging
import random
import socket
import struct
from builtins import bytes
from builtins import range
from socket import AF_INET
from socket import AF_INET6
from builtins import bytes, int, range
from socket import AF_INET, AF_INET6
class MacAddress(object):
@ -45,13 +43,13 @@ class MacAddress(object):
if not self.addr:
return IpAddress.from_string("::")
tmp = struct.unpack("!Q", "\x00\x00" + self.addr)[0]
nic = long(tmp) & 0x000000FFFFFF
oui = long(tmp) & 0xFFFFFF000000
nic = int(tmp) & 0x000000FFFFFF
oui = int(tmp) & 0xFFFFFF000000
# toggle U/L bit
oui ^= 0x020000000000
# append EUI-48 octets
oui = (oui << 16) | 0xFFFE000000
return IpAddress(AF_INET6, struct.pack("!QQ", 0xfe80 << 48, oui | nic))
return IpAddress(AF_INET6, struct.pack("!QQ", 0xFE80 << 48, oui | nic))
@classmethod
def from_string(cls, s):
@ -158,7 +156,7 @@ class IpAddress(object):
tmp = [x for x in bytearray(self.addr)]
for i in range(len(tmp) - 1, -1, -1):
x = tmp[i] + carry
tmp[i] = x & 0xff
tmp[i] = x & 0xFF
carry = x >> 8
if carry == 0:
break
@ -239,7 +237,7 @@ class IpPrefix(object):
netmask = ((1 << self.prefixlen) - 1) << addrbits
prefix = bytes(b"")
for i in range(-1, -(addrbits >> 3) - 2, -1):
prefix = bytes([self.prefix[i] & (netmask & 0xff)]) + prefix
prefix = bytes([self.prefix[i] & (netmask & 0xFF)]) + prefix
netmask >>= 8
self.prefix = self.prefix[:i] + prefix
@ -265,7 +263,11 @@ class IpPrefix(object):
elif self is other:
return True
else:
return other.af == self.af and other.prefixlen == self.prefixlen and other.prefix == self.prefix
return (
other.af == self.af
and other.prefixlen == self.prefixlen
and other.prefix == self.prefix
)
def __add__(self, other):
"""
@ -316,15 +318,20 @@ class IpPrefix(object):
if tmp in [-1, 0, 1] and self.addrlen == self.prefixlen:
return IpAddress(self.af, self.prefix)
if tmp == 0 or tmp > (1 << (self.addrlen - self.prefixlen)) - 1 or (
self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1):
if (
tmp == 0
or tmp > (1 << (self.addrlen - self.prefixlen)) - 1
or (
self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1
)
):
raise ValueError("invalid hostid for prefix %s: %s" % (self, hostid))
addr = bytes(b"")
prefix_endpoint = -1
for i in range(-1, -(self.addrlen >> 3) - 1, -1):
prefix_endpoint = i
addr = bytes([self.prefix[i] | (tmp & 0xff)]) + addr
addr = bytes([self.prefix[i] | (tmp & 0xFF)]) + addr
tmp >>= 8
if not tmp:
break

View file

@ -3,7 +3,7 @@ import logging
import os
import time
from core import utils, CoreCommandError
from core import CoreCommandError, utils
from core.emulator.enumerations import NodeTypes
from core.nodes.base import CoreNode
@ -16,10 +16,9 @@ class LxdClient(object):
self._addr = {}
def create_container(self):
utils.check_cmd("lxc launch {image} {name}".format(
name=self.name,
image=self.image
))
utils.check_cmd(
"lxc launch {image} {name}".format(name=self.name, image=self.image)
)
data = self.get_info()
self.pid = data["state"]["pid"]
return self.pid
@ -31,7 +30,9 @@ class LxdClient(object):
raise CoreCommandError(status, args, output)
data = json.loads(output)
if not data:
raise CoreCommandError(status, args, "LXC({name}) not present".format(name=self.name))
raise CoreCommandError(
status, args, "LXC({name}) not present".format(name=self.name)
)
return data[0]
def is_alive(self):
@ -42,15 +43,10 @@ class LxdClient(object):
return False
def stop_container(self):
utils.check_cmd("lxc delete --force {name}".format(
name=self.name
))
utils.check_cmd("lxc delete --force {name}".format(name=self.name))
def _cmd_args(self, cmd):
return "lxc exec -nT {name} -- {cmd}".format(
name=self.name,
cmd=cmd
)
return "lxc exec -nT {name} -- {cmd}".format(name=self.name, cmd=cmd)
def cmd_output(self, cmd):
if isinstance(cmd, list):
@ -67,10 +63,7 @@ class LxdClient(object):
return utils.cmd(args, wait)
def _ns_args(self, cmd):
return "nsenter -t {pid} -m -u -i -p -n {cmd}".format(
pid=self.pid,
cmd=cmd
)
return "nsenter -t {pid} -m -u -i -p -n {cmd}".format(pid=self.pid, cmd=cmd)
def ns_cmd_output(self, cmd):
if isinstance(cmd, list):
@ -91,9 +84,7 @@ class LxdClient(object):
destination = os.path.join("/root/", destination)
args = "lxc file push {source} {name}/{destination}".format(
source=source,
name=self.name,
destination=destination
source=source, name=self.name, destination=destination
)
status, output = utils.cmd_output(args)
if status:
@ -137,7 +128,16 @@ class LxdClient(object):
class LxcNode(CoreNode):
apitype = NodeTypes.LXC.value
def __init__(self, session, _id=None, name=None, nodedir=None, bootsh="boot.sh", start=True, image=None):
def __init__(
self,
session,
_id=None,
name=None,
nodedir=None,
bootsh="boot.sh",
start=True,
image=None,
):
"""
Create a LxcNode instance.
@ -262,7 +262,7 @@ class LxcNode(CoreNode):
:return: nothing
:raises CoreCommandError: when a non-zero exit status occurs
"""
logging.info("mounting source(%s) target(%s)", source, target)
logging.debug("mounting source(%s) target(%s)", source, target)
raise Exception("not supported")
def nodefile(self, filename, contents, mode=0o644):
@ -274,8 +274,8 @@ class LxcNode(CoreNode):
:param int mode: mode for file
:return: nothing
"""
logging.info("node dir(%s) ctrlchannel(%s)", self.nodedir, self.ctrlchnlname)
logging.info("nodefile filename(%s) mode(%s)", filename, mode)
logging.debug("node dir(%s) ctrlchannel(%s)", self.nodedir, self.ctrlchnlname)
logging.debug("nodefile filename(%s) mode(%s)", filename, mode)
file_path = os.path.join(self.nodedir, filename)
with open(file_path, "w") as f:
os.chmod(f.name, mode)
@ -292,7 +292,9 @@ class LxcNode(CoreNode):
:param int mode: mode to copy to
:return: nothing
"""
logging.info("node file copy file(%s) source(%s) mode(%s)", filename, srcfilename, mode)
logging.info(
"node file copy file(%s) source(%s) mode(%s)", filename, srcfilename, mode
)
raise Exception("not supported")
def addnetif(self, netif, ifindex):

View file

@ -9,21 +9,16 @@ import threading
import time
from socket import AF_INET, AF_INET6
from core import CoreCommandError, utils
from core import constants
from core.nodes.base import CoreNetworkBase
from core import CoreCommandError, constants, utils
from core.emulator.data import LinkData
from core.emulator.enumerations import NodeTypes, LinkTypes, RegisterTlvs
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
from core.nodes import ipaddress
from core.nodes.interface import GreTap
from core.nodes.interface import Veth
from core.nodes.base import CoreNetworkBase
from core.nodes.interface import GreTap, Veth
utils.check_executables([
constants.BRCTL_BIN,
constants.IP_BIN,
constants.EBTABLES_BIN,
constants.TC_BIN
])
utils.check_executables(
[constants.BRCTL_BIN, constants.IP_BIN, constants.EBTABLES_BIN, constants.TC_BIN]
)
ebtables_lock = threading.Lock()
@ -34,6 +29,7 @@ class EbtablesQueue(object):
atomic commits. This improves performance and reliability when there are
many WLAN link updates.
"""
# update rate is every 300ms
rate = 0.3
# ebtables
@ -83,7 +79,9 @@ class EbtablesQueue(object):
try:
del self.last_update_time[wlan]
except KeyError:
logging.exception("error deleting last update time for wlan, ignored before: %s", wlan)
logging.exception(
"error deleting last update time for wlan, ignored before: %s", wlan
)
if len(self.last_update_time) > 0:
return
@ -149,7 +147,7 @@ class EbtablesQueue(object):
# TODO: if these are WlanNodes, this will never throw an exception
try:
wlan.session
except:
except Exception:
# Just mark as updated to remove from self.updates.
self.updated(wlan)
continue
@ -168,7 +166,7 @@ class EbtablesQueue(object):
:return: nothing
"""
# save kernel ebtables snapshot to a file
args = self.ebatomiccmd(["--atomic-save", ])
args = self.ebatomiccmd(["--atomic-save"])
utils.check_cmd(args)
# modify the table file using queued ebtables commands
@ -178,7 +176,7 @@ class EbtablesQueue(object):
self.cmds = []
# commit the table file to the kernel
args = self.ebatomiccmd(["--atomic-commit", ])
args = self.ebatomiccmd(["--atomic-commit"])
utils.check_cmd(args)
try:
@ -205,20 +203,60 @@ class EbtablesQueue(object):
"""
with wlan._linked_lock:
# flush the chain
self.cmds.extend([["-F", wlan.brname], ])
self.cmds.extend([["-F", wlan.brname]])
# rebuild the chain
for netif1, v in wlan._linked.items():
for netif2, linked in v.items():
if wlan.policy == "DROP" and linked:
self.cmds.extend([["-A", wlan.brname, "-i", netif1.localname,
"-o", netif2.localname, "-j", "ACCEPT"],
["-A", wlan.brname, "-o", netif1.localname,
"-i", netif2.localname, "-j", "ACCEPT"]])
self.cmds.extend(
[
[
"-A",
wlan.brname,
"-i",
netif1.localname,
"-o",
netif2.localname,
"-j",
"ACCEPT",
],
[
"-A",
wlan.brname,
"-o",
netif1.localname,
"-i",
netif2.localname,
"-j",
"ACCEPT",
],
]
)
elif wlan.policy == "ACCEPT" and not linked:
self.cmds.extend([["-A", wlan.brname, "-i", netif1.localname,
"-o", netif2.localname, "-j", "DROP"],
["-A", wlan.brname, "-o", netif1.localname,
"-i", netif2.localname, "-j", "DROP"]])
self.cmds.extend(
[
[
"-A",
wlan.brname,
"-i",
netif1.localname,
"-o",
netif2.localname,
"-j",
"DROP",
],
[
"-A",
wlan.brname,
"-o",
netif1.localname,
"-i",
netif2.localname,
"-j",
"DROP",
],
]
)
# a global object because all WLANs share the same queue
@ -243,6 +281,7 @@ class CoreNetwork(CoreNetworkBase):
"""
Provides linux bridge network functionality for core nodes.
"""
policy = "DROP"
def __init__(self, session, _id=None, name=None, start=True, policy=None):
@ -282,10 +321,21 @@ class CoreNetwork(CoreNetworkBase):
utils.check_cmd([constants.BRCTL_BIN, "setfd", self.brname, "0"])
utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "up"])
# create a new ebtables chain for this bridge
ebtablescmds(utils.check_cmd, [
[constants.EBTABLES_BIN, "-N", self.brname, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.brname, "-j", self.brname]
])
ebtablescmds(
utils.check_cmd,
[
[constants.EBTABLES_BIN, "-N", self.brname, "-P", self.policy],
[
constants.EBTABLES_BIN,
"-A",
"FORWARD",
"--logical-in",
self.brname,
"-j",
self.brname,
],
],
)
# turn off multicast snooping so mcast forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % self.brname
if os.path.exists(snoop):
@ -308,10 +358,21 @@ class CoreNetwork(CoreNetworkBase):
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "down"])
utils.check_cmd([constants.BRCTL_BIN, "delbr", self.brname])
ebtablescmds(utils.check_cmd, [
[constants.EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.brname, "-j", self.brname],
[constants.EBTABLES_BIN, "-X", self.brname]
])
ebtablescmds(
utils.check_cmd,
[
[
constants.EBTABLES_BIN,
"-D",
"FORWARD",
"--logical-in",
self.brname,
"-j",
self.brname,
],
[constants.EBTABLES_BIN, "-X", self.brname],
],
)
except CoreCommandError:
logging.exception("error during shutdown")
@ -333,7 +394,9 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing
"""
if self.up:
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, netif.localname])
utils.check_cmd(
[constants.BRCTL_BIN, "addif", self.brname, netif.localname]
)
utils.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "up"])
CoreNetworkBase.attach(self, netif)
@ -346,7 +409,9 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing
"""
if self.up:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, netif.localname])
utils.check_cmd(
[constants.BRCTL_BIN, "delif", self.brname, netif.localname]
)
CoreNetworkBase.detach(self, netif)
@ -411,8 +476,17 @@ class CoreNetwork(CoreNetworkBase):
ebq.ebchange(self)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None,
jitter=None, netif2=None, devname=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
devname=None,
):
"""
Configure link parameters by applying tc queuing disciplines on the interface.
@ -436,12 +510,13 @@ class CoreNetwork(CoreNetworkBase):
if bw is not None:
burst = max(2 * netif.mtu, bw / 1000)
# max IP payload
limit = 0xffff
tbf = ["tbf", "rate", str(bw),
"burst", str(burst), "limit", str(limit)]
limit = 0xFFFF
tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)]
if bw > 0:
if self.up:
logging.debug("linkconfig: %s" % ([tc + parent + ["handle", "1:"] + tbf],))
logging.debug(
"linkconfig: %s" % ([tc + parent + ["handle", "1:"] + tbf],)
)
utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
netif.setparam("has_tbf", True)
changed = True
@ -496,7 +571,9 @@ class CoreNetwork(CoreNetworkBase):
netif.setparam("has_netem", False)
elif len(netem) > 1:
if self.up:
logging.debug("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],))
logging.debug(
"linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)
)
utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
netif.setparam("has_netem", True)
@ -528,7 +605,9 @@ class CoreNetwork(CoreNetworkBase):
if len(name) >= 16:
raise ValueError("interface name %s too long" % name)
netif = Veth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
netif = Veth(
node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up
)
self.attach(netif)
if net.up:
# this is similar to net.attach() but uses netif.name instead
@ -569,7 +648,9 @@ class CoreNetwork(CoreNetworkBase):
return
for addr in addrlist:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname]
)
class GreTapBridge(CoreNetwork):
@ -578,8 +659,18 @@ class GreTapBridge(CoreNetwork):
another system.
"""
def __init__(self, session, remoteip=None, _id=None, name=None,
policy="ACCEPT", localip=None, ttl=255, key=None, start=True):
def __init__(
self,
session,
remoteip=None,
_id=None,
name=None,
policy="ACCEPT",
localip=None,
ttl=255,
key=None,
start=True,
):
"""
Create a GreTapBridge instance.
@ -593,7 +684,9 @@ class GreTapBridge(CoreNetwork):
:param key: gre tap key
:param bool start: start flag
"""
CoreNetwork.__init__(self, session=session, _id=_id, name=name, policy=policy, start=False)
CoreNetwork.__init__(
self, session=session, _id=_id, name=name, policy=policy, start=False
)
self.grekey = key
if self.grekey is None:
self.grekey = self.session.id ^ self.id
@ -605,8 +698,14 @@ class GreTapBridge(CoreNetwork):
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(node=self, session=session, remoteip=remoteip,
localip=localip, ttl=ttl, key=self.grekey)
self.gretap = GreTap(
node=self,
session=session,
remoteip=remoteip,
localip=localip,
ttl=ttl,
key=self.grekey,
)
if start:
self.startup()
@ -648,8 +747,13 @@ class GreTapBridge(CoreNetwork):
localip = None
if len(addrlist) > 1:
localip = addrlist[1].split("/")[0]
self.gretap = GreTap(session=self.session, remoteip=remoteip,
localip=localip, ttl=self.ttl, key=self.grekey)
self.gretap = GreTap(
session=self.session,
remoteip=remoteip,
localip=localip,
ttl=self.ttl,
key=self.grekey,
)
self.attach(self.gretap)
def setkey(self, key):
@ -667,6 +771,7 @@ class CtrlNet(CoreNetwork):
"""
Control network functionality.
"""
policy = "ACCEPT"
# base control interface index
CTRLIF_IDX_BASE = 99
@ -674,12 +779,21 @@ class CtrlNet(CoreNetwork):
"172.16.0.0/24 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 172.16.4.0/24",
"172.17.0.0/24 172.17.1.0/24 172.17.2.0/24 172.17.3.0/24 172.17.4.0/24",
"172.18.0.0/24 172.18.1.0/24 172.18.2.0/24 172.18.3.0/24 172.18.4.0/24",
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24"
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24",
]
def __init__(self, session, _id="ctrlnet", name=None, prefix=None,
hostid=None, start=True, assign_address=True,
updown_script=None, serverintf=None):
def __init__(
self,
session,
_id="ctrlnet",
name=None,
prefix=None,
hostid=None,
start=True,
assign_address=True,
updown_script=None,
serverintf=None,
):
"""
Creates a CtrlNet instance.
@ -726,12 +840,18 @@ class CtrlNet(CoreNetwork):
logging.info("address %s", addr)
if self.updown_script:
logging.info("interface %s updown script (%s startup) called", self.brname, self.updown_script)
logging.info(
"interface %s updown script (%s startup) called",
self.brname,
self.updown_script,
)
utils.check_cmd([self.updown_script, self.brname, "startup"])
if self.serverintf:
# sets the interface as a port of the bridge
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, self.serverintf])
utils.check_cmd(
[constants.BRCTL_BIN, "addif", self.brname, self.serverintf]
)
# bring interface up
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
@ -758,7 +878,9 @@ class CtrlNet(CoreNetwork):
logging.error(
"error: An active control net bridge (%s) found. "
"An older session might still be running. "
"Stop all sessions and, if needed, delete %s to continue.", oldbr, oldbr
"Stop all sessions and, if needed, delete %s to continue.",
oldbr,
oldbr,
)
return True
return False
@ -771,13 +893,23 @@ class CtrlNet(CoreNetwork):
"""
if self.serverintf is not None:
try:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf])
utils.check_cmd(
[constants.BRCTL_BIN, "delif", self.brname, self.serverintf]
)
except CoreCommandError:
logging.exception("error deleting server interface %s from bridge %s", self.serverintf, self.brname)
logging.exception(
"error deleting server interface %s from bridge %s",
self.serverintf,
self.brname,
)
if self.updown_script is not None:
try:
logging.info("interface %s updown script (%s shutdown) called", self.brname, self.updown_script)
logging.info(
"interface %s updown script (%s shutdown) called",
self.brname,
self.updown_script,
)
utils.check_cmd([self.updown_script, self.brname, "shutdown"])
except CoreCommandError:
logging.exception("error issuing shutdown script shutdown")
@ -799,6 +931,7 @@ class PtpNet(CoreNetwork):
"""
Peer to peer network node.
"""
policy = "ACCEPT"
def attach(self, netif):
@ -809,7 +942,9 @@ class PtpNet(CoreNetwork):
:return: nothing
"""
if len(self._netif) >= 2:
raise ValueError("Point-to-point links support at most 2 network interfaces")
raise ValueError(
"Point-to-point links support at most 2 network interfaces"
)
CoreNetwork.attach(self, netif)
@ -924,7 +1059,7 @@ class PtpNet(CoreNetwork):
jitter=if2.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1)
interface2_id=if1.node.getifindex(if1),
)
all_links.append(link_data)
@ -935,6 +1070,7 @@ class SwitchNode(CoreNetwork):
"""
Provides switch functionality within a core node.
"""
apitype = NodeTypes.SWITCH.value
policy = "ACCEPT"
type = "lanswitch"
@ -945,6 +1081,7 @@ class HubNode(CoreNetwork):
Provides hub functionality within a core node, forwards packets to all bridge
ports by turning off MAC address learning.
"""
apitype = NodeTypes.HUB.value
policy = "ACCEPT"
type = "hub"
@ -970,6 +1107,7 @@ class WlanNode(CoreNetwork):
"""
Provides wireless lan functionality within a core node.
"""
apitype = NodeTypes.WIRELESS_LAN.value
linktype = LinkTypes.WIRELESS.value
policy = "DROP"
@ -1015,9 +1153,14 @@ class WlanNode(CoreNetwork):
:param dict config: configuration for model being set
:return: nothing
"""
logging.info("adding model: %s", model.name)
logging.debug("node(%s) setting model: %s", self.name, model.name)
if model.config_type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, _id=self.id)
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.poshook and netif.node:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.updatemodel(config)
elif model.config_type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, _id=self.id)
@ -1031,14 +1174,14 @@ class WlanNode(CoreNetwork):
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.id)
logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config)
logging.debug(
"node(%s) updating model(%s): %s", self.id, self.model.name, config
)
self.model.update_config(config)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
for netif in self.netifs():
if netif.poshook and netif.node:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
def all_link_data(self, flags):
"""
@ -1060,6 +1203,7 @@ class TunnelNode(GreTapBridge):
"""
Provides tunnel functionality in a core node.
"""
apitype = NodeTypes.TUNNEL.value
policy = "ACCEPT"
type = "tunnel"

View file

@ -6,11 +6,10 @@ import core.nodes.docker
import core.nodes.lxd
import core.nodes.network
import core.nodes.physical
from core.emane.nodes import EmaneNet
from core.emane.nodes import EmaneNode
from core.emane.nodes import EmaneNet, EmaneNode
from core.emulator.enumerations import NodeTypes
from core.nodes.network import GreTapBridge
from core.nodes import physical
from core.nodes.network import GreTapBridge
# legacy core nodes, that leverage linux bridges
NODES = {
@ -29,5 +28,5 @@ NODES = {
NodeTypes.PEER_TO_PEER: core.nodes.network.PtpNet,
NodeTypes.CONTROL_NET: core.nodes.network.CtrlNet,
NodeTypes.DOCKER: core.nodes.docker.DockerNode,
NodeTypes.LXC: core.nodes.lxd.LxcNode
NodeTypes.LXC: core.nodes.lxd.LxcNode,
}

View file

@ -5,21 +5,15 @@ TODO: probably goes away, or implement the usage of "unshare", or docker formal.
import logging
import socket
import threading
from socket import AF_INET
from socket import AF_INET6
from socket import AF_INET, AF_INET6
from core import CoreCommandError, utils
from core import constants
from core.nodes.base import CoreNetworkBase
from core import CoreCommandError, constants, utils
from core.emulator.data import LinkData
from core.emulator.enumerations import LinkTypes
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
from core.nodes import ipaddress
from core.nodes.interface import GreTap
from core.nodes.interface import Veth
from core.nodes.network import EbtablesQueue
from core.nodes.network import GreTapBridge
from core.nodes.base import CoreNetworkBase
from core.nodes.interface import GreTap, Veth
from core.nodes.network import EbtablesQueue, GreTapBridge
# a global object because all WLANs share the same queue
# cannot have multiple threads invoking the ebtables commnd
@ -27,11 +21,7 @@ ebtables_queue = EbtablesQueue()
ebtables_lock = threading.Lock()
utils.check_executables([
constants.IP_BIN,
constants.EBTABLES_BIN,
constants.TC_BIN
])
utils.check_executables([constants.IP_BIN, constants.EBTABLES_BIN, constants.TC_BIN])
def ebtables_commands(call, commands):
@ -89,10 +79,21 @@ class OvsNet(CoreNetworkBase):
utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "up"])
# create a new ebtables chain for this bridge
ebtables_commands(utils.check_cmd, [
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name]
])
ebtables_commands(
utils.check_cmd,
[
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[
constants.EBTABLES_BIN,
"-A",
"FORWARD",
"--logical-in",
self.bridge_name,
"-j",
self.bridge_name,
],
],
)
self.up = True
@ -106,10 +107,21 @@ class OvsNet(CoreNetworkBase):
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "down"])
utils.check_cmd([constants.OVS_BIN, "del-br", self.bridge_name])
ebtables_commands(utils.check_cmd, [
[constants.EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name],
[constants.EBTABLES_BIN, "-X", self.bridge_name]
])
ebtables_commands(
utils.check_cmd,
[
[
constants.EBTABLES_BIN,
"-D",
"FORWARD",
"--logical-in",
self.bridge_name,
"-j",
self.bridge_name,
],
[constants.EBTABLES_BIN, "-X", self.bridge_name],
],
)
except CoreCommandError:
logging.exception("error bringing bridge down and removing it")
@ -124,14 +136,20 @@ class OvsNet(CoreNetworkBase):
def attach(self, interface):
if self.up:
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, interface.localname])
utils.check_cmd([constants.IP_BIN, "link", "set", interface.localname, "up"])
utils.check_cmd(
[constants.OVS_BIN, "add-port", self.bridge_name, interface.localname]
)
utils.check_cmd(
[constants.IP_BIN, "link", "set", interface.localname, "up"]
)
CoreNetworkBase.attach(self, interface)
def detach(self, interface):
if self.up:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, interface.localname])
utils.check_cmd(
[constants.OVS_BIN, "del-port", self.bridge_name, interface.localname]
)
CoreNetworkBase.detach(self, interface)
@ -183,8 +201,17 @@ class OvsNet(CoreNetworkBase):
ebtables_queue.ebchange(self)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None,
jitter=None, netif2=None, devname=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
devname=None,
):
"""
Configure link parameters by applying tc queuing disciplines on the
interface.
@ -202,9 +229,19 @@ class OvsNet(CoreNetworkBase):
if bw > 0:
if self.up:
burst = max(2 * netif.mtu, bw / 1000)
limit = 0xffff # max IP payload
tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)]
logging.info("linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf])
limit = 0xFFFF # max IP payload
tbf = [
"tbf",
"rate",
str(bw),
"burst",
str(burst),
"limit",
str(limit),
]
logging.info(
"linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf]
)
utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
netif.setparam("has_tbf", True)
elif netif.getparam("has_tbf") and bw <= 0:
@ -234,7 +271,15 @@ class OvsNet(CoreNetworkBase):
jitter_changed = netif.setparam("jitter", jitter)
# if nothing changed return
if not any([bandwidth_changed, delay_changed, loss_changed, duplicate_changed, jitter_changed]):
if not any(
[
bandwidth_changed,
delay_changed,
loss_changed,
duplicate_changed,
jitter_changed,
]
):
return
# jitter and delay use the same delay statement
@ -265,7 +310,9 @@ class OvsNet(CoreNetworkBase):
netif.setparam("has_netem", False)
elif len(netem) > 1:
if self.up:
logging.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],))
logging.info(
"linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)
)
utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
netif.setparam("has_netem", True)
@ -295,11 +342,15 @@ class OvsNet(CoreNetworkBase):
if len(name) >= 16:
raise ValueError("interface name %s too long" % name)
interface = Veth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
interface = Veth(
node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up
)
self.attach(interface)
if network.up:
# this is similar to net.attach() but uses netif.name instead of localname
utils.check_cmd([constants.OVS_BIN, "add-port", network.bridge_name, interface.name])
utils.check_cmd(
[constants.OVS_BIN, "add-port", network.bridge_name, interface.name]
)
utils.check_cmd([constants.IP_BIN, "link", "set", interface.name, "up"])
network.attach(interface)
@ -326,7 +377,9 @@ class OvsNet(CoreNetworkBase):
return
for address in addresses:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name]
)
class OvsCtrlNet(OvsNet):
@ -336,11 +389,21 @@ class OvsCtrlNet(OvsNet):
"172.16.0.0/24 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 172.16.4.0/24",
"172.17.0.0/24 172.17.1.0/24 172.17.2.0/24 172.17.3.0/24 172.17.4.0/24",
"172.18.0.0/24 172.18.1.0/24 172.18.2.0/24 172.18.3.0/24 172.18.4.0/24",
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24"
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24",
]
def __init__(self, session, _id="ctrlnet", name=None, prefix=None, hostid=None,
start=True, assign_address=True, updown_script=None, serverintf=None):
def __init__(
self,
session,
_id="ctrlnet",
name=None,
prefix=None,
hostid=None,
start=True,
assign_address=True,
updown_script=None,
serverintf=None,
):
self.prefix = ipaddress.Ipv4Prefix(prefix)
self.hostid = hostid
self.assign_address = assign_address
@ -358,7 +421,10 @@ class OvsCtrlNet(OvsNet):
else:
addr = self.prefix.max_addr()
message = "Added control network bridge: %s %s" % (self.bridge_name, self.prefix)
message = "Added control network bridge: %s %s" % (
self.bridge_name,
self.prefix,
)
addresses = ["%s/%s" % (addr, self.prefix.prefixlen)]
if self.assign_address:
self.addrconfig(addresses=addresses)
@ -366,11 +432,16 @@ class OvsCtrlNet(OvsNet):
logging.info(message)
if self.updown_script:
logging.info("interface %s updown script %s startup called" % (self.bridge_name, self.updown_script))
logging.info(
"interface %s updown script %s startup called"
% (self.bridge_name, self.updown_script)
)
utils.check_cmd([self.updown_script, self.bridge_name, "startup"])
if self.serverintf:
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf])
utils.check_cmd(
[constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf]
)
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
def detectoldbridge(self):
@ -385,7 +456,10 @@ class OvsCtrlNet(OvsNet):
for line in output.split("\n"):
bride_name = line.split(".")
if bride_name[0] == "b" and bride_name[1] == self.id:
logging.error("older session may still be running with conflicting id for bridge: %s", line)
logging.error(
"older session may still be running with conflicting id for bridge: %s",
line,
)
return True
return False
@ -393,14 +467,23 @@ class OvsCtrlNet(OvsNet):
def shutdown(self):
if self.serverintf:
try:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf])
utils.check_cmd(
[constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf]
)
except CoreCommandError:
logging.exception("error deleting server interface %s to controlnet bridge %s",
self.serverintf, self.bridge_name)
logging.exception(
"error deleting server interface %s to controlnet bridge %s",
self.serverintf,
self.bridge_name,
)
if self.updown_script:
try:
logging.info("interface %s updown script (%s shutdown) called", self.bridge_name, self.updown_script)
logging.info(
"interface %s updown script (%s shutdown) called",
self.bridge_name,
self.updown_script,
)
utils.check_cmd([self.updown_script, self.bridge_name, "shutdown"])
except CoreCommandError:
logging.exception("error during updown script shutdown")
@ -419,7 +502,9 @@ class OvsPtpNet(OvsNet):
def attach(self, interface):
if len(self._netif) >= 2:
raise ValueError("point-to-point links support at most 2 network interfaces")
raise ValueError(
"point-to-point links support at most 2 network interfaces"
)
OvsNet.attach(self, interface)
def data(self, message_type, lat=None, lon=None, alt=None):
@ -522,7 +607,7 @@ class OvsPtpNet(OvsNet):
jitter=if1.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1)
interface2_id=if1.node.getifindex(if1),
)
all_links.append(link_data)
@ -550,7 +635,9 @@ class OvsHubNode(OvsNet):
if start:
# TODO: verify that the below flow accomplishes what is desired for a "HUB"
# TODO: replace "brctl setageing 0"
utils.check_cmd([constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"])
utils.check_cmd(
[constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"]
)
class OvsWlanNode(OvsNet):
@ -602,7 +689,9 @@ class OvsWlanNode(OvsNet):
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.id)
logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config)
logging.info(
"node(%s) updating model(%s): %s", self.id, self.model.name, config
)
self.model.set_configs(config, node_id=self.id)
if self.model.position_callback:
for netif in self.netifs():
@ -633,9 +722,21 @@ class OvsGreTapBridge(OvsNet):
another system.
"""
def __init__(self, session, remoteip=None, _id=None, name=None, policy="ACCEPT",
localip=None, ttl=255, key=None, start=True):
OvsNet.__init__(self, session=session, _id=_id, name=name, policy=policy, start=False)
def __init__(
self,
session,
remoteip=None,
_id=None,
name=None,
policy="ACCEPT",
localip=None,
ttl=255,
key=None,
start=True,
):
OvsNet.__init__(
self, session=session, _id=_id, name=name, policy=policy, start=False
)
self.grekey = key
if self.grekey is None:
self.grekey = self.session.id ^ self.id
@ -649,8 +750,14 @@ class OvsGreTapBridge(OvsNet):
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(node=self, session=session, remoteip=remoteip,
localip=localip, ttl=ttl, key=self.grekey)
self.gretap = GreTap(
node=self,
session=session,
remoteip=remoteip,
localip=localip,
ttl=ttl,
key=self.grekey,
)
if start:
self.startup()
@ -690,8 +797,13 @@ class OvsGreTapBridge(OvsNet):
if len(addresses) > 1:
localip = addresses[1].split("/")[0]
self.gretap = GreTap(session=self.session, remoteip=remoteip,
localip=localip, ttl=self.ttl, key=self.grekey)
self.gretap = GreTap(
session=self.session,
remoteip=remoteip,
localip=localip,
ttl=self.ttl,
key=self.grekey,
)
self.attach(self.gretap)
def setkey(self, key):
@ -709,5 +821,5 @@ OVS_NODES = {
NodeTypes.TUNNEL: OvsTunnelNode,
NodeTypes.TAP_BRIDGE: OvsGreTapBridge,
NodeTypes.PEER_TO_PEER: OvsPtpNet,
NodeTypes.CONTROL_NET: OvsCtrlNet
NodeTypes.CONTROL_NET: OvsCtrlNet,
}

View file

@ -7,13 +7,11 @@ import os
import subprocess
import threading
from core import CoreCommandError, utils
from core import constants
from core import CoreCommandError, constants, utils
from core.emulator.enumerations import NodeTypes
from core.nodes.base import CoreNodeBase
from core.nodes.interface import CoreInterface
from core.emulator.enumerations import NodeTypes
from core.nodes.network import GreTap
from core.nodes.network import CoreNetwork
from core.nodes.network import CoreNetwork, GreTap
class PhysicalNode(CoreNodeBase):
@ -104,14 +102,25 @@ class PhysicalNode(CoreNodeBase):
self._netif[ifindex].sethwaddr(addr)
ifname = self.ifname(ifindex)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", ifname, "address", str(addr)])
self.check_cmd(
[constants.IP_BIN, "link", "set", "dev", ifname, "address", str(addr)]
)
def addaddr(self, ifindex, addr):
"""
Add an address to an interface.
"""
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)])
self.check_cmd(
[
constants.IP_BIN,
"addr",
"add",
str(addr),
"dev",
self.ifname(ifindex),
]
)
self._netif[ifindex].addaddr(addr)
@ -125,7 +134,16 @@ class PhysicalNode(CoreNodeBase):
logging.exception("trying to delete unknown address: %s", addr)
if self.up:
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
self.check_cmd(
[
constants.IP_BIN,
"addr",
"del",
str(addr),
"dev",
self.ifname(ifindex),
]
)
def adoptnetif(self, netif, ifindex, hwaddr, addrlist):
"""
@ -140,8 +158,12 @@ class PhysicalNode(CoreNodeBase):
# use a more reasonable name, e.g. "gt0" instead of "gt.56286.150"
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "down"])
self.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "name", netif.name])
self.check_cmd(
[constants.IP_BIN, "link", "set", "dev", netif.localname, "down"]
)
self.check_cmd(
[constants.IP_BIN, "link", "set", netif.localname, "name", netif.name]
)
netif.localname = netif.name
@ -152,16 +174,35 @@ class PhysicalNode(CoreNodeBase):
self.addaddr(ifindex, addr)
if self.up:
self.check_cmd([constants.IP_BIN, "link", "set", "dev", netif.localname, "up"])
self.check_cmd(
[constants.IP_BIN, "link", "set", "dev", netif.localname, "up"]
)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
):
"""
Apply tc queing disciplines using LxBrNet.linkconfig()
"""
# borrow the tc qdisc commands from LxBrNet.linkconfig()
linux_bridge = CoreNetwork(session=self.session, start=False)
linux_bridge.up = True
linux_bridge.linkconfig(netif, bw=bw, delay=delay, loss=loss, duplicate=duplicate, jitter=jitter, netif2=netif2)
linux_bridge.linkconfig(
netif,
bw=bw,
delay=delay,
loss=loss,
duplicate=duplicate,
jitter=jitter,
netif2=netif2,
)
del linux_bridge
def newifindex(self):
@ -188,7 +229,9 @@ class PhysicalNode(CoreNodeBase):
# tunnel to net not built yet, so build it now and adopt it
gt = self.session.broker.addnettunnel(net.id)
if gt is None or len(gt) != 1:
raise ValueError("error building tunnel from adding a new network interface: %s" % gt)
raise ValueError(
"error building tunnel from adding a new network interface: %s" % gt
)
gt = gt[0]
net.detach(gt)
self.adoptnetif(gt, ifindex, hwaddr, addrlist)
@ -205,7 +248,9 @@ class PhysicalNode(CoreNodeBase):
def privatedir(self, path):
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % 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("/", ".")
)
os.mkdir(hostpath)
self.mount(hostpath, path)
@ -251,6 +296,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
RJ45Node is a physical interface on the host linked to the emulated
network.
"""
apitype = NodeTypes.RJ45.value
type = "rj45"
@ -304,7 +350,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "down"])
utils.check_cmd([constants.IP_BIN, "addr", "flush", "dev", self.localname])
utils.check_cmd([constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"])
utils.check_cmd(
[constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"]
)
except CoreCommandError:
logging.exception("error shutting down")
@ -427,7 +475,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.name]
)
CoreInterface.addaddr(self, addr)
@ -440,7 +490,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
:raises CoreCommandError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name])
utils.check_cmd(
[constants.IP_BIN, "addr", "del", str(addr), "dev", self.name]
)
CoreInterface.deladdr(self, addr)
@ -481,9 +533,22 @@ class Rj45Node(CoreNodeBase, CoreInterface):
"""
for addr in self.old_addrs:
if addr[1] is None:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname])
utils.check_cmd(
[constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname]
)
else:
utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "brd", addr[1], "dev", self.localname])
utils.check_cmd(
[
constants.IP_BIN,
"addr",
"add",
addr[0],
"brd",
addr[1],
"dev",
self.localname,
]
)
if self.old_up:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])