How to clear ISP traffic with OpenWrt?

no this is from my isp to my network

tcpdump will also capture ingress WAN traffic before any tc filters take effect, like ctinfo. If the return traffic seen on br-lan looks correct, you’re probably in good shape.

1 Like

Flowlabels are irrelevant, cake does not use those to select a packets priority tier.

TOS 0x40: CS2 -> cake's Video tin
TOS 0x80: CS4 -> cake's Voice tin

So I can see your lack a happiness. BUT why is dscpclassify not marking these? Are these terminated by the router itself and/or are the connections initiated from the outside?

Good question, I would probably take inspiration from @lynx at:

and try something along the lines of

tc filter add dev "${ul_if}" parent 1: protocol ip matchall action pedit ex munge ip dsfield set 0 retain 0xfc
tc filter add dev "${ul_if}" parent 1: protocol ip6 matchall action pedit ex munge ip6 traffic_class set 0 retain 0xfc

EDIT: Thanks @dave14305, as I said this was not tested (and apparently not even sanity checked :wink: )

Note, I only looked at man tc-pedit and composed this in this editor, so this is neither tested nor guaranteed to not explode.... but it should give you an idea how to proceed....

1 Like

@N1K I see that @dave14305 has already pointed out above that you cannot use nftables because even the ingress hook of nftables is AFTER the tc ingress hook.

I think like @moeller0 indicates, cake-qos-simple seems highly relevant in terms of offering a template.

cake-qos-simple uses a combination of nftables and tc and allows you to set DSCPs at the router and/or in client devices for upload packets (using nftables), stores them to conntrack on upload (using nftables), and then restores those values from conntrack on download (using tc), which would overwrite your ISP-set values. One caveat is that I've only bothered with IPv4 for now, but it would just be a few extra lines for IPv6 (I can't test as I don't have IPv6 access).

If you were to be motivated, I'd be helpful to have the code generalised from IPv4 to IPv6. Setting DSCPs for some of your traffic may be worthwhile anyway. See here for how it is done for the upload packets in nftables in cake-qos-simple.

Regardless, you could apply the same principles based on cake-qos-simple like using the filters (which apply before CAKE) in the format @moeller0 identified - see these lines of cake-qos-simple:

In the example above I overwrite ECN bits, but the same format could be used for anything else.

Another option would be to redirect flows to individual download and upload ifbs like in cake-dual-ifb:

and then apply cake on those.

@dlakelan has a nice recipe involving establishing a fake wan in a different namespace that is upstream of the real wan, and thus the washing could occur on that fake wan, but I lack the knowledge and/or time to figure that one out. I got as far as messing about with different namespaces, but things got a bit messy quickly. So I've personally stuck with 'cake-qos-simple' myself.

Also another option for some people is to intersperse a smart switch that offers DSCP remarking between your ISP modem and your router. Possibly using a VLAN specific to your WAN. I've got a business class TP-Link doing that duty, I think I'm remarking everything from my ISP to cs3 because of the way I've set up my qos scheme but you could remark to cs0 just as easily. I don't know what the cheap option would be for this though.

Zyxel gs1900-16 is about $70 at the moment, it makes for an ok core switch for a home or small business and will remark DSCP. So basically you put your modem on port 16 on a VLAN, put your routers wan on port 1, and remark all DSCP incoming on port 16 to cs0. I'm pretty sure it will do this. Check the user manual to confirm.

You can then send the LAN back to port 2 and have ports 3-15 for LAN usage.


It´s from the isp to my router.

Yes, I know, my question is why were these packets send to your router? Are these responses to e.g. a html request of your one of your internal machines or responses to the router's DNS queries, or are these unsolicited packets sent to e.g. start new connection to some server service you might be running.

so its basically doing the same as dscpclassify but in another way?

I mark my important packets through the windows local group policy editor because the ports often change. Will the marks be transfered to the ingress as easy as in dscpclassify ? The script looks to me a little bit more complicated to set up but with you help im optimistic we can get it to run.

Yes it mostly occurs after or while i open youtube for example. Port 443

Thanks for this information but i think it would be my last resort if i can´t get it running other ways because its one more device in the chain that in the first place would cost money and secondly could possibly make problems.

Indeed; I do the same for the same reason. See here:

Presumably. I haven't studied dscpclassify in detail. It looks very sophisticated.

In general with projects like these I strive for simplicity and elegance - e.g. compare adblock-lean to the rather more fussy alternatives.

You have LAN clients (or nftables) set DSCPs on upload, and store the DSCPs to conntrack (nftables) and the simple service script uses tc to restore DSCPs from conntrack on download thereby ensuring DSCPs are set correctly for ingress based on those set on egress on a per-connection basis, optionally override ECN bits, and apply cake with the set options.


