CAKE using veth-pair + Guest WiFi for IoT devices?

@dlakelan or @moeller0 I presently make use of:

image

to allow me to shape mixture of VPN and non-VPN traffic.

But now I would like to try to create a Guest Wifi to isolate our IoT devices.

I am hoping for any help as to how I might work that in to my existing setup?

It becomes rapidly more complex when you have multiple destination networks. One strategy is to create a veth called something like "qosveth" where the other end of the veth is in a different namespace. In that namespace you have a bridge to another veth, whose far end comes back into the main namespace as something like qosreturn... then you route everything from the WAN side to qosveth... and then everything from qosreturn gets routed normally.

It might make sense to try using an IFB... route all stuff from WAN side to an IFB, and then I don't know if it'll seem like that traffic "comes from the IFB" so you can route it again out to the normal routes.

1 Like

Thanks. This seems like a fun challenge and may be helpful for other users in the same boat.

Any chance you could draw me a sketch of the veth-based solution in terms of how the veths are linked up with br-lan and br-guest?

I tried just working with my existing setup, but having veth-br made a part of both br-lan (192.168.1.1) and br-guest (192.168.2.1), but that failed. It seems a veth end can only be a part of one interface and not more than one interface.

Regarding the IFB-based solution, I got pretty far with that during my earlier attempt:

So that grabs all the br-lan wan/VPN but then I wouldn't know how to also grab the br-guest wan/VPN as well. Assuming the goal would be to create IFB that grabs all br-lan wan/VPN combined with all br-guest wan/VPN.

Or can I just stack the br-guest to the common IFB by repeating the lines for the br-guest? Like this:

ip link add name ifb type ifb

tc qdisc add dev ifb root cake bandwidth 30Mbit diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms noatm overhead 60

tc qdisc add dev br-lan handle ffff: ingress

tc qdisc add dev br-guest handle ffff: ingress

ip link set ifb up

tc filter add dev br-lan parent ffff: protocol ip prio 1 u32 match ip dst 192.168.1.0/24 action pass
tc filter add dev br-lan parent ffff: prio 2 matchall action mirred egress redirect dev ifb

tc filter add dev br-guest parent ffff: protocol ip prio 1 u32 match ip dst 192.168.2.0/24 action pass
tc filter add dev br-guest parent ffff: prio 2 matchall action mirred egress redirect dev ifb

Here's a diagram:

Basically you have a special route rule that says all your traffic coming from WAN first gets routed to qos interface, which is one end of a veth... then that goes into a separate namespace where the other end is a member of a bridge... then it's bridged to another veth... which brings it back into the main namespace.

You'll need a kernel with network namespaces enabled, and the ip-full package to handle setting up the namespaces.

then packets received on qosreturn are routed as normal. Make qosreturn part of the WAN firewall zone, since it's got packets coming in from WAN.

Another option is something like this:

Where you shove the real ethernet/vlan device representing your WAN connection into a namespace, and then in that namespace route everything to the veth that brings packets in to your main namespace... then in the main namespace everything works as normal, except the "wan" is a virtual device that's the second end of a veth.

In this scenario, you'd also need to shove your wireguard connection into the "pre" namespace as well I think.

1 Like

@jow / @vgaetera does netifd support multiple namespaces? Can this:

be done in LuCi and if so how? If not in LuCi how can it be done using the command line?

@dlakelan any idea how to implement this? Seems elegant. But I can't see much about namespace use in OpenWrt in this way. So I don't know where or who to turn to. This returned no errors:

root@OpenWrt:~# opkg install ip-full
Installing ip-full (5.15.0-2) to root...
Downloading https://downloads.openwrt.org/snapshots/packages/aarch64_cortex-a53/base/ip-full_5.15.0-2_aarch64_cortex-a53.ipk
Installing libelf1 (0.186-1) to root...
Downloading https://downloads.openwrt.org/snapshots/packages/aarch64_cortex-a53/base/libelf1_0.186-1_aarch64_cortex-a53.ipk
Installing libbpf20220308 (2022-03-08-04c465fd-1) to root...
Downloading https://downloads.openwrt.org/snapshots/packages/aarch64_cortex-a53/base/libbpf20220308_2022-03-08-04c465fd-1_aarch64_cortex-a53.ipk
Configuring libelf1.
Configuring libbpf20220308.
Configuring ip-full.
root@OpenWrt:~# ip netns add blue
root@OpenWrt:~#

Good news that the netns stuff seems to work.

I think what you will have to do is use a script. Create a veth pair, move one end into the netns, put your WAN ethernet into the netns as well. Bridge them together with a bridge in the netns. Add cake to the veth... then you'll have to run your autorate script in the netns as well. it's not ideal, but it should work.

In my diagram, instead of routing between the wan and veth, just bridge them.

1 Like

So could I actually bridge WAN + VPN + veth all together? Or would it really have to be routing in that instance?

