2

This is on Ubuntu 20.04.

I am attempting to write a rule for nftables which will match all IP packets received on interface eth1 that have a specific TOS value (0x02). My attempt so far:

sudo nft add table raw
sudo nft -- add chain raw prerouting {type filter hook prerouting priority -300\;}
sudo nft add rule ip raw prerouting iifname eth1 ip dscp 2 counter
sudo nft add rule ip raw prerouting iifname eth1 udp dport 41378 counter

I am sending UDP packets from a seperate computer to the computer running nftables. The code to setup this sending socket, including setting the TOS in those packets:

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    int optval = 2;
    setsockopt(sockfd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); //Set TOS value
  
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(41378);
    servaddr.sin_addr.s_addr = inet_addr("192.168.10.100");

I can see the packets arrive using sudo tcpdump -i eth1 -vv:

14:51:35.153295 IP (tos 0x2,ECT(0), ttl 64, id 7091, offset 0, flags [DF], proto UDP (17), length 50)
    192.168.12.10.49089 > ubuntu.41378: [udp sum ok] UDP, length 22

The raw header of these is as follows:

IP Header
    00 E0 4C 00 05 8B 3C 97 0E C7 E1 00 08 00 45 02         ..L...<.......E.
    00 31 7E 52                                             .1~R

Decoded it shows:

IP Header
   |-IP Version        : 4
   |-IP Header Length  : 5 DWORDS or 20 Bytes
   |-Type Of Service   : 2
   |-IP Total Length   : 49  Bytes(Size of Packet)
   |-Identification    : 32338
   |-TTL      : 64
   |-Protocol : 17
   |-Checksum : 8873
   |-Source IP        : 192.168.12.10
   |-Destination IP   : 192.168.12.100

The problem is that when I run sudo nft list ruleset I see:

table ip raw {
        chain prerouting {
                type filter hook prerouting priority raw; policy accept;
                iifname "eth1" ip dscp 0x02 counter packets 0 bytes 0
                iifname "eth1" udp dport 41378 counter packets 8 bytes 392
        }
}

The rule matching based on udp destination port is working well, but the rule matching on dscp of 0x02 is not.

How can I make a rule to match on a TOS of 0x02?

So far I have tried other values of TOS, in-case 0x02 was special. I tried decimal 8, 16, 24, and 32. Each time I see the incoming packet with the TOS value I am setting, but the nfttables rule never counts, which I believe means it never matched.

Handy nftables guide: https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes

A handy reference for DSCP values to names: https://www.cisco.com/c/en/us/td/docs/switches/datacenter/nexus1000/sw/4_0/qos/configuration/guide/nexus1000v_qos/qos_6dscp_val.pdf

1
  • I am running nftables on Ubuntu 20.04 if that helps. Commented Jul 9, 2021 at 15:41

1 Answer 1

4

Looking further into the make-up of a IPv4 header: https://en.wikipedia.org/wiki/IPv4#Header

I see that TOS is the name given to the entire byte, but DSCP is the name for only the most-significant 6 bits. Based on this I guessed TOS != DSCP. I tried changing the sending code to using a TOS of 0x20 and then modified the nftables rule to look for 0x20 >> 2 == 0x08 (Shifting the TOS right two bits to convert it into a DSCP value):

sudo nft add rule ip raw prerouting iifname eth1 ip dscp 0x8 counter

With this change I now see that counter increasing for that new rule.

table ip raw {
        chain prerouting {
                type filter hook prerouting priority raw; policy accept;
                iifname "eth1" ip dscp cs1 counter packets 12 bytes 590
                iifname "eth1" udp dport 41378 counter packets 12 bytes 590
        }
}

TLDR:

  • TOS is not the same as DSCP.
  • The DSCP is the most-significant 6 bits of the TOS.
  • To match a TOS in nftables using ip dscp, shift the TOS right 2 bits and match on that value.

I'm positive I'm missing some core concepts with this answer, so I encourage anyone who understands this better to provide a more useful answer.

3
  • 1
    The confusion between TOS and DSCP is because of history: the same bits in the IP packet changed role. Before: TOS after: DSCP. If you're configuring your local network etc to use TOS, consider using DSCP instead. Also despite the socket options described in ip(7) about IP_TOS, it appears you can use DSCP with it. Example: tools.ietf.org/id/… Commented Aug 15, 2021 at 20:33
  • 3
    You can even write ip dscp cs1 which means Class Selector 1 in DSCP's language and corresponds to 0x08. Use nft describe ip dscp to see the list. Commented Oct 3, 2021 at 13:58
  • Thanks! I was not aware of that feature. Commented Oct 13, 2021 at 12:50

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.