Only a few extra lines will be needed for IPv6. I would have implemented these already if I used IPv6 myself. If you have some familiarity with scripts like these it'd be worth trying to expand it to IPv6 since in the process you'd learn a lot and be able to tweak things exactly to your own needs.

Actually I just checked and it's pretty much already IPv6 compliant. Only the washing ECN bits is IPv4.

@moeller0 or @dave14305 what would these lines need to be for IPv6:

I think something like:

tc filter add dev "${ul_if}" parent 1: protocol ip6 matchall action pedit ex munge ip6 traffic_class set 0 retain 0xfc

EDIT: Thanks @dave14305, as I said this was not tested (and apparently not even sanity checked :wink: )

should work (but I have not tested that)... however not sure if multiple filter can be added to the same parent, but then why not?


Yeah or I think can also pipe actions together from matchall too so presumably your IPv6 action could be piped to the IPv4 action from the same matchall?

All the ingredients are here for @N1K. They've been laid out in front of him with guidelines. But this is pretty fiddly and not exactly plug and play. Surely this is the OpenWrt way though - the flexibility to do whatever you want is there if you need it, as is the very knowledgeable and incredibly geeky army of nerds.

@moeller0 are the decimal ECN values the same for IPv6?

1 Like

IPv6's 8bit traffic_class field has beed dissected into a 6 bit DS field and a 2 bit ECN field like IPv4's 8bit type of service field. The ECN values are identical, what differs is the alignment of the traffic_class field in the IPv4 header versus the alignment of the Type of service field in the IPv4 header; however I think tc takes care of that for you when you use either 'ip6 traffic_class' or 'ip dsfield'.


That's a relief, thanks.

Here are my tcpdump invocations to check ECN bits:

# ECN: IPv4
tcpdump -i pppoe-wan -v -n 'ip and (ip[1] & 0x3) != 0' # NOT Not-ECT
tcpdump -i pppoe-wan -v -n 'ip and (ip[1] & 0x3) == 0' # Not-ECT
tcpdump -i pppoe-wan -v -n 'ip and (ip[1] & 0x3) == 1' # ECT(1)
tcpdump -i pppoe-wan -v -n 'ip and (ip[1] & 0x3) == 2' # ECT(0)
tcpdump -i pppoe-wan -v -n 'ip and (ip[1] & 0x3) == 3' # CE

# ECN: IPv6
tcpdump -i pppoe-wan -v -n 'ip6 and (ip6[0:2] & 0x30) >> 4  != 0' # NOT Not-ECT
tcpdump -i pppoe-wan -v -n 'ip6 and (ip6[0:2] & 0x30) >> 4  == 0' # Not-ECT
tcpdump -i pppoe-wan -v -n 'ip6 and (ip6[0:2] & 0x30) >> 4  == 1' # ECT(1)
tcpdump -i pppoe-wan -v -n 'ip6 and (ip6[0:2] & 0x30) >> 4  == 2' # ECT(0)
tcpdump -i pppoe-wan -v -n 'ip6 and (ip6[0:2] & 0x30) >> 4  == 3' # CE

# ECN IPv4/6
tcpdump -i pppoe-wan -v -n '(ip6 and (ip6[0:2] & 0x30) >> 4  != 0)' or '(ip and (ip[1] & 0x3) != 0)' # NOT Not-ECT
tcpdump -i pppoe-wan -v -n '(ip6 and (ip6[0:2] & 0x30) >> 4  == 1)' or '(ip and (ip[1] & 0x3) == 1)' # ECT(1)
tcpdump -i pppoe-wan -v -n '(ip6 and (ip6[0:2] & 0x30) >> 4  == 2)' or '(ip and (ip[1] & 0x3) == 2)' # ECT(0)
tcpdump -i pppoe-wan -v -n '(ip6 and (ip6[0:2] & 0x30) >> 4  == 3)' or '(ip and (ip[1] & 0x3) == 3)' # CE

note how the values for the 4 code points are identical between IPv4 and IPv6 (and for what it is worth, wireshark agrees :wink: )

1 Like

protocol ipv6 instead of protocol ip.

1 Like

Agreed. In my case I have a wired only router with no builtin switch so I need the switch anyway to branch off to various places (my desk, my kids desks, front room, wireless access points etc). So I basically get the DSCP retagging free.

And retain 0x3 instead of retain 0xfc :smiley:.

For the benefit of anyone reading this thread - should be:

tc filter add dev "${ul_if}" parent 1: protocol ipv6 matchall action pedit ex munge ip6 traffic_class set 0 retain 0x3
1 Like

No here the goal is wiping the DSCP while leaving the ECN bits alone, so in this thread retain 0xfc seems correct, for your cleaing of ECN bits retain 0x3 seems best :wink:

1 Like