__UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
@staticmethod
- def set_interface_state(node, interface, state):
+ def set_interface_state(node, interface, state, if_type="key"):
"""Set interface state on a node.
Function can be used for DUTs as well as for TGs.
:param node: Node where the interface is.
- :param interface: Interface name or sw_if_index.
+ :param interface: Interface key or sw_if_index or name.
:param state: One of 'up' or 'down'.
+ :param if_type: Interface type
:type node: dict
:type interface: str or int
:type state: str
- :return: nothing
+ :type if_type: str
+ :returns: Nothing.
+ :raises ValueError: If the interface type is unknown.
+ :raises ValueError: If the state of interface is unexpected.
+ :raises ValueError: If the node has an unknown node type.
"""
+
+ if if_type == "key":
+ if isinstance(interface, basestring):
+ sw_if_index = Topology.get_interface_sw_index(node, interface)
+ iface_name = Topology.get_interface_name(node, interface)
+ else:
+ sw_if_index = interface
+ elif if_type == "name":
+ iface_key = Topology.get_interface_by_name(node, interface)
+ if iface_key is not None:
+ sw_if_index = Topology.get_interface_sw_index(node, iface_key)
+ iface_name = interface
+ else:
+ raise ValueError("if_type unknown: {}".format(if_type))
+
if node['type'] == NodeType.DUT:
if state == 'up':
state = 'admin-up'
state = 'admin-down'
else:
raise ValueError('Unexpected interface state: {}'.format(state))
-
- if isinstance(interface, basestring):
- sw_if_index = Topology.get_interface_sw_index(node, interface)
- else:
- sw_if_index = interface
-
VatExecutor.cmd_from_template(node, 'set_if_state.vat',
sw_if_index=sw_if_index, state=state)
-
elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
- cmd = 'ip link set {} {}'.format(interface, state)
+ cmd = 'ip link set {} {}'.format(iface_name, state)
exec_cmd_no_error(node, cmd, sudo=True)
else:
- raise Exception('Node {} has unknown NodeType: "{}"'.
- format(node['host'], node['type']))
+ raise ValueError('Node {} has unknown NodeType: "{}"'
+ .format(node['host'], node['type']))
@staticmethod
- def set_interface_ethernet_mtu(node, interface, mtu):
+ def set_interface_ethernet_mtu(node, iface_key, mtu):
"""Set Ethernet MTU for specified interface.
Function can be used only for TGs.
:param node: Node where the interface is.
- :param interface: Interface name.
+ :param iface_key: Interface key from topology file.
:param mtu: MTU to set.
:type node: dict
- :type interface: str
+ :type iface_key: str
:type mtu: int
- :return: nothing
+ :returns: Nothing.
+ :raises ValueError: If the node type is "DUT".
+ :raises ValueError: If the node has an unknown node type.
"""
if node['type'] == NodeType.DUT:
- ValueError('Node {}: Setting Ethernet MTU for interface '
- 'on DUT nodes not supported', node['host'])
+ raise ValueError('Node {}: Setting Ethernet MTU for interface '
+ 'on DUT nodes not supported', node['host'])
elif node['type'] == NodeType.TG:
- cmd = 'ip link set {} mtu {}'.format(interface, mtu)
+ iface_name = Topology.get_interface_name(node, iface_key)
+ cmd = 'ip link set {} mtu {}'.format(iface_name, mtu)
exec_cmd_no_error(node, cmd, sudo=True)
else:
- raise ValueError('Node {} has unknown NodeType: "{}"'.
- format(node['host'], node['type']))
+ raise ValueError('Node {} has unknown NodeType: "{}"'
+ .format(node['host'], node['type']))
@staticmethod
def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
:param node: Node where to set default MTU.
:type node: dict
- :return: nothing
+ :returns: Nothing.
"""
- for ifc in node['interfaces'].values():
- InterfaceUtil.set_interface_ethernet_mtu(node, ifc['name'], 1500)
+ for ifc in node['interfaces']:
+ InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
@staticmethod
def vpp_node_interfaces_ready_wait(node, timeout=10):
:param timeout: Waiting timeout in seconds (optional, default 10s).
:type node: dict
:type timeout: int
+ :returns: Nothing.
:raises: RuntimeError if the timeout period value has elapsed.
"""
if_ready = False
:param timeout: Seconds to wait per node for all interfaces to come up.
:type nodes: list
:type timeout: int
- :raises: RuntimeError if the timeout period value has elapsed.
+ :returns: Nothing.
"""
for node in nodes:
InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
:param timeout: Seconds to wait per node for all interfaces to come up.
:type nodes: dict
:type timeout: int
- :raises: RuntimeError if the timeout period value has elapsed.
+ :returns: Nothing.
"""
for node in nodes.values():
if node['type'] == NodeType.DUT:
:param interface: Numeric index or name string of a specific interface.
:type node: dict
:type interface: int or str
- :return: List of dictionaries containing data for each interface, or a
+ :returns: List of dictionaries containing data for each interface, or a
single dictionary for the specified interface.
:rtype: list or dict
+ :raises TypeError: if the data type of interface is neither basestring
+ nor int.
"""
with VatTerminal(node) as vat:
response = vat.vat_terminal_exec_cmd_from_template(
if interface is not None:
if isinstance(interface, basestring):
- sw_if_index = Topology.get_interface_sw_index(node, interface)
+ param = "interface_name"
+ elif isinstance(interface, int):
+ param = "sw_if_index"
else:
- sw_if_index = interface
-
+ raise TypeError
for data_if in data:
- if data_if["sw_if_index"] == sw_if_index:
-
+ if data_if[param] == interface:
return data_if
-
+ return dict()
return data
+ @staticmethod
+ def vpp_get_interface_name(node, sw_if_index):
+ """Get interface name for the given SW interface index from actual
+ interface dump.
+
+ :param node: VPP node to get interface data from.
+ :param sw_if_index: SW interface index of the specific interface.
+ :type node: dict
+ :type sw_if_index: int
+ :returns: Name of the given interface.
+ :rtype: str
+ """
+
+ if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index)
+ if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
+ if_data = InterfaceUtil.vpp_get_interface_data(
+ node, if_data['sup_sw_if_index'])
+ try:
+ if_name = if_data["interface_name"]
+ except KeyError:
+ if_name = None
+ return if_name
+
+ @staticmethod
+ def vpp_get_interface_mac(node, interface=None):
+ """Get MAC address for the given interface from actual interface dump.
+
+ :param node: VPP node to get interface data from.
+ :param interface: Numeric index or name string of a specific interface.
+ :type node: dict
+ :type interface: int or str
+ :returns: MAC address.
+ :rtype: str
+ """
+
+ if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
+ if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
+ if_data = InterfaceUtil.vpp_get_interface_data(
+ node, if_data['sup_sw_if_index'])
+ mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
+ mac_data_nice = []
+ for item in mac_data:
+ if len(item) == 1:
+ item = '0' + item
+ mac_data_nice.append(item)
+ mac = ":".join(mac_data_nice)
+ return mac
+
@staticmethod
def vpp_get_interface_ip_addresses(node, interface, ip_version):
"""Get list of IP addresses from an interface on a VPP node.
:type node: dict
:type interface: str
:type ip_version: str
- :return: List of dictionaries, each containing IP address, subnet
+ :returns: List of dictionaries, each containing IP address, subnet
prefix length and also the subnet mask for ipv4 addresses.
Note: A single interface may have multiple IP addresses assigned.
:rtype: list
"""
- sw_if_index = Topology.get_interface_sw_index(node, interface)
+
+ try:
+ sw_if_index = Topology.convert_interface_reference(
+ node, interface, "sw_if_index")
+ except RuntimeError:
+ if isinstance(interface, basestring):
+ sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+ else:
+ raise
with VatTerminal(node) as vat:
response = vat.vat_terminal_exec_cmd_from_template(
:type node: dict
:type pci_addr: str
:type driver: str
+ :returns: None.
+ :raises RuntimeError: If unbinding from the current driver fails.
+ :raises RuntimeError: If binding to the new driver fails.
"""
old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
if old_driver == driver:
# Unbind from current driver
if old_driver is not None:
- cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'.format(
- pci_addr, old_driver)
+ cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\
+ .format(pci_addr, old_driver)
(ret_code, _, _) = ssh.exec_command_sudo(cmd)
if int(ret_code) != 0:
- raise Exception("'{0}' failed on '{1}'".format(cmd,
- node['host']))
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
# Bind to the new driver
- cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'.format(
- pci_addr, driver)
+ cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\
+ .format(pci_addr, driver)
(ret_code, _, _) = ssh.exec_command_sudo(cmd)
if int(ret_code) != 0:
- raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
@staticmethod
def tg_get_interface_driver(node, pci_addr):
:param pci_addr: PCI address of the interface.
:type node: dict
:type pci_addr: str
- :return: Interface driver or None if not found.
+ :returns: Interface driver or None if not found.
:rtype: str
+ :raises RuntimeError: If it is not possible to get the interface driver
+ information from the node.
.. note::
# lspci -vmmks 0000:00:05.0
ssh = SSH()
ssh.connect(node)
- cmd = 'lspci -vmmks {0}'.format(pci_addr)
-
- (ret_code, stdout, _) = ssh.exec_command(cmd)
- if int(ret_code) != 0:
- raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
-
- for line in stdout.splitlines():
- if len(line) == 0:
- continue
- (name, value) = line.split("\t", 1)
- if name == 'Driver:':
- return value
+ for i in range(3):
+ logger.trace('Try {}: Get interface driver'.format(i))
+ cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"'
+ (ret_code, _, _) = ssh.exec_command_sudo(cmd)
+ if int(ret_code) != 0:
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
- return None
+ cmd = 'lspci -vmmks {0}'.format(pci_addr)
+ (ret_code, stdout, _) = ssh.exec_command(cmd)
+ if int(ret_code) != 0:
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
+
+ for line in stdout.splitlines():
+ if len(line) == 0:
+ continue
+ try:
+ (name, value) = line.split("\t", 1)
+ except ValueError:
+ if name != "Driver:":
+ pass
+ else:
+ return None
+ if name == 'Driver:':
+ return value if value else None
+ else:
+ raise RuntimeError('Get interface driver for: {0}'
+ .format(pci_addr))
@staticmethod
def tg_set_interfaces_udev_rules(node):
:param node: Node to set udev rules on (must be TG node).
:type node: dict
+ :raises RuntimeError: If setting of udev rules fails.
"""
ssh = SSH()
ssh.connect(node)
cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
(ret_code, _, _) = ssh.exec_command_sudo(cmd)
if int(ret_code) != 0:
- raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
for interface in node['interfaces'].values():
rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
(ret_code, _, _) = ssh.exec_command_sudo(cmd)
if int(ret_code) != 0:
- raise Exception("'{0}' failed on '{1}'".format(cmd,
- node['host']))
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
cmd = '/etc/init.d/udev restart'
ssh.exec_command_sudo(cmd)
VatJsonUtil.update_vpp_interface_data_from_json(node,
interface_dump_json)
+ @staticmethod
+ def update_nic_interface_names(node):
+ """Update interface names based on nic type and PCI address.
+
+ This method updates interface names in the same format as VPP does.
+
+ :param node: Node dictionary.
+ :type node: dict
+ """
+ for ifc in node['interfaces'].values():
+ if_pci = ifc['pci_address'].replace('.', ':').split(':')
+ bus = '{:x}'.format(int(if_pci[1], 16))
+ dev = '{:x}'.format(int(if_pci[2], 16))
+ fun = '{:x}'.format(int(if_pci[3], 16))
+ loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun)
+ if ifc['model'] == 'Intel-XL710':
+ ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
+ elif ifc['model'] == 'Intel-X710':
+ ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
+ elif ifc['model'] == 'Intel-X520-DA2':
+ ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
+ elif ifc['model'] == 'Cisco-VIC-1385':
+ ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
+ elif ifc['model'] == 'Cisco-VIC-1227':
+ ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
+ else:
+ ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
+
+ @staticmethod
+ def update_nic_interface_names_on_all_duts(nodes):
+ """Update interface names based on nic type and PCI address on all DUTs.
+
+ This method updates interface names in the same format as VPP does.
+
+ :param nodes: Topology nodes.
+ :type nodes: dict
+ """
+ for node in nodes.values():
+ if node['type'] == NodeType.DUT:
+ InterfaceUtil.update_nic_interface_names(node)
+
@staticmethod
def update_tg_interface_data_on_node(node):
"""Update interface name for TG/linux node in DICT__nodes.
:param node: Node selected from DICT__nodes.
:type node: dict
+ :raises RuntimeError: If getting of interface name and MAC fails.
.. note::
# for dev in `ls /sys/class/net/`;
(ret_code, stdout, _) = ssh.exec_command(cmd)
if int(ret_code) != 0:
- raise Exception('Get interface name and MAC failed')
+ raise RuntimeError('Get interface name and MAC failed')
tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
interfaces = JsonParser().parse_data(tmp)
for interface in node['interfaces'].values():
InterfaceUtil.tg_set_interfaces_udev_rules(node)
@staticmethod
- def update_all_interface_data_on_all_nodes(nodes):
+ def iface_update_numa_node(node):
+ """For all interfaces from topology file update numa node based on
+ information from the node.
+
+ :param node: Node from topology.
+ :type node: dict
+ :returns: Nothing.
+ :raises ValueError: If numa node ia less than 0.
+ :raises RuntimeError: If update of numa node failes.
+ """
+ ssh = SSH()
+ for if_key in Topology.get_node_interfaces(node):
+ if_pci = Topology.get_interface_pci_addr(node, if_key)
+ ssh.connect(node)
+ cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
+ for _ in range(3):
+ (ret, out, _) = ssh.exec_command(cmd)
+ if ret == 0:
+ try:
+ numa_node = int(out)
+ if numa_node < 0:
+ raise ValueError
+ except ValueError:
+ logger.trace('Reading numa location failed for: {0}'\
+ .format(if_pci))
+ else:
+ Topology.set_interface_numa_node(node, if_key,
+ numa_node)
+ break
+ else:
+ raise RuntimeError('Update numa node failed for: {0}'\
+ .format(if_pci))
+
+ @staticmethod
+ def update_all_numa_nodes(nodes, skip_tg=False):
+ """For all nodes and all their interfaces from topology file update numa
+ node information based on information from the node.
+
+ :param nodes: Nodes in the topology.
+ :param skip_tg: Skip TG node
+ :type nodes: dict
+ :type skip_tg: bool
+ :returns: Nothing.
+ """
+ for node in nodes.values():
+ if node['type'] == NodeType.DUT:
+ InterfaceUtil.iface_update_numa_node(node)
+ elif node['type'] == NodeType.TG and not skip_tg:
+ InterfaceUtil.iface_update_numa_node(node)
+
+ @staticmethod
+ def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
+ numa_node=False):
"""Update interface names on all nodes in DICT__nodes.
This method updates the topology dictionary by querying interface lists
of all nodes mentioned in the topology dictionary.
:param nodes: Nodes in the topology.
+ :param skip_tg: Skip TG node
+ :param numa_node: Retrieve numa_node location.
:type nodes: dict
+ :type skip_tg: bool
+ :type numa_node: bool
"""
for node_data in nodes.values():
if node_data['type'] == NodeType.DUT:
InterfaceUtil.update_vpp_interface_data_on_node(node_data)
- elif node_data['type'] == NodeType.TG:
+ elif node_data['type'] == NodeType.TG and not skip_tg:
InterfaceUtil.update_tg_interface_data_on_node(node_data)
+ if numa_node:
+ if node_data['type'] == NodeType.DUT:
+ InterfaceUtil.iface_update_numa_node(node_data)
+ elif node_data['type'] == NodeType.TG and not skip_tg:
+ InterfaceUtil.iface_update_numa_node(node_data)
+
@staticmethod
def create_vlan_subinterface(node, interface, vlan):
"""Create VLAN subinterface on node.
:type node: dict
:type interface: str
:type vlan: int
- :return: Name and index of created subinterface.
+ :returns: Name and index of created subinterface.
:rtype: tuple
+ :raises RuntimeError: if it is unable to create VLAN subinterface on the
+ node.
"""
- sw_if_index = Topology.get_interface_sw_index(node, interface)
+ iface_key = Topology.get_interface_by_name(node, interface)
+ sw_if_index = Topology.get_interface_sw_index(node, iface_key)
output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
sw_if_index=sw_if_index,
vlan=vlan)
if output[0]["retval"] == 0:
- sw_subif_index = output[0]["sw_if_index"]
+ sw_subif_idx = output[0]["sw_if_index"]
logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
- 'created on node {}'.format(sw_subif_index,
+ 'created on node {}'.format(sw_subif_idx,
vlan, node['host']))
+ if_key = Topology.add_new_port(node, "vlan_subif")
+ Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx)
+ Topology.update_interface_name(node, if_key, ifc_name)
else:
raise RuntimeError('Unable to create VLAN subinterface on node {}'
.format(node['host']))
with VatTerminal(node, False) as vat:
vat.vat_terminal_exec_cmd('exec show interfaces')
- return '{}.{}'.format(interface, vlan), sw_subif_index
+ return '{}.{}'.format(interface, vlan), sw_subif_idx
@staticmethod
def create_vxlan_interface(node, vni, source_ip, destination_ip):
:type vni: int
:type source_ip: str
:type destination_ip: str
- :return: SW IF INDEX of created interface.
+ :returns: SW IF INDEX of created interface.
:rtype: int
+ :raises RuntimeError: if it is unable to create VxLAN interface on the
+ node.
"""
output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
src=source_ip,
output = output[0]
if output["retval"] == 0:
- return output["sw_if_index"]
+ sw_if_idx = output["sw_if_index"]
+ if_key = Topology.add_new_port(node, "vxlan_tunnel")
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
+ Topology.update_interface_name(node, if_key, ifc_name)
+ return sw_if_idx
else:
- raise RuntimeError('Unable to create VXLAN interface on node {}'
+ raise RuntimeError("Unable to create VXLAN interface on node {0}"
.format(node))
@staticmethod
If None, information about all VxLAN interfaces is returned.
:type node: dict
:type interface: int or str
- :return: Dictionary containing data for the given VxLAN interface or if
+ :returns: Dictionary containing data for the given VxLAN interface or if
interface=None, the list of dictionaries with all VxLAN interfaces.
- :rtype dict or list
+ :rtype: dict or list
+ :raises TypeError: if the data type of interface is neither basestring
+ nor int.
"""
param = "sw_if_index"
if interface is None:
elif isinstance(interface, int):
sw_if_index = interface
else:
- raise Exception("Wrong interface format {0}".format(interface))
+ raise TypeError("Wrong interface format {0}".format(interface))
with VatTerminal(node) as vat:
response = vat.vat_terminal_exec_cmd_from_template(
return response[0]
@staticmethod
- def create_subinterface(node, interface, sub_id, outer_vlan_id,
- inner_vlan_id, type_subif):
- """Create sub-interface on node.
+ def vhost_user_dump(node):
+ """Get vhost-user data for the given node.
+
+ :param node: VPP node to get interface data from.
+ :type node: dict
+ :returns: List of dictionaries with all vhost-user interfaces.
+ :rtype: list
+ """
+ with VatTerminal(node) as vat:
+ response = vat.vat_terminal_exec_cmd_from_template(
+ "vhost_user_dump.vat")
+
+ return response[0]
+
+ @staticmethod
+ def tap_dump(node, name=None):
+ """Get all TAP interface data from the given node, or data about
+ a specific TAP interface.
+
+ :param node: VPP node to get data from.
+ :param name: Optional name of a specific TAP interface.
+ :type node: dict
+ :type name: str
+ :returns: Dictionary of information about a specific TAP interface, or
+ a List of dictionaries containing all TAP data for the given node.
+ :rtype: dict or list
+ """
+ with VatTerminal(node) as vat:
+ response = vat.vat_terminal_exec_cmd_from_template(
+ "tap_dump.vat")
+ if name is None:
+ return response[0]
+ else:
+ for item in response[0]:
+ if name == item['dev_name']:
+ return item
+ return {}
+
+ @staticmethod
+ def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
+ inner_vlan_id=None, type_subif=None):
+ """Create sub-interface on node. It is possible to set required
+ sub-interface type and VLAN tag(s).
:param node: Node to add sub-interface.
:param interface: Interface name on which create sub-interface.
:param sub_id: ID of the sub-interface to be created.
- :param outer_vlan_id: Outer VLAN ID.
- :param inner_vlan_id: Inner VLAN ID.
- :param type_subif: Type of sub-interface.
+ :param outer_vlan_id: Optional outer VLAN ID.
+ :param inner_vlan_id: Optional inner VLAN ID.
+ :param type_subif: Optional type of sub-interface. Values supported by
+ VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match] [default_sub]
:type node: dict
:type interface: str or int
:type sub_id: int
:type outer_vlan_id: int
:type inner_vlan_id: int
:type type_subif: str
- :return: name and index of created sub-interface
+ :returns: Name and index of created sub-interface.
:rtype: tuple
+ :raises RuntimeError: If it is not possible to create sub-interface.
"""
+ outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
+ if outer_vlan_id else ''
+
+ inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
+ if inner_vlan_id else ''
+
+ if type_subif is None:
+ type_subif = ''
+
if isinstance(interface, basestring):
- sw_if_index = Topology.get_interface_sw_index(node, interface)
+ iface_key = Topology.get_interface_by_name(node, interface)
+ sw_if_index = Topology.get_interface_sw_index(node, iface_key)
else:
sw_if_index = interface
type_subif=type_subif)
if output[0]["retval"] == 0:
- sw_subif_index = output[0]["sw_if_index"]
+ sw_subif_idx = output[0]["sw_if_index"]
logger.trace('Created subinterface with index {}'
- .format(sw_subif_index))
+ .format(sw_subif_idx))
+ if_key = Topology.add_new_port(node, "subinterface")
+ Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx)
+ Topology.update_interface_name(node, if_key, ifc_name)
else:
- raise RuntimeError('Unable to create subinterface on node {}'
+ raise RuntimeError('Unable to create sub-interface on node {}'
.format(node['host']))
- with VatTerminal(node) as vat:
+ with VatTerminal(node, json_param=False) as vat:
vat.vat_terminal_exec_cmd('exec show interfaces')
- return '{}.{}'.format(interface, sub_id), sw_subif_index
+ name = '{}.{}'.format(interface, sub_id)
+ return name, sw_subif_idx
+
+ @staticmethod
+ def create_gre_tunnel_interface(node, source_ip, destination_ip):
+ """Create GRE tunnel interface on node.
+
+ :param node: VPP node to add tunnel interface.
+ :param source_ip: Source of the GRE tunnel.
+ :param destination_ip: Destination of the GRE tunnel.
+ :type node: dict
+ :type source_ip: str
+ :type destination_ip: str
+ :returns: Name and index of created GRE tunnel interface.
+ :rtype: tuple
+ :raises RuntimeError: If unable to create GRE tunnel interface.
+ """
+ output = VatExecutor.cmd_from_template(node, "create_gre.vat",
+ src=source_ip,
+ dst=destination_ip)
+ output = output[0]
+
+ if output["retval"] == 0:
+ sw_if_idx = output["sw_if_index"]
+
+ vat_executor = VatExecutor()
+ vat_executor.execute_script_json_out("dump_interfaces.vat", node)
+ interface_dump_json = vat_executor.get_script_stdout()
+ name = VatJsonUtil.get_interface_name_from_json(
+ interface_dump_json, sw_if_idx)
+
+ if_key = Topology.add_new_port(node, "gre_tunnel")
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
+ Topology.update_interface_name(node, if_key, name)
+
+ return name, sw_if_idx
+ else:
+ raise RuntimeError('Unable to create GRE tunnel on node {}.'
+ .format(node))
@staticmethod
def vpp_create_loopback(node):
:param node: Node to create loopback interface on.
:type node: dict
- :return: SW interface index.
+ :returns: SW interface index.
:rtype: int
+ :raises RuntimeError: If it is not possible to create loopback on the
+ node.
"""
out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
if out[0].get('retval') == 0:
- return out[0].get('sw_if_index')
+ sw_if_idx = out[0].get('sw_if_index')
+ if_key = Topology.add_new_port(node, "loopback")
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
+ Topology.update_interface_name(node, if_key, ifc_name)
+ return sw_if_idx
else:
raise RuntimeError('Create loopback failed on node "{}"'
.format(node['host']))
sw_if_index=sw_if_index,
ip_version=ip_version,
table_index=table_index)
+
+ @staticmethod
+ def get_interface_classify_table(node, interface):
+ """Get name of classify table for the given interface.
+
+ :param node: VPP node to get data from.
+ :param interface: Name or sw_if_index of a specific interface.
+ :type node: dict
+ :type interface: str or int
+ :returns: Classify table name.
+ :rtype: str
+ """
+ if isinstance(interface, basestring):
+ sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+ else:
+ sw_if_index = interface
+
+ with VatTerminal(node) as vat:
+ data = vat.vat_terminal_exec_cmd_from_template(
+ "classify_interface_table.vat",
+ sw_if_index=sw_if_index)
+ return data[0]
+
+ @staticmethod
+ def get_interface_vrf_table(node, interface):
+ """Get vrf ID for the given interface.
+
+ :param node: VPP node.
+ :param interface: Name or sw_if_index of a specific interface.
+ :type node: dict
+ :type interface: str or int
+ :returns: vrf ID of the specified interface.
+ :rtype: int
+ """
+
+ if isinstance(interface, basestring):
+ sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+ else:
+ sw_if_index = interface
+
+ with VatTerminal(node) as vat:
+ data = vat.vat_terminal_exec_cmd_from_template(
+ "interface_vrf_dump.vat",
+ sw_if_index=sw_if_index)
+ return data[0]["vrf_id"]
+
+ @staticmethod
+ def get_sw_if_index(node, interface_name):
+ """Get sw_if_index for the given interface from actual interface dump.
+
+ :param node: VPP node to get interface data from.
+ :param interface_name: Name of the specific interface.
+ :type node: dict
+ :type interface_name: str
+ :returns: sw_if_index of the given interface.
+ :rtype: str
+ """
+
+ with VatTerminal(node) as vat:
+ if_data = vat.vat_terminal_exec_cmd_from_template(
+ "interface_dump.vat")
+ for interface in if_data[0]:
+ if interface["interface_name"] == interface_name:
+ return interface["sw_if_index"]
+
+ return None
+
+ @staticmethod
+ def vxlan_gpe_dump(node, interface_name=None):
+ """Get VxLAN GPE data for the given interface.
+
+ :param node: VPP node to get interface data from.
+ :param interface_name: Name of the specific interface. If None,
+ information about all VxLAN GPE interfaces is returned.
+ :type node: dict
+ :type interface_name: str
+ :returns: Dictionary containing data for the given VxLAN GPE interface
+ or if interface=None, the list of dictionaries with all VxLAN GPE
+ interfaces.
+ :rtype: dict or list
+ """
+
+ with VatTerminal(node) as vat:
+ vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
+ "vxlan_gpe_dump.vat")
+
+ if interface_name:
+ sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
+ if sw_if_index:
+ for vxlan_gpe in vxlan_gpe_data[0]:
+ if vxlan_gpe["sw_if_index"] == sw_if_index:
+ return vxlan_gpe
+ return {}
+
+ return vxlan_gpe_data[0]
+
+ @staticmethod
+ def vpp_proxy_arp_interface_enable(node, interface):
+ """Enable proxy ARP on interface.
+
+ :param node: VPP node to enable proxy ARP on interface.
+ :param interface: Interface to enable proxy ARP.
+ :type node: dict
+ :type interface: str or int
+ """
+ if isinstance(interface, basestring):
+ sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+ else:
+ sw_if_index = interface
+
+ with VatTerminal(node) as vat:
+ vat.vat_terminal_exec_cmd_from_template(
+ "proxy_arp_intfc_enable.vat",
+ sw_if_index=sw_if_index)
+
+ @staticmethod
+ def vpp_ip_source_check_setup(node, interface):
+ """Setup Reverse Path Forwarding source check on interface.
+
+ :param node: Node to setup RPF source check.
+ :param interface: Interface name to setup RPF source check.
+ :type node: dict
+ :type interface: str
+ """
+ with VatTerminal(node) as vat:
+ vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
+ interface_name=interface)
+
+ @staticmethod
+ def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
+ """Assign VPP interface to specific VRF/FIB table.
+
+ :param node: VPP node where the FIB and interface are located.
+ :param interface: Interface to be assigned to FIB.
+ :param table_id: VRF table ID.
+ :param ipv6: Assign to IPv6 table. Default False.
+ :type node: dict
+ :type interface: str or int
+ :type table_id: int
+ :type ipv6: bool
+ """
+ if isinstance(interface, basestring):
+ sw_if_index = Topology.get_interface_sw_index(node, interface)
+ else:
+ sw_if_index = interface
+
+ ipv6 = 'ipv6' if ipv6 else ''
+
+ with VatTerminal(node) as vat:
+ ret = vat.vat_terminal_exec_cmd_from_template(
+ "set_fib_to_interface.vat",
+ sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
+
+ if ret[0]["retval"] != 0:
+ raise RuntimeError('Unable to assign interface to FIB node {}.'
+ .format(node))
+
+ @staticmethod
+ def set_linux_interface_mac(node, interface, mac, namespace=None):
+ """Set MAC address for interface in linux.
+
+ :param node: Node where to execute command.
+ :param interface: Interface in namespace.
+ :param mac: MAC to be assigned to interface.
+ :param namespace: Execute command in namespace. Optional
+ :type node: dict
+ :type interface: str
+ :type mac: str
+ :type namespace: str
+ """
+ if namespace is not None:
+ cmd = 'ip netns exec {} ip link set {} address {}'.format(
+ namespace, interface, mac)
+ else:
+ cmd = 'ip link set {} address {}'.format(interface, mac)
+ exec_cmd_no_error(node, cmd, sudo=True)