(outputs-d2)= # Declarative Diagramming (D2) Output Module *d2* output module create a description of network topology in [D2 diagram scripting language](https://d2lang.com/tour/intro). You can use that description with [D2 commands](https://d2lang.com/tour/install) to create topology diagrams. The *d2* output module is invoked by specifying the `-o d2` parameter in the **[netlab create](netlab-create)** command or by specifying the **d2** engine in the **[netlab graph](netlab-graph)** command. It takes an optional destination file name (default: `graph.d2`). A single formatting modifier can be used to specify the graph type: * **topology** (default) -- Includes point-to-point links, multi-access bridges, and stub subnets. When the network topology contains BGP information, the graph groups nodes into autonomous systems. Alternatively, you could set **defaults.outputs.graph.groups** attribute to use topology **[groups](topo-groups)** to group graph nodes. * **bgp** -- Include autonomous systems, nodes, and BGP sessions. With the **rr** option (specified with `netlab create -o graph:bgp:rr`), RR-client sessions are drawn as directed arrows. ```{tip} The network topology graph description contains nodes and links, but no placement information. D2 is pretty good at figuring out how to draw the required graph, but it pays off to test out the [layout engines](https://d2lang.com/tour/layouts). Changing the [order of links](outputs-d2-style-attributes) might also unclutter the diagrams. ``` ## Modifying Graph Attributes Graphing routines use **[default](topo-defaults)** topology settings to modify the node- or link parameters of the generated D2 file: * **outputs.d2.interface_labels** (default: False) -- Add IP addresses to links in **topology** graph. Results in a cluttered image. * **outputs.d2.groups** (default: None) -- use the specified list of groups (or all groups when set to *True*) to create graph clusters * **outputs.d2.node_address_label** (default: True) -- add node loopback IP addresses or IP addresses of the first interface (for hosts) to node labels. * **outputs.d2.node_interfaces** (default: False) -- add list of interfaces and their IP addresses to nodes[^DG]. * **outputs.d2.as_clusters** (default: True) -- use BGP autonomous systems to cluster nodes in the topology graph. BGP AS clusters are always used in BGP graphs. * **outputs.d2.rr_sessions** (default: True) -- draw IBGP sessions between BGP route reflectors and clients as directional connections. [^DG]: The results look disgusting. If you find a better way to get it done, please submit a PR. Thank you! (outputs-d2-style-attributes)= ## Modifying Link and Node Attributes You can use the **d2** link and node attributes to change the style of individual nodes or links. The following attributes are built into _netlab_ (but see also [](outputs-d2-styles)): * **d2.color** -- line color (*stroke* in D2 lingo) * **d2.width** -- line width (*stroke-width*) in D2 lingo) You can also use the **d2.linkorder** link attribute to change the order of links in the D2 graph description file, which can sometimes improve the diagrams' appearance. Links with lower **d2.linkorder** value (default: 100) appear earlier in the list of links. ## Modifying Shape and Connection Attributes *d2* output module uses `graphite.icon` device attribute to select the node style defined in **defaults.outputs.d2** settings. You can also style `lan` shapes, `container` objects (groups or autonomous systems), and `ibgp` or `ebgp` sessions. You can use any D2 style attribute in these default settings. The following printout lists the system defaults within **defaults.output.d2** dictionary: ``` router: shape: oval switch: shape: hexagon lan: shape: rectangle style.border-radius: 8 ibgp: style: stroke: '#613913' stroke-width: 4 source-arrowhead: shape: arrow target-arrowhead: shape: arrow ebgp: style: stroke: '#b21a1a' stroke-width: 4 source-arrowhead: shape: arrow target-arrowhead: shape: arrow ``` ## Specifying D2 Attributes You could specify D2 attributes in your [topology file](defaults-topology) (where you would have to prefix them with **defaults**), in [per-user topology defaults](defaults-user-file), or with [environment variables](defaults-env) (even [more details](../defaults.md)). You could also specify them with the `-s` parameter of the **[netlab create](netlab-create)** command, yet again prefixed with **defaults** ([more details](netlab-create-set)). Use the **netlab show defaults outputs.d2** [command](netlab-show-defaults) to show the current D2 defaults, including topology file defaults and user defaults, for example: ``` % netlab show defaults outputs.d2 netlab default settings within the outputs.d2 subtree ===================================================== as_clusters: true ebgp: source-arrowhead: shape: arrow style: stroke: '#b21a1a' stroke-width: 4 target-arrowhead: shape: arrow ibgp: source-arrowhead: shape: arrow style: stroke: '#613913' stroke-width: 4 target-arrowhead: shape: arrow interface_labels: false lan: shape: rectangle style: border-radius: 8 font-size: 20 node_address_label: true router: shape: oval style: font-size: 20 rr_sessions: true switch: shape: hexagon style: font-size: 20 ``` (outputs-d2-styles)= ## Extending D2 Style Attributes You can define your own link/node style attributes: * Define the attribute within **defaults.outputs.d2.attributes** dictionary. For example, you might define **d2.background** node attribute (a string) to add background color to nodes[^AD]: ``` defaults.outputs.d2.attributes.node.background: str ``` * Define a mapping between your attribute and D2 style attribute within the **defaults.outputs.d2.styles** dictionary. For example, your **d2.background** attribute maps into D2 **style.fill** attribute: ``` defaults.outputs.d2.styles.background: fill ``` [^AD]: See [](dev-attribute-validation) and [](dev-valid-data-types) for more details.