Skip to content

Commit

Permalink
Merge pull request #500 from open-traffic-generator/loopback_support
Browse files Browse the repository at this point in the history
loopback support
  • Loading branch information
alakendu authored Mar 16, 2022
2 parents a4397a8 + fc605ed commit 2800cb4
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 63 deletions.
5 changes: 5 additions & 0 deletions snappi_ixnetwork/device/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def multivalue(self, value, enum=None):
value = enum[value]
return MultiValue(value)

def as_multivalue(self, snappi_obj, name, enum=None):
return self.multivalue(
snappi_obj.get(name), enum
)

def post_calculated(self, key, ref_ixnobj=None, ixnobj=None):
return PostCalculated(
key, ref_ixnobj, ixnobj
Expand Down
12 changes: 6 additions & 6 deletions snappi_ixnetwork/device/bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,16 @@ def _config_ipv4_interfaces(self, bgp):
is_invalid = False
ipv4_name = ipv4_interface.get("ipv4_name")
if ipv4_name in self._invalid_ips:
self._ngpf._api.add_error("Multiple IP {name} on top of name Ethernet".format(
self._ngpf.api.add_error("Multiple IP {name} on top of name Ethernet".format(
name=ipv4_name
))
is_invalid = True
if ipv4_name not in self._same_dg_ips:
self._ngpf._api.add_error("BGP should not configured on top of different device")
self._ngpf.api.add_error("BGP should not configured on top of different device")
is_invalid = True
if is_invalid:
continue
ixn_ipv4 = self._ngpf._api.ixn_objects.get_object(ipv4_name)
ixn_ipv4 = self._ngpf.api.ixn_objects.get_object(ipv4_name)
self._config_bgpv4(ipv4_interface.get("peers"),
ixn_ipv4)

Expand All @@ -163,16 +163,16 @@ def _config_ipv6_interfaces(self, bgp):
is_invalid = False
ipv6_name = ipv6_interface.get("ipv6_name")
if ipv6_name in self._invalid_ips:
self._ngpf._api.add_error("Multiple IP {name} on top of name Ethernet".format(
self._ngpf.api.add_error("Multiple IP {name} on top of name Ethernet".format(
name=ipv6_name
))
is_invalid = True
if ipv6_name not in self._same_dg_ips:
self._ngpf._api.add_error("BGP should not configured on top of different device")
self._ngpf.api.add_error("BGP should not configured on top of different device")
is_invalid = True
if is_invalid:
continue
ixn_ipv6 = self._ngpf._api.ixn_objects.get_object(ipv6_name)
ixn_ipv6 = self._ngpf.api.ixn_objects.get_object(ipv6_name)
self._config_bgpv6(ipv6_interface.get("peers"),
ixn_ipv6)

Expand Down
File renamed without changes.
55 changes: 55 additions & 0 deletions snappi_ixnetwork/device/loopbackint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from snappi_ixnetwork.device.base import Base


class LoopbackInt(Base):
def __init__(self, ngpf):
super(LoopbackInt, self).__init__()
self._ngpf = ngpf
self._ixn_parent_dgs = []

def config(self):
self._ixn_parent_dgs = []
for device in self._ngpf.api.snappi_config.devices:
ipv4_loopbacks = device.get("ipv4_loopbacks")
if ipv4_loopbacks is not None:
self._config_ipv4_loopbacks(ipv4_loopbacks, device)
ipv6_loopbacks = device.get("ipv6_loopbacks")
if ipv6_loopbacks is not None:
self._config_ipv6_loopbacks(ipv6_loopbacks, device)
return self._ixn_parent_dgs

def _create_dg(self, loop_back, device):
eth_name = loop_back.get("eth_name")
if eth_name not in self._ngpf.api.ixn_objects.names:
raise Exception("Ethernet %s not present within configuration"
% eth_name)
ixn_parent_dg = self._ngpf.api.ixn_objects.get_working_dg(
eth_name
)
self._ixn_parent_dgs.append(ixn_parent_dg)
ixn_dg = self.create_node_elemet(
ixn_parent_dg, "deviceGroup", "loopback_{}".format(device.get("name"))
)
ixn_dg["multiplier"] = 1
self._ngpf.working_dg = ixn_dg
return ixn_dg

def _config_ipv4_loopbacks(self, ipv4_loopbacks, device):
for ipv4_loopback in ipv4_loopbacks:
ixn_dg = self._create_dg(ipv4_loopback, device)
ixn_v4lb = self.create_node_elemet(
ixn_dg, "ipv4Loopback", ipv4_loopback.get("name")
)
self._ngpf.set_device_info(ipv4_loopback, ixn_v4lb)
ixn_v4lb["address"] = self.as_multivalue(ipv4_loopback, "address")

def _config_ipv6_loopbacks(self, ipv6_loopbacks, device):
for ipv6_loopback in ipv6_loopbacks:
ixn_dg = self._create_dg(ipv6_loopback, device)
ixn_v4lb = self.create_node_elemet(
ixn_dg, "ipv6Loopback", ipv6_loopback.get("name")
)
self._ngpf.set_device_info(ipv6_loopback, ixn_v4lb)
ixn_v4lb["address"] = self.as_multivalue(ipv6_loopback, "address")


122 changes: 71 additions & 51 deletions snappi_ixnetwork/device/ngpf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from snappi_ixnetwork.timer import Timer
from snappi_ixnetwork.device.base import Base
from snappi_ixnetwork.device.bgp import Bgp
from snappi_ixnetwork.device.ethernet import Ethernet
from snappi_ixnetwork.device.interface import Ethernet
from snappi_ixnetwork.device.loopbackint import LoopbackInt
from snappi_ixnetwork.device.compactor import Compactor
from snappi_ixnetwork.device.createixnconfig import CreateIxnConfig

Expand All @@ -17,7 +18,9 @@ class Ngpf(Base):
"BgpV4Peer": "ipv4",
"BgpV6Peer": "ipv6",
"BgpV4RouteRange": "ipv4",
"BgpV6RouteRange": "ipv6"
"BgpV6RouteRange": "ipv6",
"DeviceIpv4Loopback": "ipv4",
"DeviceIpv6Loopback": "ipv6",
}

_ROUTE_STATE = {
Expand All @@ -27,14 +30,16 @@ class Ngpf(Base):

def __init__(self, ixnetworkapi):
super(Ngpf, self).__init__()
self._api = ixnetworkapi
self.api = ixnetworkapi
self._ixn_config = {}
self.working_dg = None
self._ixn_topo_objects = {}
self.ether_v4gateway_map = {}
self.ether_v6gateway_map = {}
self._ethernet = Ethernet(self)
self._bgp = Bgp(self)
self.compactor = Compactor(self._api)
self._loop_back = LoopbackInt(self)
self.compactor = Compactor(self.api)
self._createixnconfig = CreateIxnConfig(self)

def config(self):
Expand All @@ -44,14 +49,14 @@ def config(self):
self.ether_v4gateway_map = {}
self.ether_v6gateway_map = {}
self._ixn_config["xpath"] = "/"
self._resource_manager = self._api._ixnetwork.ResourceManager
with Timer(self._api, "Convert device config :"):
self._resource_manager = self.api._ixnetwork.ResourceManager
with Timer(self.api, "Convert device config :"):
self._configure_topology()
with Timer(self._api, "Create IxNetwork config :"):
with Timer(self.api, "Create IxNetwork config :"):
self._createixnconfig.create(
self._ixn_config["topology"], "topology"
)
with Timer(self._api, "Push IxNetwork config :"):
with Timer(self.api, "Push IxNetwork config :"):
self._pushixnconfig()

def set_device_info(self, snappi_obj, ixn_obj):
Expand All @@ -63,15 +68,15 @@ def set_device_info(self, snappi_obj, ixn_obj):
raise NameError(
"Mapping is missing for {0}".format(class_name)
)
self._api.set_device_encap(name, encap)
self._api.set_device_encap(
self.api.set_device_encap(name, encap)
self.api.set_device_encap(
self.get_name(self.working_dg), encap
)
self._api.ixn_objects.set(name, ixn_obj)
self.api.ixn_objects.set(name, ixn_obj)

def set_ixn_routes(self, snappi_obj, ixn_obj):
name = snappi_obj.get("name")
self._api.ixn_routes.set(name, ixn_obj)
self.api.ixn_routes.set(name, ixn_obj)

def _get_topology_name(self, port_name):
return "Topology %s" % port_name
Expand All @@ -82,15 +87,26 @@ def _set_dev_compacted(self, dgs):
for dg in dgs:
names = dg.get("name")
if isinstance(names, list) and len(names) > 1:
self._api.set_dev_compacted(names[0], names)
self.api.set_dev_compacted(names[0], names)

def _configure_topology(self):
self.stop_topology()
self._api._remove(self._api._topology, [])
self.api._remove(self.api._topology, [])
ixn_topos = self.create_node(self._ixn_config, "topology")
for device in self._api.snappi_config.devices:
self._configure_device_group(device, ixn_topos)
ixn_parent_dgs = self._configure_device_group(ixn_topos)

# We need to configure all interface before configure protocols
for device in self.api.snappi_config.devices:
self.working_dg = self.api.ixn_objects.get_working_dg(device.name)
self._bgp.config(device)

# First compact all loopback interfaces
for ix_parent_dg in ixn_parent_dgs:
self.compactor.compact(ix_parent_dg.get(
"deviceGroup"
))

# Finally compact primary DGs
for ixn_topo in self._ixn_topo_objects.values():
self.compactor.compact(ixn_topo.get(
"deviceGroup"
Expand All @@ -99,63 +115,67 @@ def _configure_topology(self):
"deviceGroup"
))

def _configure_device_group(self, device, ixn_topos):
def _configure_device_group(self, ixn_topos):
"""map ethernet with a ixn deviceGroup with multiplier = 1"""
for ethernet in device.get("ethernets"):
port_name = ethernet.get("port_name")
if port_name in self._ixn_topo_objects:
ixn_topo = self._ixn_topo_objects[port_name]
else:
ixn_topo = self.add_element(ixn_topos)
ixn_topo["name"] = self._get_topology_name(port_name)
ixn_topo["ports"] = [self._api.ixn_objects.get_xpath(port_name)]
self._ixn_topo_objects[port_name] = ixn_topo
ixn_dg = self.create_node_elemet(
ixn_topo, "deviceGroup", device.get("name")
)
ixn_dg["multiplier"] = 1
self.working_dg = ixn_dg
self.set_device_info(device, ixn_dg)
self._ethernet.config(ethernet, ixn_dg)
self._bgp.config(device)
for device in self.api.snappi_config.devices:
for ethernet in device.get("ethernets"):
port_name = ethernet.get("port_name")
if port_name in self._ixn_topo_objects:
ixn_topo = self._ixn_topo_objects[port_name]
else:
ixn_topo = self.add_element(ixn_topos)
ixn_topo["name"] = self._get_topology_name(port_name)
ixn_topo["ports"] = [self.api.ixn_objects.get_xpath(port_name)]
self._ixn_topo_objects[port_name] = ixn_topo
ixn_dg = self.create_node_elemet(
ixn_topo, "deviceGroup", device.get("name")
)
ixn_dg["multiplier"] = 1
self.working_dg = ixn_dg
self.set_device_info(device, ixn_dg)
self._ethernet.config(ethernet, ixn_dg)

# Create all ethernet before start loopback
return self._loop_back.config()


def _pushixnconfig(self):
erros = self._api.get_errors()
erros = self.api.get_errors()
if len(erros) > 0:
return
ixn_cnf = json.dumps(self._ixn_config, indent=2)
errata = self._resource_manager.ImportConfig(
ixn_cnf, False
)
for item in errata:
self._api.warning(item)
self.api.warning(item)

def stop_topology(self):
glob_topo = self._api._globals.Topology.refresh()
glob_topo = self.api._globals.Topology.refresh()
if glob_topo.Status == "started":
self._api._ixnetwork.StopAllProtocols("sync")
self.api._ixnetwork.StopAllProtocols("sync")

def set_protocol_state(self,request):
if request.state is None:
raise Exception("state is None within set_protocol_state")
if request.state == "start":
if len(self._api._topology.find()) > 0:
self._api._ixnetwork.StartAllProtocols("sync")
self._api.check_protocol_statistics()
if len(self.api._topology.find()) > 0:
self.api._ixnetwork.StartAllProtocols("sync")
self.api.check_protocol_statistics()
else:
if len(self._api._topology.find()) > 0:
self._api._ixnetwork.StopAllProtocols("sync")
if len(self.api._topology.find()) > 0:
self.api._ixnetwork.StopAllProtocols("sync")

def set_route_state(self, payload):
if payload.state is None:
return
names = payload.names
if len(names) == 0:
names = self._api.ixn_routes.names
names = self.api.ixn_routes.names
ixn_obj_idx_list = {}
names = list(set(names))
for name in names:
route_info = self._api.ixn_routes.get(name)
route_info = self.api.ixn_routes.get(name)
ixn_obj = None
for obj in ixn_obj_idx_list.keys():
if obj.xpath == route_info.xpath:
Expand Down Expand Up @@ -184,17 +204,17 @@ def set_route_state(self, payload):
xpath, active, values
))
self.imports(imports)
self._api._ixnetwork.Globals.Topology.ApplyOnTheFly()
self.api._ixnetwork.Globals.Topology.ApplyOnTheFly()
return names

def get_states(self, request):
if request.choice == "ipv4_neighbors":
ip_objs = self._api._ixnetwork.Topology.find().DeviceGroup.find().Ethernet.find().Ipv4.find()
ip_objs = self.api._ixnetwork.Topology.find().DeviceGroup.find().Ethernet.find().Ipv4.find()
resolved_mac_list = self._get_ether_resolved_mac(
ip_objs, self.ether_v4gateway_map, request.ipv4_neighbors, "ipv4"
)
elif request.choice == "ipv6_neighbors":
ip_objs = self._api._ixnetwork.Topology.find().DeviceGroup.find().Ethernet.find().Ipv6.find()
ip_objs = self.api._ixnetwork.Topology.find().DeviceGroup.find().Ethernet.find().Ipv6.find()
resolved_mac_list = self._get_ether_resolved_mac(
ip_objs, self.ether_v6gateway_map, request.ipv6_neighbors, "ipv6"
)
Expand Down Expand Up @@ -262,8 +282,8 @@ def select_properties(self, xpath, properties=[]):
}
]
}
url = "%s/operations/select?xpath=true" % self._api._ixnetwork.href
results = self._api._ixnetwork._connection._execute(url, payload)
url = "%s/operations/select?xpath=true" % self.api._ixnetwork.href
results = self.api._ixnetwork._connection._execute(url, payload)
try:
return results[0]
except Exception:
Expand All @@ -275,7 +295,7 @@ def imports(self, imports):
json.dumps(imports), False
)
for item in errata:
self._api.warning(item)
self.api.warning(item)
return len(errata) == 0
return True

Expand Down
Loading

0 comments on commit 2800cb4

Please sign in to comment.