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.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes import client, ipaddress from core.nodes import client, ipaddress
from core.nodes.interface import CoreInterface, TunTap, Veth 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 _DEFAULT_MTU = 1500
@ -1065,10 +1065,10 @@ class CoreNetworkBase(NodeBase):
super(CoreNetworkBase, self).__init__(session, _id, name, start=start) super(CoreNetworkBase, self).__init__(session, _id, name, start=start)
self._linked = {} self._linked = {}
self._linked_lock = threading.Lock() self._linked_lock = threading.Lock()
if session.options.get_config("ovs"): if session.options.get_config("ovs") == "True":
self.net_client = OvsClient() self.net_client = OvsNetClient()
else: else:
self.net_client = BrctlClient() self.net_client = LinuxNetClient()
def startup(self): 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 abc
import os 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): class NetClientBase(with_metaclass(abc.ABCMeta)):
__metaclass__ = abc.ABCMeta """
Base client for running command line bridge/interface commands.
"""
@abc.abstractmethod @abc.abstractmethod
def create_bridge(self, name): 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): 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 # disable spanning tree protocol and set forward delay to 0
utils.check_cmd([constants.BRCTL_BIN, "stp", name, "off"]) check_cmd([BRCTL_BIN, "stp", name, "off"])
utils.check_cmd([constants.BRCTL_BIN, "setfd", name, "0"]) check_cmd([BRCTL_BIN, "setfd", name, "0"])
utils.check_cmd([constants.IP_BIN, "link", "set", name, "up"]) check_cmd([IP_BIN, "link", "set", name, "up"])
# turn off multicast snooping so forwarding occurs w/o IGMP joins # turn off multicast snooping so forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % name snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % name
@ -31,44 +93,60 @@ class BrctlClient(object):
f.write("0") f.write("0")
def delete_bridge(self, name): def delete_bridge(self, name):
utils.check_cmd([constants.IP_BIN, "link", "set", name, "down"]) check_cmd([IP_BIN, "link", "set", name, "down"])
utils.check_cmd([constants.BRCTL_BIN, "delbr", name]) check_cmd([BRCTL_BIN, "delbr", name])
def create_interface(self, bridge_name, interface_name): def create_interface(self, bridge_name, interface_name):
utils.check_cmd([constants.BRCTL_BIN, "addif", bridge_name, interface_name]) check_cmd([BRCTL_BIN, "addif", bridge_name, interface_name])
utils.check_cmd([constants.IP_BIN, "link", "set", interface_name, "up"]) check_cmd([IP_BIN, "link", "set", interface_name, "up"])
def delete_interface(self, bridge_name, interface_name): 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): def existing_bridges(self, _id):
return utils.check_cmd([constants.OVS_BIN, "list-br"]) 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): 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): def create_bridge(self, name):
# turn off spanning tree protocol and forwarding delay # turn off spanning tree protocol and forwarding delay
# TODO: verify stp and rstp are always off by default # TODO: verify stp and rstp are always off by default
# TODO: ovs only supports rstp forward delay and again it's 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]) check_cmd([OVS_BIN, "add-br", name])
utils.check_cmd([constants.IP_BIN, "link", "set", name, "up"]) check_cmd([IP_BIN, "link", "set", name, "up"])
def delete_bridge(self, name): def delete_bridge(self, name):
utils.check_cmd([constants.IP_BIN, "link", "set", name, "down"]) check_cmd([IP_BIN, "link", "set", name, "down"])
utils.check_cmd([constants.OVS_BIN, "del-br", name]) check_cmd([OVS_BIN, "del-br", name])
def create_interface(self, bridge_name, interface_name): def create_interface(self, bridge_name, interface_name):
utils.check_cmd([constants.OVS_BIN, "add-port", bridge_name, interface_name]) check_cmd([OVS_BIN, "add-port", bridge_name, interface_name])
utils.check_cmd([constants.IP_BIN, "link", "set", interface_name, "up"]) check_cmd([IP_BIN, "link", "set", interface_name, "up"])
def delete_interface(self, bridge_name, interface_name): 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): def existing_bridges(self, _id):
utils.check_cmd([constants.BRCTL_BIN, "show"]) 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): 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 import time
from socket import AF_INET, AF_INET6 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.data import LinkData
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
from core.nodes import ipaddress from core.nodes import ipaddress
@ -806,8 +806,8 @@ class CtrlNet(CoreNetwork):
:return: nothing :return: nothing
:raises CoreCommandError: when there is a command exception :raises CoreCommandError: when there is a command exception
""" """
if self.detectoldbridge(): if self.net_client.existing_bridges(self.id):
return raise CoreError("old bridges exist for node: %s" % self.id)
CoreNetwork.startup(self) CoreNetwork.startup(self)
@ -834,32 +834,6 @@ class CtrlNet(CoreNetwork):
if self.serverintf: if self.serverintf:
self.net_client.create_interface(self.brname, 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): def shutdown(self):
""" """
Control network shutdown. Control network shutdown.