implemented net client for linux and ovs
This commit is contained in:
parent
b449729a31
commit
0c002bb491
3 changed files with 114 additions and 62 deletions
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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"])
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Add table
Reference in a new issue