Merge branch 'develop' into pydocupdates
This commit is contained in:
commit
2bfcc9ef24
100 changed files with 5340 additions and 3488 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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"])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue