DSCP & TOS
Note: I'm perfectly happy for this table and associated information to be used anywhere by anyone, that's why it's been published here, I couldn't find an easy reference, so I created one and published it for everyone, but, if you do republish the information, please attribute the source and don't try to pass it off as original work. Thanks.
You're trying to get QoS working smoothly on your network and you have a DSCP tag on your packets, but, you can only see ToS when capturing packets? How do you work out which ToS value equates to which DSCP value? Or... You are tagging using DSCP/PHB classes but only seeing DSCP hex or decimal tags on your packets? What does it all mean?
The following table shows common decimal, hex and binary values for TOS, broken down into the meaning of the parts of that byte including DSCP values when interpretting that byte as DSCP.
So, there you have it, one byte in a packet header, two ways to look at it...
If dealing with TOS (Type of Service), the first 3 bits indicate the precedence, the 4th bit indicates the whether or not low delay is preferred, the 5th bit indicates whether or not high throughput is preferred, the 6th bit indicates whether or not high reliability is preferred and the 7th and 8th bits are reserved... More info can be found in RFC 791, written in 1981, which defines IP.
If dealing with DSCP (Differentiated Services (Diffserv) Codepoint) only the first 6 bits are used and the last 2 are ignored, these can be used for ECN (Explicit Congestion Notification) RFC 3168 ... More info can be found in RFC 2474, written in 1998, which defines the Differentiated Services Field (DS Field) which is what the TOS byte is referred to when talking about differentiated services and specifically DSCP. Also, RFC 2597 and RFC 3246 which define some of the PHB (Per-hop Behaviour) classes may be useful reading...
Update 2013-04-21: Added voice-admit as defined in RFC 5865 and listed at the IANA DSCP Registry. Added various TOS flag only options as used in certain software, e.g. openssh and old versions of asterisk.
I want to capture IPv4 packets using tcpdump that have had the DSCP class 'af21' set, but, tcpdump doesn't have a filter for DSCP and doesn't decode values to DSCP classes, what can I do?
$ tcpdump -v -n -i ppp0 'ip and ip & 0xfc == 72'
What this does run tcpdump with verbose output (-v), no name lookups (-n) on the interface ppp0 (-i ppp0), the filter, specified in quotes, says to only include packets that are ip (ip) and (and) where the second byte in the ip header (ip) has a decimal value of 72 which we took from the table above as being the TOS decimal value equivalent to the DSCP class 'af21' (== 72) ignoring the last 2 bits in that byte as they may contain ECN flags (& 0xfc).
17:50:20.207827 IP (tos 0x48, ttl 108, id 12190, offset 0, flags [none], proto UDP (17), length 116)
18.104.22.168.22238 > 22.214.171.124.51420: UDP, length 88
tcpdump shows packets that match our filter, it prefers to use a hex TOS value in it's display, so, showing 'tos 0x48'.
If we instead want to capture IPv6 traffic with the same class set, we'd do:
$ tcpdump -v -n -i he-ipv6 'ip6 and (ip6[0:2] & 0xfc0) >> 4 == 72'
Here, it's a little more complex, with IPv6 the traffic class byte straddles the first and second bytes of the header, so, we look at the first two bytes of the header (ip6[0:2]), ignore the first 4 bits and the last 6 bits (& 0xfc0) then shift the value 4 bits to the right (>> 4) to remove the 4 right hand ignored bits that are outside the traffic class byte from the value and leave us with the value we want.
In both these examples, you can use TOS hex values instead of TOS decimal values, e.g. == 0x48. Alternatively, if you want to use DSCP hex or DSCP decimal values, you can shift the result, for the first example, this would give, as exact equivalents of those above:
$ tcpdump -v -n -i ppp0 'ip and (ip & 0xfc) >> 2 == 0x12'
and for the second example:
$ tcpdump -v -n -i he-ipv6 'ip6 and (ip6[0:2] & 0xfc0) >> 4 == 0x12'
In both cases, using the DSCP hex value of 0x12 which as you can see from the table above is equivalent to the TOS decimal value 72.
Note the quotes around the filter string above, while you don't need quotes when specifying simple filters with tcpdump, without them in this case the shell would likely interpret '&' and '>>' executing a partial command as a background task and trying to execute the rest with output redirected, something that you likely don't want to do...
Ping can be used to generate some outbound packets to test your QoS configuration or tcpdump filters. Ping has a '-Q' option to specify the value you want to set on your packets, for IPv4, this takes either a TOS hex or TOS decimal value, for IPv6, it only takes a TOS hex value.
To generate packets that our tcpdump filters above would capture, for IPv4 these two are equivalent:
$ ping -Q 72 126.96.36.199
$ ping -Q 0x48 188.8.131.52
For IPv6, these two are equivalent:
$ ping6 -Q 48 2404:6800:4003:801::1014
$ ping6 -Q 0x48 2404:6800:4003:801::1014
As mentioned, ping6 only takes a hex value, while 48 in this case may appear to be decimal as we didn't explicitly specify it was hex with '0x', it is interpreted as hex.