Skip to content

Commit

Permalink
Add module features to 'netlab show modules' command
Browse files Browse the repository at this point in the history
* Add the 'display module feature' functionality that is enabled
  when 'netlab show module' command is called with -m parameter
* Add 'features' dictionary describing individual configurable features
  to the module definitions
  • Loading branch information
ipspace committed Jul 3, 2023
1 parent 5ea5597 commit ab51343
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 8 deletions.
47 changes: 45 additions & 2 deletions docs/netlab/show.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

## Usage

```
usage: netlab show [-h] [-d DEVICE] [--system] [--format {table,text,yaml}]
```text
usage: netlab show [-h] [-d DEVICE] [-m MODULE] [--system]
[--format {table,text,yaml}]
{images,devices,module-support,modules}
Display default settings
Expand All @@ -23,6 +24,8 @@ options:
-h, --help show this help message and exit
-d DEVICE, --device DEVICE
Display information for a single device
-m MODULE, --module MODULE
Display information for a single module
--system Display system information (without user defaults)
--format {table,text,yaml}
Output format (table, text, yaml)
Expand Down Expand Up @@ -172,3 +175,43 @@ Configuration modules supported by individual devices
| vyos | x | | x | | | | | |
+--------------+-----+------+------+-------+-----+----+------+------+
```

EVPN features supported by individual devices:

```text
$ netlab show modules -m evpn
Devices and features supported by evpn module
+----------+-----+------------------+------------+
| device | irb | asymmetrical_irb | bundle |
+==========+=====+==================+============+
| sros | x | x | |
+----------+-----+------------------+------------+
| srlinux | x | x | |
+----------+-----+------------------+------------+
| frr | x | | |
+----------+-----+------------------+------------+
| eos | x | x | vlan_aware |
+----------+-----+------------------+------------+
| vyos | x | x | |
+----------+-----+------------------+------------+
| dellos10 | x | x | |
+----------+-----+------------------+------------+
| cumulus | x | x | |
+----------+-----+------------------+------------+
| nxos | x | | |
+----------+-----+------------------+------------+
| arubacx | x | x | |
+----------+-----+------------------+------------+
| vptx | | | |
+----------+-----+------------------+------------+
Notes:
* All devices listed in the table support evpn configuration module.
* Some devices might not support any module-specific additional feature
Feature legend:
* irb: Supports symmetrical IRB (routing on ingress and egress)
* asymmetrical_irb: Support asymmetrical IRB (routing on ingress, bridging on egress)
* bundle: EVPN bundle service support
```
99 changes: 93 additions & 6 deletions netsim/cli/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,19 @@ def show_devices(settings: Box, args: argparse.Namespace) -> None:
elif args.format in ['text','yaml']:
print(common.get_yaml_string(result))

def get_modlist(settings: Box, args: argparse.Namespace) -> list:
if args.module:
if settings[args.module].supported_on:
return [ args.module ]
else:
common.fatal(f'Unknown module: {args.module}')
return []

return sorted([ m for m in settings.keys() if 'supported_on' in settings[m]])

def show_module_support(settings: Box, args: argparse.Namespace) -> None:
heading = ['device']
mod_list = sorted([ m for m in settings.keys() if 'supported_on' in settings[m]])
mod_list = get_modlist(settings,args)
heading.extend(mod_list)

rows = []
Expand All @@ -122,7 +132,11 @@ def show_module_support(settings: Box, args: argparse.Namespace) -> None:
rows.append(row)
else:
dev_mods = [ m for m in mod_list if device in settings[m].supported_on ]
result[device] = dev_mods
if args.device and args.format == 'yaml':
for m in mod_list:
result[m] = settings.devices[device].features.get(m,True)
else:
result[device] = dev_mods
if args.format == 'text':
print(f'{device}: {",".join(dev_mods)}')

Expand All @@ -133,25 +147,93 @@ def show_module_support(settings: Box, args: argparse.Namespace) -> None:
elif args.format == 'yaml':
print(common.get_yaml_string(result))

def get_feature_list(features: Box,prefix: str = '') -> list:
f_list = []
for k in features.keys():
if isinstance(features[k],dict):
f_list.extend(get_feature_list(features[k],k+'.'))
else:
f_list.append(prefix+k)

return f_list

def show_module_features(settings: Box, args: argparse.Namespace) -> None:
m = args.module
heading = ['device']
heading.extend(get_feature_list(settings[m].features))

rows = []
need_notes = False

for d in settings[m].supported_on:
if d in DEVICES_TO_SKIP:
continue
row = [ d ]

has_feature = False
for f in heading[1:]:
value = settings.devices[d].features[m].get(f,None)
if value is None:
value = ""
elif isinstance(value,bool):
value = "x" if value else ""
elif isinstance(value,list):
value = ",".join(value)

if value:
has_feature = True

value = value.center(len(f))
row.append(value)
rows.append(row)
if not has_feature:
need_notes = True

print_table(heading,rows)

if need_notes:
print(f"""
Notes:
* All devices listed in the table support {m} configuration module.
* Some devices might not support any module-specific additional feature""")

print("")
print("Feature legend:")
for f in heading[1:]:
print(f"* {f}: {settings[m].features[f]}")

def show_modules(settings: Box, args: argparse.Namespace) -> None:
mod_list = sorted([ m for m in settings.keys() if 'supported_on' in settings[m]])
mod_list = get_modlist(settings,args)
result = data.get_empty_box()

if args.format == 'table':
print("netlab Configuration modules and supported devices")
print("=" * 75)
if args.module:
if settings[args.module].features:
print(f"Devices and features supported by {args.module} module")
else:
print(f"Devices supported by {args.module} module")
print("")
else:
print("netlab Configuration modules and supported devices")
print("=" * 75)

for m in mod_list:
dev_list = [ d for d in settings[m].supported_on if not d in DEVICES_TO_SKIP ]
if args.format == 'text':
print(f'{m}: {",".join(dev_list)}')
elif args.format == 'table' and args.module and settings[args.module].features:
show_module_features(settings,args)
elif args.format == 'table':
print(f'{m}:')
print(textwrap.TextWrapper(
initial_indent=" ",
subsequent_indent=" ").fill(", ".join(dev_list)))
else:
result[m] = settings[m].dev_list
if args.module and settings[args.module].features:
for d in dev_list:
result[d] = settings.devices[d].features[m]
else:
result[m] = settings[m].dev_list

if args.format == 'yaml':
print(common.get_yaml_string(result))
Expand All @@ -177,6 +259,11 @@ def show_parse(args: typing.List[str]) -> argparse.Namespace:
action='store',
default='*',
help='Display information for a single device')
parser.add_argument(
'-m','--module',
dest='module',
action='store',
help='Display information for a single module')
parser.add_argument(
'--system',
dest='system',
Expand Down
7 changes: 7 additions & 0 deletions netsim/modules/bgp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,10 @@ attributes:
interface:
local_as: asn
replace_global_as: bool
features:
local_as: Supports local-as functionality
vrf_local_as: Supports local-as within a VRF
local_as_ibgp: Can use local-as to create IBGP sesssion
activate_af: Can control activation of individual address families
ipv6_lla: Can run EBGP sessions over IPv6 link-local addresses
rfc8950: Can run IPv4 AF over IPv6 LLA EBGP session
4 changes: 4 additions & 0 deletions netsim/modules/evpn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ attributes:
vrf:
transit_vni: { type: int, min_value: 1, max_value: 16777215, _alt_types: [ str, bool ] }
bundle: { type: str, valid_values: [ vlan_aware, vlan, port, port_vlan ]}
features:
irb: Supports symmetrical IRB (routing on ingress and egress)
asymmetrical_irb: Support asymmetrical IRB (routing on ingress, bridging on egress)
bundle: EVPN bundle service support
2 changes: 2 additions & 0 deletions netsim/modules/gateway.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ attributes:
priority: int
preempt: bool
link_to_neighbor: True
features:
protocol: Supported FHRP protocols
5 changes: 5 additions & 0 deletions netsim/modules/isis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ attributes:
_alt_types: [ bool ]
network_type: { type: str, valid_values: [ point-to-point ] }
passive: bool
features:
unnumbered:
ipv4: IPv4 unnumbered interfaces
ipv6: IPv6 unnumbered interfaces
network: multi-access unnumbered links
5 changes: 5 additions & 0 deletions netsim/modules/mpls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ attributes:
6pe:
link:
ldp: bool
features:
ldp: Can run LDP within an autonomous system
bgp: Supports BGP Labeled Unicast address family
vpn: Supports MPLS/VPN
6pe: Supports 6PE
3 changes: 3 additions & 0 deletions netsim/modules/ospf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ attributes:
bfd: bool
passive: bool
network_type: { type: str, valid_values: [ point-to-point,point-to-multipoint,broadcast,non-broadcast ] }
features:
unnumbered: Can run OSPFv2 over unnumbered IPv4 interfaces
strict_bfd: Supports strict BFD mode (RFC 9355)
4 changes: 4 additions & 0 deletions netsim/modules/vlan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ attributes:
extra:
global: [ vlans ]
node: [ vlans ]
features:
model: Conceptual device configuration model
mixed_trunk: Supports trunk interfaces with mixed routed/bridged VLANs
native_routed: Supports native layer-3 interface on a trunk port

0 comments on commit ab51343

Please sign in to comment.