Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions docs/outputs/graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,43 @@ _netlab_ uses the node **graph.rank** attribute to:

The default value of the **graph.rank** attribute is 100, allowing you to push some nodes (with rank below 100) toward the top of the graph and others (with rank above 100) toward the bottom.

You can also use the **graph.rank** on links to influence how Graphviz draws multi-access links.
You can also use the **graph.rank** on links to influence how Graphviz positions multi-access links relative to other links and nodes.

Finally, the link/interface **graph.linkorder** attribute allows you to specify the node order in individual links. The default **graph.linkorder** value is 50 for interfaces and 100 for subnets (multi-access links), resulting in subnets being "below" nodes unless you change the link- or interface **graph.linkorder** value.
Finally, the **graph.linkorder** attribute allows you to specify the node order in individual links. The default **graph.linkorder** value is 50 for interfaces and 100 for subnets (multi-access links). **graph.rank** is used to sort objects with the same **graph.linkorder**.

The default value of **graph.linkorder** places subnets (multi-access links) below all nodes attached to them. For example, the following lab topology results in a graph with the subnet below sw, h1, and h2:

```
nodes: [ sw, h1, h2 ]
links:
- interfaces: [ sw, h1, h2 ]
```

You can change the **graph.linkorder** on the host interfaces (h1, h2) to put the host nodes below the subnet:

```
nodes: [ sw, h1, h2 ]
links:
- sw:
h1:
graph.linkorder: 200
h2:
graph.linkorder: 200
```

You can also change the node **graph.linkorder** attribute to put nodes below subnets *on all links they're connected to*. For example, you could use a `hosts` group to set the **graph.linkorder** for all hosts to a value higher than the default link value (100):

```
groups:
hosts:
members: [ h1, h2 ]
graph.linkorder: 200

nodes: [ r1, h1, h2 ]

links:
- interfaces: [ r1, h1, h2 ]
```

(outputs-graph-appearance)=
## Modifying Graph Appearance
Expand Down
30 changes: 21 additions & 9 deletions netsim/outputs/_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,20 @@ def get_graph_attributes(obj: Box, g_type: str, exclude: list = []) -> Box:
"""
Get a graph attribute from shared or graph-specific dictionary
"""
def get_attr(obj: Box, g_type: str, attr: str, default: typing.Any) -> typing.Any:
return obj.get(f'{g_type}.{attr}',obj.get(f'graph.{attr}',default))
def get_attr(obj: Box, topology: Box, g_type: str, attr: str, default: typing.Any) -> typing.Any:
kw_list = [ f'{g_type}.{attr}', f'graph.{attr}' ] # Try graph-specific (graph/d2) and shared graph attributes
for kw in kw_list: # Try to find the value in interface/link object
if kw in obj:
return obj[kw]

if 'node' in obj: # Try to get node data from object.node (if present)
ndata = topology.nodes.get(obj.node,None)
if ndata: # If we found node data, try to get the keyword value from it
for kw in kw_list:
if kw in ndata:
return ndata[kw]

return default # Nothing works, return the default value

"""
Propagate link graph attributes to interfaces
Expand Down Expand Up @@ -182,22 +194,22 @@ def append_segment(graph: Box,link: Box, g_type: str, topology: Box) -> None:

for intf in link.interfaces:
e_data = [ intf, link ]
e_data.sort(key = lambda x: x.get('graph.rank',topology.nodes[intf.node].get('graph.rank',100)))
e_data.sort(key = lambda x: get_attr(x,g_type,'linkorder',50))
e_data.sort(key = lambda x: get_attr(x,topology,g_type,'rank',100))
e_data.sort(key = lambda x: get_attr(x,topology,g_type,'linkorder',50))
append_edge(graph,e_data[0],e_data[1],g_type)

def topo_edges(graph: Box, topology: Box, settings: Box,g_type: str) -> None:
graph.edges = []
for link in sorted(topology.links,key=lambda x: get_attr(x,g_type,'linkorder',100)):
propagate_link_attributes(link,g_type,['linkorder','type'])
for link in sorted(topology.links,key=lambda x: get_attr(x,topology,g_type,'linkorder',100)):
propagate_link_attributes(link,g_type,['linkorder','rank','type'])

if settings.get('topology.vlan',False):
for intf in link.interfaces:
set_vlan_type(intf)

if len(link.interfaces) == 2 and link.get('graph.type','') != 'lan':
intf_list = sorted(link.interfaces,key=lambda intf: topology.nodes[intf.node].get('graph.rank',100))
intf_list.sort(key = lambda x: get_attr(x,g_type,'linkorder',50))
intf_list.sort(key = lambda x: get_attr(x,topology,g_type,'linkorder',50))
append_edge(graph,intf_list[0],intf_list[1],g_type)
else:
append_segment(graph,link,g_type,topology)
Expand Down Expand Up @@ -300,8 +312,8 @@ def get_node_interface(topology: Box, intf: Box) -> Box:

def isis_edges(topology: Box, graph: Box, g_type: str) -> None:
graph.edges = []
for link in sorted(topology.links,key=lambda x: get_attr(x,g_type,'linkorder',100)):
propagate_link_attributes(link,g_type,['linkorder','type'])
for link in sorted(topology.links,key=lambda x: get_attr(x,topology,g_type,'linkorder',100)):
propagate_link_attributes(link,g_type,['linkorder','rank','type'])

isis_nodes = [ intf.node
for intf in link.interfaces
Expand Down
1 change: 1 addition & 0 deletions netsim/outputs/graph.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ attributes:
fill: str
width: { type: int, min_value: 1, max_value: 32 }
rank: { type: int, min_value: 1, max_value: 200 }
linkorder: { type: int, min_value: 1, max_value: 200 }
format: dict
class: { type: list, _subtype: str}
link:
Expand Down
9 changes: 4 additions & 5 deletions tests/platform-integration/graph/01-topo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ groups:
host:
members: [ h1, h2, h3, h4 ]
device: linux
edge_host:
members: [ h1, h2 ]
graph.linkorder: 200
spine:
members: [ s-1, s-b-2 ]
graph.rank: 1
Expand All @@ -42,11 +45,7 @@ links:
l2:
graph.format.style: dashed
d2.format.style.stroke-dash: 5
- l1:
h1:
graph.linkorder: 200
h2:
graph.linkorder: 200
- interfaces: [ l1, h1, h2 ]
graph.color: "#FF0000"
graph.width: 3
d2.format.shape: oval
Expand Down
Loading