1

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

3

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/…
    – A.B
    Commented Aug 15, 2021 at 20:33
  • 2
    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.
    – Totor
    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.

Not the answer you're looking for? Browse other questions tagged .