Following my objective of increasing home FTTH bandwith by removing ISP set-top-box, I needed to change the VLAN priority of the DHCP packets (priority 6).
In previous articles, I patched the DHCP client of OpenWRT which uses raw sockets to use priority 6.
Now my objective is to use a standard router such as Mikrotik, which do not support the DHCP packet CoS by default.
I decided to use my Macchiatobin running a custom kernel and OpenWRT and configure it as a bridge which modifies the VLAN priority of specific packets.
This was actually easier than expected!
When creating a bridge, it is important to understand that we are operating at layer 2. A typical bridge is not inspecting packets at higher layers (3 and up), and as such not interacting at IP level.
There is however an option to change this behavior, and to force the processing of packets by the kernel at IP layer!
Just try the following command to enable the processing of bridge packets through iptables:
echo "1" > /proc/sys/net/bridge/bridge-nf-call-iptables
This change can be made persistent by altering sysctl configuration file in /etc/sysctl.d/.
Now that the packets are being processed by iptables, the steps are the following:
- Define VLAN interfaces
- Create the bridge and attach interfaces
- Create iptables rule to change the VLAN priority of selected packets
Defining VLAN interfaces
Why defining every VLAN, instead of just bridging interface as a trunk ? If you do that, the kernel will not have any knowledge about packets, and especially that 802.1Q is in use. And as VLAN priority is a feature that comes with 802.1Q – no VLAN = no priority !
Declare VLAN on the interfaces you wish to bridge, and specify the egress map, to indicate that packets with CoS set to 6 will be leaving the interface with a VLAN priority set to 6:
ip link add link eth0 name eth0.832 type vlan id 832 ip link set eth0.832 type vlan egress 6:6 ip link add link eth3 name eth3.832 type vlan id 832 ip link set eth3.832 type vlan egress 6:6
Create the bridge
Now, it is time to create the bridge and add the interfaces to it. Note that we don’t need to define an IP configuration for this interface (br0) as we just want the device to be a “passive” bridge.
brctl addbr br0 brctl addif br0 eth0.832 brctl addif br0 eth3.832
Create iptables rule to change the CoS of selected packets
The only packets we want to alter is DHCP configuration. Those packets typically have a predefined source and destination port, making it easy.
iptables -A FORWARD -p udp --sport 68 --dport 67 -j CLASSIFY --set-class 0:6
Here we are! At this stage, the device is operating as a bridge, bridging vlan 832 and changing the priorty of DHCP packets to 6.
Persisting this configuration with OpenWRT
If you use OpenWRT and want to persist this configuration, here are the changes.
# /etc/config/network config device option type '8021q' option ifname 'eth3' option vid '832' option name 'eth3.832' option ipv6 '0' list egress_qos_mapping '6:6' list egress_qos_mapping '0:0' list egress_qos_mapping '1:0' list egress_qos_mapping '2:0' list egress_qos_mapping '3:0' list egress_qos_mapping '4:0' list egress_qos_mapping '5:0' config device option type '8021q' option ifname 'eth0' option vid '832' option name 'eth0.832' option ipv6 '0' list egress_qos_mapping '6:6' list egress_qos_mapping '0:0' list egress_qos_mapping '1:0' list egress_qos_mapping '2:0' list egress_qos_mapping '3:0' list egress_qos_mapping '4:0' list egress_qos_mapping '5:0' config interface 'br0' option type 'bridge' option ifname 'eth3.832 eth0.832'
# /etc/sysctl.d/11-br-netfilter.conf net.bridge.bridge-nf-call-arptables=0 net.bridge.bridge-nf-call-ip6tables=0 net.bridge.bridge-nf-call-iptables=1
# /etc/firewall.user iptables -A FORWARD -p udp --sport 68 --dport 67 -j CLASSIFY --set-class 0:6