Would the IFB solution be in any sense inferior? I ask because I imagine setting it up may be easier for me because I don't altogether understand how the routing would be implemented. I mean I know how to use netifd in LuCi. But I'm a bit hazy beyond that.

The VPN is not an Ethernet layer device so I don't think it can be in the bridge meaningfully.

I'm not sure how well the IFB will work. You don't want the VPN traffic to go twice through, so you'll have to do some magic to send just either the encrypted packet, or the unencrypted packet through not both.

I assume you want to shape traffic in the tunnel with prioritization, so just the unencrypted stuff which you can then prioritize differently and / or flow/fair queue

I tried this for at the br-lan/br-guest end, but this seems to capture upload and not download?

ip link add name ifb type ifb
tc qdisc add dev br-lan handle ffff: ingress
tc qdisc add dev br-guest handle ffff: ingress
tc filter add dev br-lan parent ffff: protocol ip prio 1 u32 match ip dst 192.168.1.0/24 action pass
tc filter add dev br-lan parent ffff: prio 2 matchall action mirred egress redirect dev ifb
tc filter add dev br-guest parent ffff: protocol ip prio 1 u32 match ip dst 192.168.2.0/24 action pass
tc filter add dev br-guest parent ffff: prio 2 matchall action mirred egress redirect dev ifb

Any idea what's wrong?

These are filters on ingress to br-lan and br-guest so that's packets coming from inside your network

Ah. Is it not possible to work with br-lan/br-guest in this way then?

What you want is ingress to WAN that matches non encrypted packets, and ingress to wireguard that matches all packets. Send those all to an IFB. But it won't be classified yet...

How do you mean?

How about this?

tc filter add dev wan parent ffff: protocol ip prio 1 u32 match ip sport 51820 0xffff action pass
tc filter add dev wan parent ffff: prio 2 matchall action mirred egress redirect dev ifb
tc filter add dev vpn parent ffff: matchall action mirred egress redirect dev ifb

The main reason to not just handle everything on an ingress to WAN is that you want to treat some flows differently from others, and to handle fairness etc. If you just want to rate limit you can do ingress on WAN.

Will this recipe give me that?

It will allow the VPN flows to be treated as separate flows, so at least that. But you won't have any DSCP/classification. So for example if you're interested in making guest traffic lower priority than regular LAN traffic, then you'll need some other magic for that.

1 Like

Don't you want this to be dport? You're trying to pass incoming traffic to your VPN port

I see lines like this:

    10.xx.xx.xx.34769 >  178.xx.xx.xx.51820: UDP, length 128
    178.xx.xx.xx.51820 > 10.xx.xx.xx.34769: UDP, length 128

So for download (the second line from WireGuard server to my Wan IP), the source port is 51820 - does this seem right?

potentially any device on the internet could send you packets from that identical port. So I think you're best off to match on something like UDP packets from your VPN provider's IP address coming from that port.

1 Like

Any thoughts on this?

root@OpenWrt:/etc/init.d# cat sqm-wan-vpn
#!/bin/sh /etc/rc.common
# Copyright (C) 2007 OpenWrt.org

exec &> /tmp/sqm.log

START=50
STOP=4

start() {
        # apply CAKE on upload (must be besteffort flows nonat nowash to work with the skb->hash preservation)
        tc qdisc add dev wan root cake bandwidth 30Mbit besteffort flows nonat nowash no-ack-filter split-gso rtt 100ms noatm overhead 92

        # set up ifb that combines vpn and wan flows
        ip link add name ifb type ifb
        tc qdisc add dev wan handle ffff: ingress
        tc qdisc add dev vpn handle ffff: ingress
        ip link set ifb up

        # filter out packets from WireGuard src IP on wan, else preserve, and combine all vpn flows
        tc filter add dev wan parent ffff: protocol ip prio 1 u32 match ip src xx.xx.xx.xx/32 action pass
        tc filter add dev wan parent ffff: prio 2 matchall action mirred egress redirect dev ifb
        tc filter add dev vpn parent ffff: matchall action mirred egress redirect dev ifb

        # apply CAKE on download using the ifb
        tc qdisc add dev ifb root cake bandwidth 25Mbit besteffort triple-isolate nat wash ingress no-ack-filter split-gso rtt 100ms noatm overhead 92
}

stop() {
        tc qdisc del dev wan ingress
        tc qdisc del dev wan root
        tc qdisc del dev vpn ingress
        tc qdisc del dev ifb root
        ip link set ifb down
        ip link del ifb
}

@moeller0 this is what I mean - couldn't the LuCi sqm-script be adapted to allow setting up IFB's for those who have wan/vpn like this? If I just use this script does that mean I don't need all the sqm packages? Think I need: kmod-sched-core + tc-tiny?

Maybe this is a fairly generic solution that could be brought in?