26.4 Trace File Format

The []Trace::format method defines the trace file format used in trace files produced by the Trace class. It is constructed to maintain backward compatibility with output files in earlier versions of the simulator (, ns v1) so that ns v1 post-processing scripts continue to operate. The important pieces of its implementation are as follows:

        // this function should retain some backward-compatibility, so that
        // scripts don't break.
        void Trace::format(int tt, int s, int d, Packet* p)
        {
                hdr_cmn *th = (hdr_cmn*)p-\>access(off_cmn_);
                hdr_ip *iph = (hdr_ip*)p-\>access(off_ip_);
                hdr_tcp *tcph = (hdr_tcp*)p-\>access(off_tcp_);
                hdr_rtp *rh = (hdr_rtp*)p-\>access(off_rtp_);
                packet_t t = th-\>ptype();
                const char* name = packet_info.name(t);

                if (name == 0)
                        abort();

                int seqno;
                /* XXX */
                /* CBR's now have seqno's too */
                if (t == PT_RTP || t == PT_CBR)
                        seqno = rh-\>seqno();
                else if (t == PT_TCP || t == PT_ACK)
                        seqno = tcph-\>seqno();
                else
                        seqno = -1;

                \ldots

                if (!show_tcphdr_) {
                        sprintf(wrk_, "%c %g %d %d %s %d %s %d %d.%d %d.%d %d %d",
                                tt,
                                Scheduler::instance().clock(),
                                s,
                                d,
                                name,
                                th-\>size(),
                                flags,
                                iph-\>flowid() /* was p-\>class_ */,
                                iph-\>src() \>\> 8, iph-\>src() & 0xff,     // XXX
                                iph-\>dst() \>\> 8, iph-\>dst() & 0xff,     // XXX
                                seqno,
                                th-\>uid() /* was p-\>uid_ */);
                } else {
                        sprintf(wrk_,
                        "%c %g %d %d %s %d %s %d %d.%d %d.%d %d %d %d 0x%x %d",
                                tt,
                                Scheduler::instance().clock(),
                                s,
                                d,
                                name,
                                th-\>size(),
                                flags,
                                iph-\>flowid() /* was p-\>class_ */,
                                iph-\>src() \>\> 8, iph-\>src() & 0xff,     // XXX
                                iph-\>dst() \>\> 8, iph-\>dst() & 0xff,     // XXX
                                seqno,
                                th-\>uid(), /* was p-\>uid_ */
                                tcph-\>ackno(),
                                tcph-\>flags(),
                                tcph-\>hlen());
                }
This function is somewhat unelegant, primarily due to the desire to maintain backward compatibility. It formats the source, destination, and type fields defined in the trace object (not in the packet headers), the current time, along with various packet header fields including, type of packet (as a name), size, flags (symbolically), flow identifier, source and destination packet header fields, sequence number (if present), and unique identifier. The show_tcphdr_ variable indicates whether the trace output should append tcp header information (ack number, flags, header length) at the end of each output line. This is especially useful for simulations using FullTCP agents (Section 35.3). An example of a trace file (without the tcp header fields) might appear as follows:
+ 1.84375 0 2 cbr 210 ------- 0 0.0 3.1 225 610
- 1.84375 0 2 cbr 210 ------- 0 0.0 3.1 225 610
r 1.84471 2 1 cbr 210 ------- 1 3.0 1.0 195 600
r 1.84566 2 0 ack 40 ------- 2 3.2 0.1 82 602
+ 1.84566 0 2 tcp 1000 ------- 2 0.1 3.2 102 611
- 1.84566 0 2 tcp 1000 ------- 2 0.1 3.2 102 611
r 1.84609 0 2 cbr 210 ------- 0 0.0 3.1 225 610
+ 1.84609 2 3 cbr 210 ------- 0 0.0 3.1 225 610
d 1.84609 2 3 cbr 210 ------- 0 0.0 3.1 225 610
- 1.8461 2 3 cbr 210 ------- 0 0.0 3.1 192 511
r 1.84612 3 2 cbr 210 ------- 1 3.0 1.0 196 603
+ 1.84612 2 1 cbr 210 ------- 1 3.0 1.0 196 603
- 1.84612 2 1 cbr 210 ------- 1 3.0 1.0 196 603
+ 1.84625 3 2 cbr 210 ------- 1 3.0 1.0 199 612
Here we see 14 trace entries, five enque operations (indicated by ``+'' in the first column), four deque operations (indicated by ``-''), four receive events (indicated by ``r''), and one drop event. (this had better be a trace fragment, or some packets would have just vanished!). The simulated time (in seconds) at which each event occurred is listed in the second column. The next two fields indicate between which two nodes tracing is happening. The next field is a descriptive name for the the type of packet seen (Section 26.5). The next field is the packet's size, as encoded in its IP header.

The next field contains the flags, which not used in this example. The flags are defined in the flags[] array in trace.cc. Four of the flags are used for ECN: ``E'' for Congestion Experienced (CE) and ``N'' for ECN-Capable-Transport (ECT) indications in the IP header, and ``C'' for ECN-Echo and ``A'' for Congestion Window Reduced (CWR) in the TCP header. For the other flags, ``P'' is for priority, and ``F'' is for TCP Fast Start.

The next field gives the IP flow identifier field as defined for IP version 6.26.1. The subsequent two fields indicate the packet's source and destination node addresses, respectively. The following field indicates the sequence number.26.2The last field is a unique packet identifier. Each new packet created in the simulation is assigned a new, unique identifier.

Tom Henderson 2011-11-05