Search code examples
tcpgraphviz

How to use graphviz draw a TCP/IP data encapsulation diagram?


I am trying to use Graphviz to draw a TCP/IP data encapsulation diagram in Stevens' classical TCP/IP book.

diagram

The diagram seems not a standard computer graph. My questions are:

  1. how to align to right?
  2. how to mark the size below each record(i.e. 14 in IP header, 20 in TCP)?
  3. how to draw a edge like |<----------- 46 to 1500 bytes ---------->| and put it below some node?

Can graphviz draw it? If so, how? Thanks in advance.


Solution

    1. For alignment, I used straight edges (splines=false) and an indication of which corner of the node they come from and which corner of the other node they enter (compass points).
    2. To create labels under the words, I used a HTML-label with a two-row table, in the second row I made the bottom borders and the borders on the left and right sides invisible by setting the attribute sides="T" (T meaning top border).
    3. For drawing edge like |<----------- 46 to 1500 bytes ---------->|, I used node's width reduction (width=.01) and invisible nodes and edges, you can find them in the script below by attribute style=invis. Here is a small example with red tinted elements that are invisible in the final image:
      highlighted invisible nodes made with graphviz dot

    Graphviz can draw it (see below for a example), but as answered in the comments above, it will be faster to use graphics editor.

    Script:

    digraph TCP_IP_diagram {
        label=<<FONT><B>Figure 1.7 </B> Encapsulation of data as it goes down the protocol stack.</FONT>>
        nodesep=0
        ranksep=.1
        splines=false
        
        edge[style=dashed]
        node[shape=box height=.6]
        
        // NODES ------------------------------------
        
        table_0 [margin=0 shape=none label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
        <TR><TD PORT="f0" HEIGHT="40" FIXEDSIZE="TRUE">user data</TD></TR>
        </TABLE>>]
        
        inv_0 [shape=point style=invis]
        
        table_1 [margin=0 shape=none label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
        <TR>
            <TD PORT="f0">Appl<BR/>header</TD>
            <TD PORT="f1">user data</TD>
        </TR>
        </TABLE>>]
        
        inv_00 [shape=point style=invis]
        
        table_2 [margin=0 shape=none label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
        <TR>
            <TD PORT="f0">TCP<BR/>header</TD>
            <TD PORT="f1"> application data</TD>
        </TR>
        </TABLE>>]
        
        {
            rank=same;
            "TCP segment" [shape=plaintext]
            inv_1 [shape=point height=.01]
            inv_2 [shape=point height=.01]
        }
        
        table_3 [margin=0 shape=none label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
        <TR>
            <TD PORT="f0">IP<BR/>header</TD>
            <TD>TCP<BR/>header</TD>
            <TD PORT="f1"> application data</TD>
        </TR>
        </TABLE>>]
        
        {
            rank=same;
            "IP datagram" [shape=plaintext]
            inv_3 [shape=point height=.01]
            inv_4 [shape=point height=.01]
        }
        
        table_4 [margin=0 shape=none label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
        <TR>
            <TD PORT="f0">Ethernet<BR/>header</TD>
            <TD>IP<BR/>header</TD>
            <TD>TCP<BR/>header</TD>
            <TD> application data</TD>
            <TD PORT="f1">Ethernet<BR/>trailer</TD>
        </TR>
        <TR>
            <TD SIDES="T">14</TD>
            <TD SIDES="T">20</TD>
            <TD SIDES="T">20</TD>
            <TD SIDES="T"></TD>
            <TD SIDES="T">4</TD>
        </TR>
        </TABLE>>]
        
        {
            rank=same;
            "Ethernet frame" [shape=plaintext]
            inv_5 [shape=box height=.4 width=.01 label=""]
            inv_6 [shape=box height=.4 width=.01 label=""]
        }
        
        {
            rank=same;
            "46 to 1500 bytes" [shape=plaintext]
            inv_7 [shape=box height=.4 width=.01 label=""]
            inv_8 [shape=box height=.4 width=.01 label=""]
        }
        
        table_5 [margin=0 shape=none label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
        <TR><TD BORDER="4" PORT="f0" SIDES="T">Ethernet</TD></TR>
        </TABLE>>]
        
        morespace [style=invis shape=plain]
        
        // EDGES ------------------------------------
        
        table_0:f0:se -> table_1:f1:ne
        table_0:f0:sw -> table_1:f1:nw
        table_0 -> inv_0 [style=invis]
        inv_0 -> table_1 [style=invis]
        
        table_1:f0:sw -> table_2:f0:ne
        table_1:f1:se -> table_2:f1:ne
        
        table_1 -> inv_00 [style=invis]
        inv_00 -> table_2 [style=invis]
        
        table_2 -> "TCP segment" [style=invis]
        table_2:f0:sw -> inv_1 [arrowhead=none]
        table_2:f1:se -> inv_2 [arrowhead=none]
        
        inv_1 -> table_3:f0:ne
        inv_2 -> table_3:f1:ne
        
        "TCP segment" -> inv_1 [weight=0 style=solid]
        "TCP segment" -> inv_2 [weight=0 style=solid]
        
        table_3 -> "IP datagram" [style=invis]
        table_3:f0:sw -> inv_3 [arrowhead=none]
        table_3:f1:se -> inv_4 [arrowhead=none]
        
        "IP datagram" -> inv_3 [weight=0 style=solid]
        "IP datagram" -> inv_4 [weight=0 style=solid]
        
        inv_3 -> table_4:f0:ne [style=dashed]
        inv_4 -> table_4:f1:nw
        
        table_4 -> "Ethernet frame" [style=invis]
        table_4:f0:sw -> inv_5 [style=invis]
        table_4:f1:se -> inv_6 [style=invis]
        "Ethernet frame" -> inv_5 [weight=0 style=solid]
        "Ethernet frame" -> inv_6 [weight=0 style=solid]
    
        "Ethernet frame" -> "46 to 1500 bytes" [style=invis]
        table_4:f0:se -> inv_7 [style=invis]
        table_4:f1:sw -> inv_8 [style=invis]
        "46 to 1500 bytes" -> inv_7 [weight=0 style=solid]
        "46 to 1500 bytes" -> inv_8 [weight=0 style=solid]
        
        "46 to 1500 bytes" -> morespace [style=invis]
        
        {
            edge [minlen=2]
            "application" -> "TCP" -> "IP" -> "Ethernet\ndriver"
        }
        "Ethernet\ndriver" -> table_5:f0 [style=solid arrowhead=none]
        
        // OTHER RANKS ------------------------------------
        
        {rank=same;"application";inv_0}
        {rank=same;table_4;table_5}
    }
    

    Result:
    TCP IP data encapsulation diagram made with graphviz dot