Skip to content

Commit

Permalink
Merge pull request #349 from fabric-testbed/sub-imterface-support
Browse files Browse the repository at this point in the history
Sub interface support
  • Loading branch information
kthare10 authored Jul 9, 2024
2 parents 67d98f4 + 187fb53 commit 06d4abc
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
# Unreleased

### Fixed
- Sub Interface Support (Issue [#350](https://github.com/fabric-testbed/fabrictestbed-extensions/issues/350))
- Advanced reservations (Issue [#345](https://github.com/fabric-testbed/fabrictestbed-extensions/issues/345))
- Port Mirroring with Basic NICs (Issue [#343](https://github.com/fabric-testbed/fabrictestbed-extensions/issues/343))
- P4 support (Issue [#340](https://github.com/fabric-testbed/fabrictestbed-extensions/issues/340))
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,4 @@ help FABlib, please review the [guidelines] first.

[guidelines]: ./CONTRIBUTING.md


52 changes: 29 additions & 23 deletions fabrictestbed_extensions/fablib/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@

import jinja2

from fabrictestbed_extensions.fablib.constants import Constants

if TYPE_CHECKING:
from fabrictestbed_extensions.fablib.slice import Slice
from fabrictestbed_extensions.fablib.node import Node
Expand All @@ -60,17 +62,17 @@

class Component:
component_model_map = {
"NIC_Basic": ComponentModelType.SharedNIC_ConnectX_6,
"NIC_ConnectX_6": ComponentModelType.SmartNIC_ConnectX_6,
"NIC_ConnectX_5": ComponentModelType.SmartNIC_ConnectX_5,
"NIC_P4": "P4_DedicatedPort",
"NVME_P4510": ComponentModelType.NVME_P4510,
"GPU_TeslaT4": ComponentModelType.GPU_Tesla_T4,
"GPU_RTX6000": ComponentModelType.GPU_RTX6000,
"GPU_A40": ComponentModelType.GPU_A40,
"GPU_A30": ComponentModelType.GPU_A30,
"NIC_OpenStack": ComponentModelType.SharedNIC_OpenStack_vNIC,
"FPGA_Xilinx_U280": ComponentModelType.FPGA_Xilinx_U280,
Constants.CMP_NIC_Basic: ComponentModelType.SharedNIC_ConnectX_6,
Constants.CMP_NIC_ConnectX_6: ComponentModelType.SmartNIC_ConnectX_6,
Constants.CMP_NIC_ConnectX_5: ComponentModelType.SmartNIC_ConnectX_5,
Constants.CMP_NIC_P4: Constants.P4_DedicatedPort,
Constants.CMP_NVME_P4510: ComponentModelType.NVME_P4510,
Constants.CMP_GPU_TeslaT4: ComponentModelType.GPU_Tesla_T4,
Constants.CMP_GPU_RTX6000: ComponentModelType.GPU_RTX6000,
Constants.CMP_GPU_A40: ComponentModelType.GPU_A40,
Constants.CMP_GPU_A30: ComponentModelType.GPU_A30,
Constants.CMP_NIC_OpenStack: ComponentModelType.SharedNIC_OpenStack_vNIC,
Constants.CMP_FPGA_Xilinx_U280: ComponentModelType.FPGA_Xilinx_U280,
}

def __str__(self):
Expand Down Expand Up @@ -317,10 +319,13 @@ def __init__(self, node: Node = None, fim_component: FimComponent = None):
self.node = node
self.interfaces = None

def get_interfaces(self) -> List[Interface]:
def get_interfaces(self, include_subs: bool = True) -> List[Interface]:
"""
Gets the interfaces attached to this fablib component's FABRIC component.
:param include_subs: Flag indicating if sub interfaces should be included
:type include_subs: bool
:return: a list of the interfaces on this component.
:rtype: List[Interface]
"""
Expand All @@ -330,9 +335,12 @@ def get_interfaces(self) -> List[Interface]:
if not self.interfaces:
self.interfaces = []
for fim_interface in self.get_fim_component().interface_list:
self.interfaces.append(
Interface(component=self, fim_interface=fim_interface)
)
iface = Interface(component=self, fim_interface=fim_interface)
self.interfaces.append(iface)
if include_subs:
child_interfaces = iface.get_interfaces()
if child_interfaces and len(child_interfaces):
self.interfaces.extend(child_interfaces)

return self.interfaces

Expand Down Expand Up @@ -448,25 +456,23 @@ def get_model(self) -> str:
str(self.get_type()) == "SmartNIC"
and str(self.get_fim_model()) == "ConnectX-6"
):
return "NIC_ConnectX_6"
return Constants.CMP_NIC_ConnectX_6
elif (
str(self.get_type()) == "SmartNIC"
and str(self.get_fim_model()) == "ConnectX-5"
):
return "NIC_ConnectX_5"
return Constants.CMP_NIC_ConnectX_5
elif str(self.get_type()) == "NVME" and str(self.get_fim_model()) == "P4510":
return "NVME_P4510"
return Constants.CMP_NVME_P4510
elif str(self.get_type()) == "GPU" and str(self.get_fim_model()) == "Tesla T4":
return "GPU_TeslaT4"
return Constants.CMP_GPU_TeslaT4
elif str(self.get_type()) == "GPU" and str(self.get_fim_model()) == "RTX6000":
return "GPU_RTX6000"
return Constants.CMP_GPU_RTX6000
elif (
str(self.get_type()) == "SharedNIC"
and str(self.get_fim_model()) == "ConnectX-6"
):
return "NIC_Basic"
else:
return None
return Constants.CMP_NIC_Basic

def get_reservation_id(self) -> str or None:
"""
Expand Down
13 changes: 13 additions & 0 deletions fabrictestbed_extensions/fablib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,16 @@ class Constants:
CPUS = "CPUs"
HOSTS = "Hosts"
P4_SWITCH = "P4-Switch"

CMP_NIC_Basic = "NIC_Basic"
CMP_NIC_ConnectX_6 = "NIC_ConnectX_6"
CMP_NIC_ConnectX_5 = "NIC_ConnectX_5"
CMP_NIC_P4 = "NIC_P4"
CMP_NVME_P4510 = "NVME_P4510"
CMP_GPU_TeslaT4 = "GPU_TeslaT4"
CMP_GPU_RTX6000 = "GPU_RTX6000"
CMP_GPU_A40 = "GPU_A40"
CMP_GPU_A30 = "GPU_A30"
CMP_NIC_OpenStack = "NIC_OpenStack"
CMP_FPGA_Xilinx_U280 = "FPGA_Xilinx_U280"
P4_DedicatedPort = "P4_DedicatedPort"
100 changes: 97 additions & 3 deletions fabrictestbed_extensions/fablib/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@
import json
import logging
from ipaddress import IPv4Address
from typing import TYPE_CHECKING, Any, Union
from typing import TYPE_CHECKING, Any, List, Union

import jinja2
from fabrictestbed.slice_editor import Flags
from fim.user import Labels
from fim.user import Capacities, InterfaceType, Labels
from tabulate import tabulate

from fabrictestbed_extensions.fablib.constants import Constants

if TYPE_CHECKING:
from fabrictestbed_extensions.fablib.slice import Slice
from fabrictestbed_extensions.fablib.node import Node
Expand All @@ -66,6 +68,7 @@ def __init__(
fim_interface: FimInterface = None,
node: Union[Switch, FacilityPort] = None,
model: str = None,
parent: Interface = None,
):
"""
.. note::
Expand All @@ -89,6 +92,8 @@ def __init__(
self.dev = None
self.node = node
self.model = model
self.interfaces = None
self.parent = parent

def get_fablib_manager(self):
return self.get_slice().get_fablib_manager()
Expand Down Expand Up @@ -448,7 +453,12 @@ def get_mac(self) -> str:
:rtype: String
"""
try:
mac = self.get_fim_interface().get_property(pname="label_allocations").mac
if self.parent:
mac = self.parent.get_mac()
else:
mac = (
self.get_fim_interface().get_property(pname="label_allocations").mac
)
except:
mac = None

Expand Down Expand Up @@ -719,6 +729,9 @@ def get_short_name(self):
:return: Shortened name of the interface.
:rtype: str
"""
if self.parent:
return self.get_name()

# Strip off the extra parts of the name added by FIM
prefix_length = len(
f"{self.get_node().get_name()}-{self.get_component().get_short_name()}-"
Expand Down Expand Up @@ -1193,6 +1206,8 @@ def delete(self):
net = self.get_network()
if net:
net.remove_interface(self)
if self.parent and self.parent.get_fim():
self.parent.get_fim().remove_child_interface(name=self.get_name())

def set_subnet(self, ipv4_subnet: str = None, ipv6_subnet: str = None):
"""
Expand Down Expand Up @@ -1278,3 +1293,82 @@ def get_peer_account_id(self):
"""
if self.get_fim() and self.get_fim().peer_labels:
return self.get_fim().peer_labels.account_id

def get_interfaces(self) -> List[Interface]:
"""
Gets the interfaces attached to this fablib component's FABRIC component.
:return: a list of the interfaces on this component.
:rtype: List[Interface]
"""

if not self.interfaces:
self.interfaces = []
for fim_interface in self.get_fim().interface_list:
self.interfaces.append(
Interface(
component=self.get_component(),
fim_interface=fim_interface,
model=str(InterfaceType.SubInterface),
parent=self,
)
)

return self.interfaces

def add_sub_interface(self, name: str, vlan: str, bw: int = 10):
"""
Add a sub-interface to a dedicated NIC.
This method adds a sub-interface to a NIC (Network Interface Card) with the specified
name, VLAN (Virtual Local Area Network) ID, and bandwidth. It supports only specific
NIC models.
:param name: The name of the sub-interface.
:type name: str
:param vlan: The VLAN ID for the sub-interface.
:type vlan: str
:param bw: The bandwidth allocated to the sub-interface, in Gbps. Default is 10 Gbps.
:type bw: int
:raises Exception: If the NIC model does not support sub-interfaces.
"""
if self.get_model() not in [
Constants.CMP_NIC_ConnectX_5,
Constants.CMP_NIC_ConnectX_6,
]:
raise Exception(
f"Sub interfaces are only supported for the following NIC models: "
f"{Constants.CMP_NIC_ConnectX_5}, {Constants.CMP_NIC_ConnectX_6}"
)

if self.get_fim():
child_interface = self.get_fim().add_child_interface(
name=name, labels=Labels(vlan=vlan)
)
child_if_capacities = child_interface.get_property(pname="capacities")
if not child_if_capacities:
child_if_capacities = Capacities()
child_if_capacities.bw = int(bw)
child_interface.set_properties(capacities=child_if_capacities)
if not self.interfaces:
self.interfaces = []

ch_iface = Interface(
component=self.get_component(),
fim_interface=child_interface,
model=str(InterfaceType.SubInterface),
)
self.interfaces.append(ch_iface)
return ch_iface

def get_type(self) -> str:
"""
Get Interface type
:return: get interface type
:rtype: String
"""
if self.get_fim():
return self.get_fim().type
7 changes: 5 additions & 2 deletions fabrictestbed_extensions/fablib/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1024,16 +1024,19 @@ def get_error_message(self) -> str or None:
except:
return ""

def get_interfaces(self) -> List[Interface] or None:
def get_interfaces(self, include_subs: bool = True) -> List[Interface] or None:
"""
Gets a list of the interfaces associated with the FABRIC node.
:param include_subs: Flag indicating if sub interfaces should be included
:type include_subs: bool
:return: a list of interfaces on the node
:rtype: List[Interface]
"""
interfaces = []
for component in self.get_components():
for interface in component.get_interfaces():
for interface in component.get_interfaces(include_subs=include_subs):
interfaces.append(interface)

return interfaces
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies = [
"ipyleaflet",
"ipycytoscape",
"tabulate",
"fabrictestbed==1.7.0b11",
"fabrictestbed==1.7.0b12",
"paramiko",
"jinja2>=3.0.0",
"pandas",
Expand Down

0 comments on commit 06d4abc

Please sign in to comment.