implemented net client for linux and ovs

This commit is contained in:
bharnden 2019-09-26 22:04:29 -07:00
parent b449729a31
commit 0c002bb491
3 changed files with 114 additions and 62 deletions

View file

@ -19,7 +19,7 @@ from core.emulator.data import LinkData, NodeData
from core.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes import client, ipaddress
from core.nodes.interface import CoreInterface, TunTap, Veth
from core.nodes.netclient import BrctlClient, OvsClient
from core.nodes.netclient import LinuxNetClient, OvsNetClient
_DEFAULT_MTU = 1500
@ -1065,10 +1065,10 @@ 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"):
self.net_client = OvsClient()
if session.options.get_config("ovs") == "True":
self.net_client = OvsNetClient()
else:
self.net_client = BrctlClient()
self.net_client = LinuxNetClient()
def startup(self):
"""

View file

@ -1,28 +1,90 @@
"""
Clients for dealing with bridge and interface commands.
Clients for dealing with bridge/interface commands.
"""
import abc
import os
from core import constants, utils
from future.utils import with_metaclass
from core.constants import BRCTL_BIN, IP_BIN, OVS_BIN
from core.utils import check_cmd
class NetworkClient(object):
__metaclass__ = abc.ABCMeta
class NetClientBase(with_metaclass(abc.ABCMeta)):
"""
Base client for running command line bridge/interface commands.
"""
@abc.abstractmethod
def create_bridge(self, name):
return NotImplemented
"""
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 branch.
:param str name: branch name
:return: nothing
"""
pass
class BrctlClient(object):
class LinuxNetClient(NetClientBase):
def create_bridge(self, name):
utils.check_cmd([constants.BRCTL_BIN, "addbr", name])
check_cmd([BRCTL_BIN, "addbr", name])
# disable spanning tree protocol and set forward delay to 0
utils.check_cmd([constants.BRCTL_BIN, "stp", name, "off"])
utils.check_cmd([constants.BRCTL_BIN, "setfd", name, "0"])
utils.check_cmd([constants.IP_BIN, "link", "set", name, "up"])
check_cmd([BRCTL_BIN, "stp", name, "off"])
check_cmd([BRCTL_BIN, "setfd", name, "0"])
check_cmd([IP_BIN, "link", "set", name, "up"])
# turn off multicast snooping so forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % name
@ -31,44 +93,60 @@ class BrctlClient(object):
f.write("0")
def delete_bridge(self, name):
utils.check_cmd([constants.IP_BIN, "link", "set", name, "down"])
utils.check_cmd([constants.BRCTL_BIN, "delbr", name])
check_cmd([IP_BIN, "link", "set", name, "down"])
check_cmd([BRCTL_BIN, "delbr", name])
def create_interface(self, bridge_name, interface_name):
utils.check_cmd([constants.BRCTL_BIN, "addif", bridge_name, interface_name])
utils.check_cmd([constants.IP_BIN, "link", "set", interface_name, "up"])
check_cmd([BRCTL_BIN, "addif", bridge_name, interface_name])
check_cmd([IP_BIN, "link", "set", interface_name, "up"])
def delete_interface(self, bridge_name, interface_name):
utils.check_cmd([constants.BRCTL_BIN, "delif", bridge_name, interface_name])
check_cmd([BRCTL_BIN, "delif", bridge_name, interface_name])
def get_bridges(self):
return utils.check_cmd([constants.OVS_BIN, "list-br"])
def existing_bridges(self, _id):
output = check_cmd([BRCTL_BIN, "show"])
lines = output.split("\n")
for line in lines[1:]:
columns = line.split()
name = columns[0]
fields = name.split(".")
if len(fields) != 3:
continue
if fields[0] == "b" and fields[1] == _id:
return True
return False
def disable_mac_learning(self, name):
utils.check_cmd([constants.BRCTL_BIN, "setageing", name, "0"])
check_cmd([BRCTL_BIN, "setageing", name, "0"])
class OvsClient(object):
class OvsNetClient(NetClientBase):
def create_bridge(self, name):
# turn off spanning tree protocol and forwarding delay
# TODO: verify stp and rstp are always off by default
# TODO: ovs only supports rstp forward delay and again it's off by default
utils.check_cmd([constants.OVS_BIN, "add-br", name])
utils.check_cmd([constants.IP_BIN, "link", "set", name, "up"])
check_cmd([OVS_BIN, "add-br", name])
check_cmd([IP_BIN, "link", "set", name, "up"])
def delete_bridge(self, name):
utils.check_cmd([constants.IP_BIN, "link", "set", name, "down"])
utils.check_cmd([constants.OVS_BIN, "del-br", name])
check_cmd([IP_BIN, "link", "set", name, "down"])
check_cmd([OVS_BIN, "del-br", name])
def create_interface(self, bridge_name, interface_name):
utils.check_cmd([constants.OVS_BIN, "add-port", bridge_name, interface_name])
utils.check_cmd([constants.IP_BIN, "link", "set", interface_name, "up"])
check_cmd([OVS_BIN, "add-port", bridge_name, interface_name])
check_cmd([IP_BIN, "link", "set", interface_name, "up"])
def delete_interface(self, bridge_name, interface_name):
utils.check_cmd([constants.OVS_BIN, "del-port", bridge_name, interface_name])
check_cmd([OVS_BIN, "del-port", bridge_name, interface_name])
def get_bridges(self):
utils.check_cmd([constants.BRCTL_BIN, "show"])
def existing_bridges(self, _id):
output = check_cmd([OVS_BIN, "list-br"])
if output:
for line in output.split("\n"):
fields = line.split(".")
if fields[0] == "b" and fields[1] == _id:
return True
return False
def disable_mac_learning(self, name):
pass
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:mac-aging-time=0"])

View file

@ -9,7 +9,7 @@ import threading
import time
from socket import AF_INET, AF_INET6
from core import CoreCommandError, constants, utils
from core import CoreCommandError, CoreError, constants, utils
from core.emulator.data import LinkData
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
from core.nodes import ipaddress
@ -806,8 +806,8 @@ class CtrlNet(CoreNetwork):
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
if self.detectoldbridge():
return
if self.net_client.existing_bridges(self.id):
raise CoreError("old bridges exist for node: %s" % self.id)
CoreNetwork.startup(self)
@ -834,32 +834,6 @@ class CtrlNet(CoreNetwork):
if self.serverintf:
self.net_client.create_interface(self.brname, self.serverintf)
def detectoldbridge(self):
"""
Occasionally, control net bridges from previously closed sessions are not
cleaned up. Check if there are old control net bridges and delete them
:return: True if an old bridge was detected, False otherwise
:rtype: bool
"""
output = self.net_client.get_bridges()
lines = output.split("\n")
for line in lines[1:]:
cols = line.split("\t")
oldbr = cols[0]
flds = cols[0].split(".")
if len(flds) == 3:
if flds[0] == "b" and flds[1] == self.id:
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,
)
return True
return False
def shutdown(self):
"""
Control network shutdown.