Merge pull request #298 from coreemu/cleanup/node-client
Cleanup/node client
This commit is contained in:
commit
478eb84786
10 changed files with 349 additions and 589 deletions
|
@ -7,7 +7,7 @@ import logging
|
|||
import os
|
||||
import threading
|
||||
|
||||
from core import constants, utils
|
||||
from core import utils
|
||||
from core.api.tlv import coreapi, dataconversion
|
||||
from core.config import ConfigGroup, ConfigShim, Configuration, ModelManager
|
||||
from core.emane import emanemanifest
|
||||
|
@ -733,13 +733,11 @@ class EmaneManager(ModelManager):
|
|||
)
|
||||
|
||||
# multicast route is needed for OTA data
|
||||
args = [constants.IP_BIN, "route", "add", otagroup, "dev", otadev]
|
||||
node.network_cmd(args)
|
||||
node.node_net_client.create_route(otagroup, otadev)
|
||||
|
||||
# multicast route is also needed for event data if on control network
|
||||
if eventservicenetidx >= 0 and eventgroup != otagroup:
|
||||
args = [constants.IP_BIN, "route", "add", eventgroup, "dev", eventdev]
|
||||
node.network_cmd(args)
|
||||
node.node_net_client.create_route(eventgroup, eventdev)
|
||||
|
||||
# start emane
|
||||
args = emanecmd + [
|
||||
|
|
|
@ -17,7 +17,6 @@ from socket import AF_INET, AF_INET6
|
|||
from core import constants, utils
|
||||
from core.emulator.data import LinkData, NodeData
|
||||
from core.emulator.enumerations import LinkTypes, NodeTypes
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes import client, ipaddress
|
||||
from core.nodes.interface import CoreInterface, TunTap, Veth
|
||||
from core.nodes.netclient import LinuxNetClient, OvsNetClient
|
||||
|
@ -54,7 +53,7 @@ class NodeBase(object):
|
|||
self.type = None
|
||||
self.server = None
|
||||
self.services = None
|
||||
# ifindex is key, PyCoreNetIf instance is value
|
||||
# ifindex is key, CoreInterface instance is value
|
||||
self._netif = {}
|
||||
self.ifindex = 0
|
||||
self.canvas = None
|
||||
|
@ -62,6 +61,11 @@ class NodeBase(object):
|
|||
self.opaque = None
|
||||
self.position = Position()
|
||||
|
||||
if session.options.get_config("ovs") == "True":
|
||||
self.net_client = OvsNetClient(self.net_cmd)
|
||||
else:
|
||||
self.net_client = LinuxNetClient(self.net_cmd)
|
||||
|
||||
def startup(self):
|
||||
"""
|
||||
Each object implements its own startup method.
|
||||
|
@ -78,6 +82,18 @@ class NodeBase(object):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def net_cmd(self, args):
|
||||
"""
|
||||
Runs a command that is used to configure and setup the network on the host
|
||||
system.
|
||||
|
||||
:param list[str]|str args: command to run
|
||||
:return: combined stdout and stderr
|
||||
:rtype: str
|
||||
:raises CoreCommandError: when a non-zero exit status occurs
|
||||
"""
|
||||
return utils.check_cmd(args)
|
||||
|
||||
def setposition(self, x=None, y=None, z=None):
|
||||
"""
|
||||
Set the (x,y,z) position of the object.
|
||||
|
@ -360,6 +376,18 @@ class CoreNodeBase(NodeBase):
|
|||
|
||||
return common
|
||||
|
||||
def node_net_cmd(self, args):
|
||||
"""
|
||||
Runs a command that is used to configure and setup the network within a
|
||||
node.
|
||||
|
||||
:param list[str]|str args: command to run
|
||||
:return: combined stdout and stderr
|
||||
:rtype: str
|
||||
:raises CoreCommandError: when a non-zero exit status occurs
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def check_cmd(self, args):
|
||||
"""
|
||||
Runs shell command on node.
|
||||
|
@ -434,6 +462,12 @@ class CoreNode(CoreNodeBase):
|
|||
self.lock = threading.RLock()
|
||||
self._mounts = []
|
||||
self.bootsh = bootsh
|
||||
|
||||
if session.options.get_config("ovs") == "True":
|
||||
self.node_net_client = OvsNetClient(self.node_net_cmd)
|
||||
else:
|
||||
self.node_net_client = LinuxNetClient(self.node_net_cmd)
|
||||
|
||||
if start:
|
||||
self.startup()
|
||||
|
||||
|
@ -489,11 +523,11 @@ class CoreNode(CoreNodeBase):
|
|||
|
||||
# bring up the loopback interface
|
||||
logging.debug("bringing up loopback interface")
|
||||
self.network_cmd([constants.IP_BIN, "link", "set", "lo", "up"])
|
||||
self.node_net_client.device_up("lo")
|
||||
|
||||
# set hostname for node
|
||||
logging.debug("setting hostname: %s", self.name)
|
||||
self.network_cmd(["hostname", self.name])
|
||||
self.node_net_client.set_hostname(self.name)
|
||||
|
||||
# mark node as up
|
||||
self.up = True
|
||||
|
@ -568,9 +602,10 @@ class CoreNode(CoreNodeBase):
|
|||
"""
|
||||
return self.client.cmd_output(args)
|
||||
|
||||
def network_cmd(self, args):
|
||||
def node_net_cmd(self, args):
|
||||
"""
|
||||
Runs a command for a node that is used to configure and setup network interfaces.
|
||||
Runs a command that is used to configure and setup the network within a
|
||||
node.
|
||||
|
||||
:param list[str]|str args: command to run
|
||||
:return: combined stdout and stderr
|
||||
|
@ -625,15 +660,8 @@ class CoreNode(CoreNodeBase):
|
|||
"""
|
||||
source = os.path.abspath(source)
|
||||
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)
|
||||
self.client.check_cmd(["mkdir", "-p", target])
|
||||
self.client.check_cmd([constants.MOUNT_BIN, "-n", "--bind", source, target])
|
||||
self._mounts.append((source, target))
|
||||
|
||||
def newifindex(self):
|
||||
|
@ -682,22 +710,16 @@ class CoreNode(CoreNodeBase):
|
|||
)
|
||||
|
||||
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"]
|
||||
)
|
||||
self.net_client.device_ns(veth.name, str(self.pid))
|
||||
self.node_net_client.device_name(veth.name, ifname)
|
||||
self.node_net_client.checksums_off(ifname)
|
||||
|
||||
veth.name = ifname
|
||||
|
||||
if self.up:
|
||||
# TODO: potentially find better way to query interface ID
|
||||
# retrieve interface information
|
||||
output = self.network_cmd([constants.IP_BIN, "link", "show", veth.name])
|
||||
output = self.node_net_client.device_show(veth.name)
|
||||
logging.debug("interface command output: %s", output)
|
||||
output = output.split("\n")
|
||||
veth.flow_id = int(output[0].strip().split(":")[0]) + 1
|
||||
|
@ -707,7 +729,8 @@ class CoreNode(CoreNodeBase):
|
|||
logging.debug("interface mac: %s - %s", veth.name, veth.hwaddr)
|
||||
|
||||
try:
|
||||
# add network interface to the node. If unsuccessful, destroy the network interface and raise exception.
|
||||
# add network interface to the node. If unsuccessful, destroy the
|
||||
# network interface and raise exception.
|
||||
self.addnetif(veth, ifindex)
|
||||
except ValueError as e:
|
||||
veth.shutdown()
|
||||
|
@ -758,105 +781,47 @@ class CoreNode(CoreNodeBase):
|
|||
:return: nothing
|
||||
:raises CoreCommandError: when a non-zero exit status occurs
|
||||
"""
|
||||
self._netif[ifindex].sethwaddr(addr)
|
||||
interface = self._netif[ifindex]
|
||||
interface.sethwaddr(addr)
|
||||
if self.up:
|
||||
args = [
|
||||
constants.IP_BIN,
|
||||
"link",
|
||||
"set",
|
||||
"dev",
|
||||
self.ifname(ifindex),
|
||||
"address",
|
||||
str(addr),
|
||||
]
|
||||
self.network_cmd(args)
|
||||
self.node_net_client.device_mac(interface.name, str(addr))
|
||||
|
||||
def addaddr(self, ifindex, addr):
|
||||
"""
|
||||
Add interface address.
|
||||
|
||||
:param int ifindex: index of interface to add address to
|
||||
:param str addr: address to add to interface
|
||||
:param core.nodes.ipaddress.IpAddress addr: address to add to interface
|
||||
:return: nothing
|
||||
"""
|
||||
interface = self._netif[ifindex]
|
||||
interface.addaddr(addr)
|
||||
if self.up:
|
||||
# check if addr is ipv6
|
||||
if ":" in str(addr):
|
||||
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),
|
||||
]
|
||||
self.network_cmd(args)
|
||||
|
||||
self._netif[ifindex].addaddr(addr)
|
||||
address = str(addr)
|
||||
# ipv6 check
|
||||
broadcast = None
|
||||
if ":" not in address:
|
||||
broadcast = "+"
|
||||
self.node_net_client.create_address(interface.name, address, broadcast)
|
||||
|
||||
def deladdr(self, ifindex, addr):
|
||||
"""
|
||||
Delete address from an interface.
|
||||
|
||||
:param int ifindex: index of interface to delete address from
|
||||
:param str addr: address to delete from interface
|
||||
:param core.nodes.ipaddress.IpAddress addr: address to delete from interface
|
||||
:return: nothing
|
||||
:raises CoreCommandError: when a non-zero exit status occurs
|
||||
"""
|
||||
interface = self._netif[ifindex]
|
||||
|
||||
try:
|
||||
self._netif[ifindex].deladdr(addr)
|
||||
interface.deladdr(addr)
|
||||
except ValueError:
|
||||
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),
|
||||
]
|
||||
)
|
||||
|
||||
def delalladdr(self, ifindex, address_types=None):
|
||||
"""
|
||||
Delete all addresses from an interface.
|
||||
|
||||
:param int ifindex: index of interface to delete address types from
|
||||
:param tuple[str] address_types: address types to delete
|
||||
:return: nothing
|
||||
:raises CoreCommandError: when a non-zero exit status occurs
|
||||
"""
|
||||
if not address_types:
|
||||
address_types = self.valid_address_types
|
||||
|
||||
interface_name = self.ifname(ifindex)
|
||||
addresses = self.client.getaddr(interface_name, rescan=True)
|
||||
|
||||
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)
|
||||
)
|
||||
for address in addresses[address_type]:
|
||||
self.deladdr(ifindex, address)
|
||||
|
||||
# update cached information
|
||||
self.client.getaddr(interface_name, rescan=True)
|
||||
self.node_net_client.delete_address(interface.name, str(addr))
|
||||
|
||||
def ifup(self, ifindex):
|
||||
"""
|
||||
|
@ -866,9 +831,8 @@ class CoreNode(CoreNodeBase):
|
|||
:return: nothing
|
||||
"""
|
||||
if self.up:
|
||||
self.network_cmd(
|
||||
[constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"]
|
||||
)
|
||||
interface_name = self.ifname(ifindex)
|
||||
self.node_net_client.device_up(interface_name)
|
||||
|
||||
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
|
||||
"""
|
||||
|
@ -919,7 +883,7 @@ class CoreNode(CoreNodeBase):
|
|||
Connect a node.
|
||||
|
||||
:param str ifname: name of interface to connect
|
||||
:param core.nodes.CoreNodeBase othernode: node to connect to
|
||||
:param core.nodes.base.CoreNode othernode: node to connect to
|
||||
:param str otherifname: interface name to connect to
|
||||
:return: nothing
|
||||
"""
|
||||
|
@ -930,32 +894,14 @@ class CoreNode(CoreNodeBase):
|
|||
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])
|
||||
self.net_client.create_veth(tmp1, tmp2)
|
||||
self.net_client.device_ns(tmp1, str(self.pid))
|
||||
self.node_net_client.device_name(tmp1, 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]
|
||||
)
|
||||
self.net_client.device_ns(tmp2, str(othernode.pid))
|
||||
othernode.node_net_client.device_name(tmp2, otherifname)
|
||||
other_interface = CoreInterface(
|
||||
node=othernode, name=otherifname, mtu=_DEFAULT_MTU
|
||||
)
|
||||
|
@ -972,11 +918,9 @@ class CoreNode(CoreNodeBase):
|
|||
"""
|
||||
logging.info("adding file from %s to %s", srcname, filename)
|
||||
directory = os.path.dirname(filename)
|
||||
|
||||
cmd = 'mkdir -p "%s" && mv "%s" "%s" && sync' % (directory, srcname, filename)
|
||||
status, output = self.client.shcmd_result(cmd)
|
||||
if status:
|
||||
raise CoreCommandError(status, cmd, output)
|
||||
self.client.check_cmd(["mkdir", "-p", directory])
|
||||
self.client.check_cmd(["mv", srcname, filename])
|
||||
self.client.check_cmd(["sync"])
|
||||
|
||||
def hostfilename(self, filename):
|
||||
"""
|
||||
|
@ -1064,10 +1008,6 @@ class CoreNetworkBase(NodeBase):
|
|||
super(CoreNetworkBase, self).__init__(session, _id, name, start=start)
|
||||
self._linked = {}
|
||||
self._linked_lock = threading.Lock()
|
||||
if session.options.get_config("ovs") == "True":
|
||||
self.net_client = OvsNetClient()
|
||||
else:
|
||||
self.net_client = LinuxNetClient()
|
||||
|
||||
def startup(self):
|
||||
"""
|
||||
|
|
|
@ -26,7 +26,6 @@ class VnodeClient(object):
|
|||
"""
|
||||
self.name = name
|
||||
self.ctrlchnlname = ctrlchnlname
|
||||
self._addr = {}
|
||||
|
||||
def _verify_connection(self):
|
||||
"""
|
||||
|
@ -146,36 +145,6 @@ class VnodeClient(object):
|
|||
*args
|
||||
)
|
||||
|
||||
def redircmd(self, infd, outfd, errfd, args, wait=True):
|
||||
"""
|
||||
Execute a command on a node with standard input, output, and
|
||||
error redirected according to the given file descriptors.
|
||||
|
||||
:param infd: stdin file descriptor
|
||||
:param outfd: stdout file descriptor
|
||||
:param errfd: stderr file descriptor
|
||||
:param list[str]|str args: command arguments
|
||||
:param bool wait: wait flag
|
||||
:return: command status
|
||||
:rtype: int
|
||||
"""
|
||||
self._verify_connection()
|
||||
|
||||
# run command, return process when not waiting
|
||||
args = utils.split_args(args)
|
||||
cmd = self._cmd_args() + args
|
||||
logging.debug("redircmd: %s", cmd)
|
||||
p = Popen(cmd, stdin=infd, stdout=outfd, stderr=errfd)
|
||||
|
||||
if not wait:
|
||||
return p
|
||||
|
||||
# wait for and return exit status
|
||||
status = p.wait()
|
||||
if status:
|
||||
logging.warning("cmd exited with status %s: %s", status, args)
|
||||
return status
|
||||
|
||||
def term(self, sh="/bin/sh"):
|
||||
"""
|
||||
Open a terminal on a node.
|
||||
|
@ -215,111 +184,3 @@ class VnodeClient(object):
|
|||
:return: str
|
||||
"""
|
||||
return "%s -c %s -- %s" % (constants.VCMD_BIN, self.ctrlchnlname, sh)
|
||||
|
||||
def shcmd(self, cmd, sh="/bin/sh"):
|
||||
"""
|
||||
Execute a shell command.
|
||||
|
||||
:param str cmd: command string
|
||||
:param str sh: shell to run command in
|
||||
:return: command result
|
||||
:rtype: int
|
||||
"""
|
||||
return self.cmd([sh, "-c", cmd])
|
||||
|
||||
def shcmd_result(self, cmd, sh="/bin/sh"):
|
||||
"""
|
||||
Execute a shell command and return the exist status and combined output.
|
||||
|
||||
:param str cmd: shell command to run
|
||||
:param str sh: shell to run command in
|
||||
:return: exist status and combined output
|
||||
:rtype: tuple[int, str]
|
||||
"""
|
||||
return self.cmd_output([sh, "-c", cmd])
|
||||
|
||||
def getaddr(self, ifname, rescan=False):
|
||||
"""
|
||||
Get address for interface on node.
|
||||
|
||||
:param str ifname: interface name to get address for
|
||||
:param bool rescan: rescan flag
|
||||
:return: interface information
|
||||
:rtype: dict
|
||||
"""
|
||||
if ifname in self._addr and not rescan:
|
||||
return self._addr[ifname]
|
||||
|
||||
interface = {"ether": [], "inet": [], "inet6": [], "inet6link": []}
|
||||
args = [constants.IP_BIN, "addr", "show", "dev", ifname]
|
||||
p, stdin, stdout, stderr = self.popen(args)
|
||||
stdin.close()
|
||||
|
||||
for line in stdout:
|
||||
line = line.strip().split()
|
||||
if line[0] == "link/ether":
|
||||
interface["ether"].append(line[1])
|
||||
elif line[0] == "inet":
|
||||
interface["inet"].append(line[1])
|
||||
elif line[0] == "inet6":
|
||||
if line[3] == "global":
|
||||
interface["inet6"].append(line[1])
|
||||
elif line[3] == "link":
|
||||
interface["inet6link"].append(line[1])
|
||||
else:
|
||||
logging.warning("unknown scope: %s" % line[3])
|
||||
|
||||
err = stderr.read()
|
||||
stdout.close()
|
||||
stderr.close()
|
||||
status = p.wait()
|
||||
if status:
|
||||
logging.warning("nonzero exist status (%s) for cmd: %s", status, args)
|
||||
if err:
|
||||
logging.warning("error output: %s", err)
|
||||
self._addr[ifname] = interface
|
||||
return interface
|
||||
|
||||
def netifstats(self, ifname=None):
|
||||
"""
|
||||
Retrieve network interface state.
|
||||
|
||||
:param str ifname: name of interface to get state for
|
||||
:return: interface state information
|
||||
:rtype: dict
|
||||
"""
|
||||
stats = {}
|
||||
args = ["cat", "/proc/net/dev"]
|
||||
p, stdin, stdout, stderr = self.popen(args)
|
||||
stdin.close()
|
||||
# ignore first line
|
||||
stdout.readline()
|
||||
# second line has count names
|
||||
tmp = stdout.readline().decode("utf-8").strip().split("|")
|
||||
rxkeys = tmp[1].split()
|
||||
txkeys = tmp[2].split()
|
||||
for line in stdout:
|
||||
line = line.decode("utf-8").strip().split()
|
||||
devname, tmp = line[0].split(":")
|
||||
if tmp:
|
||||
line.insert(1, tmp)
|
||||
stats[devname] = {"rx": {}, "tx": {}}
|
||||
field = 1
|
||||
for count in rxkeys:
|
||||
stats[devname]["rx"][count] = int(line[field])
|
||||
field += 1
|
||||
for count in txkeys:
|
||||
stats[devname]["tx"][count] = int(line[field])
|
||||
field += 1
|
||||
err = stderr.read()
|
||||
stdout.close()
|
||||
stderr.close()
|
||||
status = p.wait()
|
||||
if status:
|
||||
logging.warning("nonzero exist status (%s) for cmd: %s", status, args)
|
||||
if err:
|
||||
logging.warning("error output: %s", err)
|
||||
if ifname is not None:
|
||||
return stats[ifname]
|
||||
else:
|
||||
return stats
|
||||
|
|
|
@ -13,7 +13,6 @@ class DockerClient(object):
|
|||
self.name = name
|
||||
self.image = image
|
||||
self.pid = None
|
||||
self._addr = {}
|
||||
|
||||
def create_container(self):
|
||||
utils.check_cmd(
|
||||
|
@ -95,40 +94,6 @@ class DockerClient(object):
|
|||
if status:
|
||||
raise CoreCommandError(status, args, output)
|
||||
|
||||
def getaddr(self, ifname, rescan=False):
|
||||
"""
|
||||
Get address for interface on node.
|
||||
|
||||
:param str ifname: interface name to get address for
|
||||
:param bool rescan: rescan flag
|
||||
:return: interface information
|
||||
:rtype: dict
|
||||
"""
|
||||
if ifname in self._addr and not rescan:
|
||||
return self._addr[ifname]
|
||||
|
||||
interface = {"ether": [], "inet": [], "inet6": [], "inet6link": []}
|
||||
args = ["ip", "addr", "show", "dev", ifname]
|
||||
status, output = self.ns_cmd(args)
|
||||
for line in output:
|
||||
line = line.strip().split()
|
||||
if line[0] == "link/ether":
|
||||
interface["ether"].append(line[1])
|
||||
elif line[0] == "inet":
|
||||
interface["inet"].append(line[1])
|
||||
elif line[0] == "inet6":
|
||||
if line[3] == "global":
|
||||
interface["inet6"].append(line[1])
|
||||
elif line[3] == "link":
|
||||
interface["inet6link"].append(line[1])
|
||||
else:
|
||||
logging.warning("unknown scope: %s" % line[3])
|
||||
|
||||
if status:
|
||||
logging.warning("nonzero exist status (%s) for cmd: %s", status, args)
|
||||
self._addr[ifname] = interface
|
||||
return interface
|
||||
|
||||
|
||||
class DockerNode(CoreNode):
|
||||
apitype = NodeTypes.DOCKER.value
|
||||
|
@ -225,7 +190,7 @@ class DockerNode(CoreNode):
|
|||
raise CoreCommandError(status, args, output)
|
||||
return output
|
||||
|
||||
def network_cmd(self, args):
|
||||
def node_net_cmd(self, args):
|
||||
if not self.up:
|
||||
logging.debug("node down, not running network command: %s", args)
|
||||
return 0
|
||||
|
|
|
@ -6,8 +6,9 @@ import logging
|
|||
import time
|
||||
from builtins import int, range
|
||||
|
||||
from core import constants, utils
|
||||
from core import utils
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes.netclient import LinuxNetClient
|
||||
|
||||
|
||||
class CoreInterface(object):
|
||||
|
@ -41,6 +42,7 @@ class CoreInterface(object):
|
|||
self.netindex = None
|
||||
# index used to find flow data
|
||||
self.flow_id = None
|
||||
self.net_client = LinuxNetClient(utils.check_cmd)
|
||||
|
||||
def startup(self):
|
||||
"""
|
||||
|
@ -216,21 +218,8 @@ 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", "set", self.localname, "up"])
|
||||
self.net_client.create_veth(self.localname, self.name)
|
||||
self.net_client.device_up(self.localname)
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
|
@ -244,15 +233,13 @@ class Veth(CoreInterface):
|
|||
|
||||
if self.node:
|
||||
try:
|
||||
self.node.network_cmd(
|
||||
[constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]
|
||||
)
|
||||
self.node.node_net_client.device_flush(self.name)
|
||||
except CoreCommandError:
|
||||
logging.exception("error shutting down interface")
|
||||
|
||||
if self.localname:
|
||||
try:
|
||||
utils.check_cmd([constants.IP_BIN, "link", "delete", self.localname])
|
||||
self.net_client.delete_device(self.localname)
|
||||
except CoreCommandError:
|
||||
logging.info("link already removed: %s", self.localname)
|
||||
|
||||
|
@ -307,9 +294,7 @@ class TunTap(CoreInterface):
|
|||
return
|
||||
|
||||
try:
|
||||
self.node.network_cmd(
|
||||
[constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]
|
||||
)
|
||||
self.node.node_net_client.device_flush(self.name)
|
||||
except CoreCommandError:
|
||||
logging.exception("error shutting down tunnel tap")
|
||||
|
||||
|
@ -357,8 +342,11 @@ class TunTap(CoreInterface):
|
|||
logging.debug("waiting for device local: %s", self.localname)
|
||||
|
||||
def localdevexists():
|
||||
args = [constants.IP_BIN, "link", "show", self.localname]
|
||||
return utils.cmd(args)
|
||||
try:
|
||||
self.net_client.device_show(self.localname)
|
||||
return 0
|
||||
except CoreCommandError:
|
||||
return 1
|
||||
|
||||
self.waitfor(localdevexists)
|
||||
|
||||
|
@ -371,9 +359,8 @@ class TunTap(CoreInterface):
|
|||
logging.debug("waiting for device node: %s", self.name)
|
||||
|
||||
def nodedevexists():
|
||||
args = [constants.IP_BIN, "link", "show", self.name]
|
||||
try:
|
||||
self.node.network_cmd(args)
|
||||
self.node.node_net_client.device_show(self.name)
|
||||
return 0
|
||||
except CoreCommandError:
|
||||
return 1
|
||||
|
@ -406,13 +393,9 @@ 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]
|
||||
)
|
||||
self.node.network_cmd([constants.IP_BIN, "link", "set", self.name, "up"])
|
||||
self.net_client.device_ns(self.localname, netns)
|
||||
self.node.node_net_client.device_name(self.localname, self.name)
|
||||
self.node.node_net_client.device_up(self.name)
|
||||
|
||||
def setaddrs(self):
|
||||
"""
|
||||
|
@ -422,9 +405,7 @@ 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.node_net_client.create_address(self.name, str(addr))
|
||||
|
||||
|
||||
class GreTap(CoreInterface):
|
||||
|
@ -478,25 +459,11 @@ 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),
|
||||
]
|
||||
if localip:
|
||||
args += ["local", str(localip)]
|
||||
if ttl:
|
||||
args += ["ttl", str(ttl)]
|
||||
if key:
|
||||
args += ["key", str(key)]
|
||||
utils.check_cmd(args)
|
||||
args = [constants.IP_BIN, "link", "set", self.localname, "up"]
|
||||
utils.check_cmd(args)
|
||||
|
||||
self.net_client.create_gretap(
|
||||
self.localname, str(remoteip), str(localip), str(ttl), str(key)
|
||||
)
|
||||
self.net_client.device_up(self.localname)
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
|
@ -507,10 +474,8 @@ class GreTap(CoreInterface):
|
|||
"""
|
||||
if self.localname:
|
||||
try:
|
||||
args = [constants.IP_BIN, "link", "set", self.localname, "down"]
|
||||
utils.check_cmd(args)
|
||||
args = [constants.IP_BIN, "link", "del", self.localname]
|
||||
utils.check_cmd(args)
|
||||
self.net_client.device_down(self.localname)
|
||||
self.net_client.delete_device(self.localname)
|
||||
except CoreCommandError:
|
||||
logging.exception("error during shutdown")
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ class LxdClient(object):
|
|||
self.name = name
|
||||
self.image = image
|
||||
self.pid = None
|
||||
self._addr = {}
|
||||
|
||||
def create_container(self):
|
||||
utils.check_cmd(
|
||||
|
@ -91,40 +90,6 @@ class LxdClient(object):
|
|||
if status:
|
||||
raise CoreCommandError(status, args, output)
|
||||
|
||||
def getaddr(self, ifname, rescan=False):
|
||||
"""
|
||||
Get address for interface on node.
|
||||
|
||||
:param str ifname: interface name to get address for
|
||||
:param bool rescan: rescan flag
|
||||
:return: interface information
|
||||
:rtype: dict
|
||||
"""
|
||||
if ifname in self._addr and not rescan:
|
||||
return self._addr[ifname]
|
||||
|
||||
interface = {"ether": [], "inet": [], "inet6": [], "inet6link": []}
|
||||
args = ["ip", "addr", "show", "dev", ifname]
|
||||
status, output = self.ns_cmd_output(args)
|
||||
for line in output:
|
||||
line = line.strip().split()
|
||||
if line[0] == "link/ether":
|
||||
interface["ether"].append(line[1])
|
||||
elif line[0] == "inet":
|
||||
interface["inet"].append(line[1])
|
||||
elif line[0] == "inet6":
|
||||
if line[3] == "global":
|
||||
interface["inet6"].append(line[1])
|
||||
elif line[3] == "link":
|
||||
interface["inet6link"].append(line[1])
|
||||
else:
|
||||
logging.warning("unknown scope: %s" % line[3])
|
||||
|
||||
if status:
|
||||
logging.warning("nonzero exist status (%s) for cmd: %s", status, args)
|
||||
self._addr[ifname] = interface
|
||||
return interface
|
||||
|
||||
|
||||
class LxcNode(CoreNode):
|
||||
apitype = NodeTypes.LXC.value
|
||||
|
@ -228,7 +193,7 @@ class LxcNode(CoreNode):
|
|||
raise CoreCommandError(status, args, output)
|
||||
return output
|
||||
|
||||
def network_cmd(self, args):
|
||||
def node_net_cmd(self, args):
|
||||
if not self.up:
|
||||
logging.debug("node down, not running network command: %s", args)
|
||||
return 0
|
||||
|
|
|
@ -2,87 +2,205 @@
|
|||
Clients for dealing with bridge/interface commands.
|
||||
"""
|
||||
|
||||
import abc
|
||||
import os
|
||||
|
||||
from future.utils import with_metaclass
|
||||
|
||||
from core.constants import BRCTL_BIN, IP_BIN, OVS_BIN
|
||||
from core.constants import BRCTL_BIN, ETHTOOL_BIN, IP_BIN, OVS_BIN, TC_BIN
|
||||
from core.utils import check_cmd
|
||||
|
||||
|
||||
class NetClientBase(with_metaclass(abc.ABCMeta)):
|
||||
"""
|
||||
Base client for running command line bridge/interface commands.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_bridge(self, name):
|
||||
"""
|
||||
Create a network bridge to connect interfaces to.
|
||||
|
||||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_bridge(self, name):
|
||||
"""
|
||||
Delete a network bridge.
|
||||
|
||||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_interface(self, bridge_name, interface_name):
|
||||
"""
|
||||
Create an interface associated with a network bridge.
|
||||
|
||||
:param str bridge_name: bridge name
|
||||
:param str interface_name: interface name
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_interface(self, bridge_name, interface_name):
|
||||
"""
|
||||
Delete an interface associated with a network bridge.
|
||||
|
||||
:param str bridge_name: bridge name
|
||||
:param str interface_name: interface name
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def existing_bridges(self, _id):
|
||||
"""
|
||||
Checks if there are any existing bridges for a node.
|
||||
|
||||
:param _id: node id to check bridges for
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def disable_mac_learning(self, name):
|
||||
"""
|
||||
Disable mac learning for a bridge.
|
||||
|
||||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class LinuxNetClient(NetClientBase):
|
||||
class LinuxNetClient(object):
|
||||
"""
|
||||
Client for creating Linux bridges and ip interfaces for nodes.
|
||||
"""
|
||||
|
||||
def __init__(self, run):
|
||||
"""
|
||||
Create LinuxNetClient instance.
|
||||
|
||||
:param run: function to run commands with
|
||||
"""
|
||||
self.run = run
|
||||
|
||||
def set_hostname(self, name):
|
||||
"""
|
||||
Set network hostname.
|
||||
|
||||
:param str name: name for hostname
|
||||
:return: nothing
|
||||
"""
|
||||
self.run(["hostname", name])
|
||||
|
||||
def create_route(self, route, device):
|
||||
"""
|
||||
Create a new route for a device.
|
||||
|
||||
:param str route: route to create
|
||||
:param str device: device to add route to
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "route", "add", route, "dev", device])
|
||||
|
||||
def device_up(self, device):
|
||||
"""
|
||||
Bring a device up.
|
||||
|
||||
:param str device: device to bring up
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "link", "set", device, "up"])
|
||||
|
||||
def device_down(self, device):
|
||||
"""
|
||||
Bring a device down.
|
||||
|
||||
:param str device: device to bring down
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "link", "set", device, "down"])
|
||||
|
||||
def device_name(self, device, name):
|
||||
"""
|
||||
Set a device name.
|
||||
|
||||
:param str device: device to set name for
|
||||
:param str name: name to set
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "link", "set", device, "name", name])
|
||||
|
||||
def device_show(self, device):
|
||||
"""
|
||||
Show information for a device.
|
||||
|
||||
:param str device: device to get information for
|
||||
:return: device information
|
||||
:rtype: str
|
||||
"""
|
||||
return self.run([IP_BIN, "link", "show", device])
|
||||
|
||||
def device_ns(self, device, namespace):
|
||||
"""
|
||||
Set netns for a device.
|
||||
|
||||
:param str device: device to setns for
|
||||
:param str namespace: namespace to set device to
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "link", "set", device, "netns", namespace])
|
||||
|
||||
def device_flush(self, device):
|
||||
"""
|
||||
Flush device addresses.
|
||||
|
||||
:param str device: device to flush
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "-6", "address", "flush", "dev", device])
|
||||
|
||||
def device_mac(self, device, mac):
|
||||
"""
|
||||
Set MAC address for a device.
|
||||
|
||||
:param str device: device to set mac for
|
||||
:param str mac: mac to set
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "link", "set", "dev", device, "address", mac])
|
||||
|
||||
def delete_device(self, device):
|
||||
"""
|
||||
Delete device.
|
||||
|
||||
:param str device: device to delete
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "link", "delete", device])
|
||||
|
||||
def delete_tc(self, device):
|
||||
"""
|
||||
Remove traffic control settings for a device.
|
||||
|
||||
:param str device: device to remove tc
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([TC_BIN, "qdisc", "del", "dev", device, "root"])
|
||||
|
||||
def checksums_off(self, interface_name):
|
||||
"""
|
||||
Turns interface checksums off.
|
||||
|
||||
:param str interface_name: interface to update
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([ETHTOOL_BIN, "-K", interface_name, "rx", "off", "tx", "off"])
|
||||
|
||||
def create_address(self, device, address, broadcast=None):
|
||||
"""
|
||||
Create address for a device.
|
||||
|
||||
:param str device: device to add address to
|
||||
:param str address: address to add
|
||||
:param str broadcast: broadcast address to use, default is None
|
||||
:return: nothing
|
||||
"""
|
||||
if broadcast is not None:
|
||||
self.run(
|
||||
[
|
||||
IP_BIN,
|
||||
"address",
|
||||
"add",
|
||||
address,
|
||||
"broadcast",
|
||||
broadcast,
|
||||
"dev",
|
||||
device,
|
||||
]
|
||||
)
|
||||
else:
|
||||
self.run([IP_BIN, "address", "add", address, "dev", device])
|
||||
|
||||
def delete_address(self, device, address):
|
||||
"""
|
||||
Delete an address from a device.
|
||||
|
||||
:param str device: targeted device
|
||||
:param str address: address to remove
|
||||
:return: nothing
|
||||
"""
|
||||
self.run([IP_BIN, "address", "delete", address, "dev", device])
|
||||
|
||||
def create_veth(self, name, peer):
|
||||
"""
|
||||
Create a veth pair.
|
||||
|
||||
:param str name: veth name
|
||||
:param str peer: peer name
|
||||
:return: nothing
|
||||
"""
|
||||
self.run(
|
||||
[IP_BIN, "link", "add", "name", name, "type", "veth", "peer", "name", peer]
|
||||
)
|
||||
|
||||
def create_gretap(self, device, address, local, ttl, key):
|
||||
"""
|
||||
Create a GRE tap on a device.
|
||||
|
||||
:param str device: device to add tap to
|
||||
:param str address: address to add tap for
|
||||
:param str local: local address to tie to
|
||||
:param str ttl: time to live value
|
||||
:param str key: key for tap
|
||||
:return: nothing
|
||||
"""
|
||||
cmd = [IP_BIN, "link", "add", device, "type", "gretap", "remote", address]
|
||||
if local is not None:
|
||||
cmd.extend(["local", local])
|
||||
if ttl is not None:
|
||||
cmd.extend(["ttl", ttl])
|
||||
if key is not None:
|
||||
cmd.extend(["key", key])
|
||||
self.run(cmd)
|
||||
|
||||
def create_bridge(self, name):
|
||||
"""
|
||||
Create a Linux bridge and bring it up.
|
||||
|
@ -90,10 +208,10 @@ class LinuxNetClient(NetClientBase):
|
|||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([BRCTL_BIN, "addbr", name])
|
||||
check_cmd([BRCTL_BIN, "stp", name, "off"])
|
||||
check_cmd([BRCTL_BIN, "setfd", name, "0"])
|
||||
check_cmd([IP_BIN, "link", "set", name, "up"])
|
||||
self.run([BRCTL_BIN, "addbr", name])
|
||||
self.run([BRCTL_BIN, "stp", name, "off"])
|
||||
self.run([BRCTL_BIN, "setfd", name, "0"])
|
||||
self.device_up(name)
|
||||
|
||||
# turn off multicast snooping so forwarding occurs w/o IGMP joins
|
||||
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % name
|
||||
|
@ -108,8 +226,8 @@ class LinuxNetClient(NetClientBase):
|
|||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([IP_BIN, "link", "set", name, "down"])
|
||||
check_cmd([BRCTL_BIN, "delbr", name])
|
||||
self.device_down(name)
|
||||
self.run([BRCTL_BIN, "delbr", name])
|
||||
|
||||
def create_interface(self, bridge_name, interface_name):
|
||||
"""
|
||||
|
@ -119,8 +237,8 @@ class LinuxNetClient(NetClientBase):
|
|||
:param str interface_name: interface name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([BRCTL_BIN, "addif", bridge_name, interface_name])
|
||||
check_cmd([IP_BIN, "link", "set", interface_name, "up"])
|
||||
self.run([BRCTL_BIN, "addif", bridge_name, interface_name])
|
||||
self.device_up(interface_name)
|
||||
|
||||
def delete_interface(self, bridge_name, interface_name):
|
||||
"""
|
||||
|
@ -130,7 +248,7 @@ class LinuxNetClient(NetClientBase):
|
|||
:param str interface_name: interface name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([BRCTL_BIN, "delif", bridge_name, interface_name])
|
||||
self.run([BRCTL_BIN, "delif", bridge_name, interface_name])
|
||||
|
||||
def existing_bridges(self, _id):
|
||||
"""
|
||||
|
@ -138,7 +256,7 @@ class LinuxNetClient(NetClientBase):
|
|||
|
||||
:param _id: node id to check bridges for
|
||||
"""
|
||||
output = check_cmd([BRCTL_BIN, "show"])
|
||||
output = self.run([BRCTL_BIN, "show"])
|
||||
lines = output.split("\n")
|
||||
for line in lines[1:]:
|
||||
columns = line.split()
|
||||
|
@ -160,7 +278,7 @@ class LinuxNetClient(NetClientBase):
|
|||
check_cmd([BRCTL_BIN, "setageing", name, "0"])
|
||||
|
||||
|
||||
class OvsNetClient(NetClientBase):
|
||||
class OvsNetClient(LinuxNetClient):
|
||||
"""
|
||||
Client for creating OVS bridges and ip interfaces for nodes.
|
||||
"""
|
||||
|
@ -172,11 +290,11 @@ class OvsNetClient(NetClientBase):
|
|||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([OVS_BIN, "add-br", name])
|
||||
check_cmd([OVS_BIN, "set", "bridge", name, "stp_enable=false"])
|
||||
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:stp-max-age=6"])
|
||||
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:stp-forward-delay=4"])
|
||||
check_cmd([IP_BIN, "link", "set", name, "up"])
|
||||
self.run([OVS_BIN, "add-br", name])
|
||||
self.run([OVS_BIN, "set", "bridge", name, "stp_enable=false"])
|
||||
self.run([OVS_BIN, "set", "bridge", name, "other_config:stp-max-age=6"])
|
||||
self.run([OVS_BIN, "set", "bridge", name, "other_config:stp-forward-delay=4"])
|
||||
self.device_up(name)
|
||||
|
||||
def delete_bridge(self, name):
|
||||
"""
|
||||
|
@ -185,8 +303,8 @@ class OvsNetClient(NetClientBase):
|
|||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([IP_BIN, "link", "set", name, "down"])
|
||||
check_cmd([OVS_BIN, "del-br", name])
|
||||
self.device_down(name)
|
||||
self.run([OVS_BIN, "del-br", name])
|
||||
|
||||
def create_interface(self, bridge_name, interface_name):
|
||||
"""
|
||||
|
@ -196,8 +314,8 @@ class OvsNetClient(NetClientBase):
|
|||
:param str interface_name: interface name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([OVS_BIN, "add-port", bridge_name, interface_name])
|
||||
check_cmd([IP_BIN, "link", "set", interface_name, "up"])
|
||||
self.run([OVS_BIN, "add-port", bridge_name, interface_name])
|
||||
self.device_up(interface_name)
|
||||
|
||||
def delete_interface(self, bridge_name, interface_name):
|
||||
"""
|
||||
|
@ -207,7 +325,7 @@ class OvsNetClient(NetClientBase):
|
|||
:param str interface_name: interface name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([OVS_BIN, "del-port", bridge_name, interface_name])
|
||||
self.run([OVS_BIN, "del-port", bridge_name, interface_name])
|
||||
|
||||
def existing_bridges(self, _id):
|
||||
"""
|
||||
|
@ -215,7 +333,7 @@ class OvsNetClient(NetClientBase):
|
|||
|
||||
:param _id: node id to check bridges for
|
||||
"""
|
||||
output = check_cmd([OVS_BIN, "list-br"])
|
||||
output = self.run([OVS_BIN, "list-br"])
|
||||
if output:
|
||||
for line in output.split("\n"):
|
||||
fields = line.split(".")
|
||||
|
@ -230,4 +348,4 @@ class OvsNetClient(NetClientBase):
|
|||
:param str name: bridge name
|
||||
:return: nothing
|
||||
"""
|
||||
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:mac-aging-time=0"])
|
||||
self.run([OVS_BIN, "set", "bridge", name, "other_config:mac-aging-time=0"])
|
||||
|
|
|
@ -629,9 +629,7 @@ class CoreNetwork(CoreNetworkBase):
|
|||
return
|
||||
|
||||
for addr in addrlist:
|
||||
utils.check_cmd(
|
||||
[constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname]
|
||||
)
|
||||
self.net_client.create_address(self.brname, str(addr))
|
||||
|
||||
|
||||
class GreTapBridge(CoreNetwork):
|
||||
|
|
|
@ -100,51 +100,33 @@ class PhysicalNode(CoreNodeBase):
|
|||
"""
|
||||
Set hardware address for an interface.
|
||||
"""
|
||||
self._netif[ifindex].sethwaddr(addr)
|
||||
ifname = self.ifname(ifindex)
|
||||
interface = self._netif[ifindex]
|
||||
interface.sethwaddr(addr)
|
||||
if self.up:
|
||||
self.check_cmd(
|
||||
[constants.IP_BIN, "link", "set", "dev", ifname, "address", str(addr)]
|
||||
)
|
||||
self.net_client.device_mac(interface.name, str(addr))
|
||||
|
||||
def addaddr(self, ifindex, addr):
|
||||
"""
|
||||
Add an address to an interface.
|
||||
"""
|
||||
interface = self._netif[ifindex]
|
||||
if self.up:
|
||||
self.check_cmd(
|
||||
[
|
||||
constants.IP_BIN,
|
||||
"addr",
|
||||
"add",
|
||||
str(addr),
|
||||
"dev",
|
||||
self.ifname(ifindex),
|
||||
]
|
||||
)
|
||||
|
||||
self._netif[ifindex].addaddr(addr)
|
||||
self.net_client.create_address(interface.name, str(addr))
|
||||
interface.addaddr(addr)
|
||||
|
||||
def deladdr(self, ifindex, addr):
|
||||
"""
|
||||
Delete an address from an interface.
|
||||
"""
|
||||
interface = self._netif[ifindex]
|
||||
|
||||
try:
|
||||
self._netif[ifindex].deladdr(addr)
|
||||
interface.deladdr(addr)
|
||||
except ValueError:
|
||||
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.net_client.delete_address(interface.name, str(addr))
|
||||
|
||||
def adoptnetif(self, netif, ifindex, hwaddr, addrlist):
|
||||
"""
|
||||
|
@ -159,12 +141,8 @@ 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.net_client.device_down(netif.localname)
|
||||
self.net_client.device_name(netif.localname, netif.name)
|
||||
|
||||
netif.localname = netif.name
|
||||
|
||||
|
@ -175,9 +153,7 @@ class PhysicalNode(CoreNodeBase):
|
|||
self.addaddr(ifindex, addr)
|
||||
|
||||
if self.up:
|
||||
self.check_cmd(
|
||||
[constants.IP_BIN, "link", "set", "dev", netif.localname, "up"]
|
||||
)
|
||||
self.net_client.device_up(netif.localname)
|
||||
|
||||
def linkconfig(
|
||||
self,
|
||||
|
@ -335,7 +311,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
"""
|
||||
# interface will also be marked up during net.attach()
|
||||
self.savestate()
|
||||
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
|
||||
self.net_client.device_up(self.localname)
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
|
@ -349,18 +325,17 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
return
|
||||
|
||||
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"]
|
||||
)
|
||||
self.net_client.device_down(self.localname)
|
||||
self.net_client.device_flush(self.localname)
|
||||
self.net_client.delete_tc(self.localname)
|
||||
except CoreCommandError:
|
||||
logging.exception("error shutting down")
|
||||
|
||||
self.up = False
|
||||
self.restorestate()
|
||||
|
||||
# TODO: issue in that both classes inherited from provide the same method with different signatures
|
||||
# TODO: issue in that both classes inherited from provide the same method with
|
||||
# different signatures
|
||||
def attachnet(self, net):
|
||||
"""
|
||||
Attach a network.
|
||||
|
@ -370,7 +345,8 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
"""
|
||||
CoreInterface.attachnet(self, net)
|
||||
|
||||
# TODO: issue in that both classes inherited from provide the same method with different signatures
|
||||
# TODO: issue in that both classes inherited from provide the same method with
|
||||
# different signatures
|
||||
def detachnet(self):
|
||||
"""
|
||||
Detach a network.
|
||||
|
@ -476,9 +452,7 @@ 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]
|
||||
)
|
||||
self.net_client.create_address(self.name, str(addr))
|
||||
|
||||
CoreInterface.addaddr(self, addr)
|
||||
|
||||
|
@ -491,9 +465,7 @@ 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]
|
||||
)
|
||||
self.net_client.delete_address(self.name, str(addr))
|
||||
|
||||
CoreInterface.deladdr(self, addr)
|
||||
|
||||
|
@ -507,8 +479,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
"""
|
||||
self.old_up = False
|
||||
self.old_addrs = []
|
||||
args = [constants.IP_BIN, "addr", "show", "dev", self.localname]
|
||||
output = utils.check_cmd(args)
|
||||
output = self.net_client.device_show(self.localname)
|
||||
for line in output.split("\n"):
|
||||
items = line.split()
|
||||
if len(items) < 2:
|
||||
|
@ -534,25 +505,14 @@ 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]
|
||||
)
|
||||
self.net_client.create_address(self.localname, addr[0])
|
||||
else:
|
||||
utils.check_cmd(
|
||||
[
|
||||
constants.IP_BIN,
|
||||
"addr",
|
||||
"add",
|
||||
addr[0],
|
||||
"brd",
|
||||
addr[1],
|
||||
"dev",
|
||||
self.localname,
|
||||
]
|
||||
self.net_client.create_address(
|
||||
self.localname, addr[0], broadcast=addr[1]
|
||||
)
|
||||
|
||||
if self.old_up:
|
||||
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
|
||||
self.net_client.device_up(self.localname)
|
||||
|
||||
def setposition(self, x=None, y=None, z=None):
|
||||
"""
|
||||
|
|
|
@ -4,7 +4,6 @@ Unit tests for testing basic CORE networks.
|
|||
|
||||
import os
|
||||
import stat
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
|
@ -109,10 +108,6 @@ class TestCore:
|
|||
p, stdin, stdout, stderr = client.popen(command)
|
||||
assert not p.wait()
|
||||
assert not client.icmd(command)
|
||||
assert not client.redircmd(
|
||||
subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, command
|
||||
)
|
||||
assert not client.shcmd(command[0])
|
||||
|
||||
# check various command using command line
|
||||
assert not client.cmd(command)
|
||||
|
@ -121,15 +116,10 @@ class TestCore:
|
|||
p, stdin, stdout, stderr = client.popen(command)
|
||||
assert not p.wait()
|
||||
assert not client.icmd(command)
|
||||
assert not client.shcmd(command[0])
|
||||
|
||||
# check module methods
|
||||
assert createclients(session.session_dir)
|
||||
|
||||
# check convenience methods for interface information
|
||||
assert client.getaddr("eth0")
|
||||
assert client.netifstats()
|
||||
|
||||
def test_netif(self, session, ip_prefixes):
|
||||
"""
|
||||
Test netif methods.
|
||||
|
|
Loading…
Add table
Reference in a new issue