Discussion:
[OpenWrt-Devel] Understanding/reimplementing forwarding acceleration used by Broadcom (ctf)
Rafał Miłecki
2013-08-24 15:19:53 UTC
Permalink
Recently I've finally discovered what makes packets forwarding much
faster when using Broadcom's firmware for their routers. It seems
pretty obvious for some DD-WRT guys, but I guess noone of us knew
about it.

It's the magic ctf.ko module that does the trick. It's a closed source
kernel module, that interferences with kernel using simple symbol
exported in setup.c:
ctf_attach_t ctf_attach_fn = NULL;
EXPORT_SYMBOL(ctf_attach_fn);

CTF probably stands for Cut-Through Forwarding.

Removing this module (rmmod ctf) resulted in performance drop on my
WNDR4500 from 505 Mbits/sec to 379 Mbits/sec for LAN to WAN
iperf-tested traffic. My friend tested this on his BCM4706-based
router and removing ctf.ko module resulted in 850Mb/s to 120Mb/s drop.

When ctf.ko gets loaded, it probably just replaces NULL with it's
struct allowing kernel to use it's mysterious API. If you wonder what
part of Linux kernel was modified to make use of ctf.ko, see attached
diff, that's what Broadcom modified in the net tree.

I don't have so good understanding of the net layer, so your help on
that would be more than appreciated.

AFAIK this magic kernel module allows some packets forwarding to be
done directly, with skipping packets analyze in the OS. It means some
features can't be used with it (like QoS), but it still looks like a
nice solution for basic routing.
It looks for me that ctf uses two connections types:
1) brc which may stand for Bridge Connection
2) ipc which may stand for IP Connection

You can see struct ctf_brc and struct ctf_ipc in the attached
hndctf.h. I didn't focus on ctf_brc yet, but I tried to analyze
ctf_ipc. It contains set of data allowing detection of the specific IP
connection. Pretty obviously, it means storing protocol, source (MAC,
IP, port), destination (MAC, IP, port) and few others (like VLAN id,
NAT rules, target interface) values. I guess that ctf.ko analyzes
every received packet using rules stored in struct ctf_ipc. When it
gets some packet covered in it's struct ctf_ipc database, it doesn't
pass it to the OS, but modifies it itself (if needed) and transmits to
the target.
You can see that nf_nat_packet was modified to call
ip_conntrack_ipct_add which tests if the packets matches it's
requirements. If it does, a new IP forwarding rule is added using
ctf_ipc_add.

I wonder what do you think about this solution. Is this something we
could try to implement ourself? Is it worth it? Is there some existing
project doing similar thing?

While ctf.ko module is closed source, it should be possible to
re-implement it. It probably just keeps a list of rules and does some
simple modifications of the received packets (like VLAN id change,
IP/port hacking for SNAT/DNAT), etc.

I don't have any experience in hacking net layer, so any comments on
that would be great!
--
Rafał
Kristian Evensen
2013-08-24 17:14:50 UTC
Permalink
Hi Rafal,
Post by Rafał Miłecki
I wonder what do you think about this solution. Is this something we
could try to implement ourself? Is it worth it? Is there some existing
project doing similar thing?
This is a very interesting discovery. Have you tried to use etables
and checked how much data you can push through the router? For
example, have one machine connected to the LAN and one to the WAN port
(probably using static IPs for the "WAN" is the easiest). Use MAC NAT
(http://ebtables.sourceforge.net/examples/basic.html#ex_nat) on the
OpenWRT router to set the destination to the machine connected to the
WAN, push UDP traffic from a client connected to the LAN to some
remote IP and see how much data flows through the router. Use for
example bwm-ng on the machine connected to the WAN port to see current
throughput (also to avoid putting any additional pressure on the
router CPU). Be aware that unless you configure the machine connected
to the WAN port as a router, the forwarded packets will be discarded.

If this works and gives good performance, based on my understanding,
you could implement this ctf module as an etables extension.

-Kristian
Rafał Miłecki
2013-08-25 21:16:37 UTC
Permalink
Post by Kristian Evensen
Hi Rafal,
Thanks Kristian for your reply, unfortunately I can't make it work the
way I want :(
Post by Kristian Evensen
Post by Rafał Miłecki
I wonder what do you think about this solution. Is this something we
could try to implement ourself? Is it worth it? Is there some existing
project doing similar thing?
This is a very interesting discovery. Have you tried to use etables
and checked how much data you can push through the router? For
example, have one machine connected to the LAN and one to the WAN port
(probably using static IPs for the "WAN" is the easiest). Use MAC NAT
(http://ebtables.sourceforge.net/examples/basic.html#ex_nat) on the
OpenWRT router to set the destination to the machine connected to the
WAN, push UDP traffic from a client connected to the LAN to some
remote IP and see how much data flows through the router. Use for
example bwm-ng on the machine connected to the WAN port to see current
throughput (also to avoid putting any additional pressure on the
router CPU). Be aware that unless you configure the machine connected
to the WAN port as a router, the forwarded packets will be discarded.
If this works and gives good performance, based on my understanding,
you could implement this ctf module as an etables extension.
I've tried to setup network the way you suggested.

I configured OpenWrt router to use static 192.168.5.2 on the WAN
interface and then I set 192.168.5.1 on my monitor (bwm-ng) machine
connected to that WAN port.

OpenWrt uses 192.168.1.1 by default on LAN ports and my second (TX)
machine received some random 192.168.1.131.

I use iperf on my 192.168.1.131 TX machine, so I decided to tell iperf
to use 192.168.1.1 and redirect that traffinc (on the OpenWrt router)
to the WAN port. To do that I typed:
ebtables -t nat -A PREROUTING \
-d $(OPENWRT_MAC) \
-i eth0.1 \
-j dnat --to-destination $(MONITOR_MACHINE_MAC)

eth0.1 interface is the one used for LAN ports and bridged with the br-lan:
# brctl show
bridge name bridge id STP enabled interfaces
br-lan 7fff.204e7fab3aa8 no eth0.1

Then I started:
iperf -c 192.168.1.1 --udp
on my TX machine, but no RX traffic has appeared on my monitor
(192.168.5.1) machine :(

What's worse, after executing that "ebtable" command even direct:
iperf -c 192.168.5.1 --udp
doesn't generate any RX on my monitor (192.168.5.1) machine. Flushing
-t nat makes that direct command work again.

I guess I did something wrong in my ebtables rule. Do you have any
idea what could it be? It's the first time I've heard about ebtables
to be honest.
--
Rafał
Rafał Miłecki
2013-08-25 21:26:21 UTC
Permalink
Post by Kristian Evensen
If this works and gives good performance, based on my understanding,
you could implement this ctf module as an etables extension.
I guess you got some idea of what Broadcom can be doing in their magic
ctf.ko. Could you share some details on that, please?

Do you think they implemented packets routing/forwarding in the 2nd
OSI data link layer? This could explain the set of *brc* commands in
their API:
ctf_brc_add, ctf_brc_delete, ctf_brc_update, ctf_brc_lkup and struct ctf_brc

But they also have some ipc commands like:
ctf_ipc_add, ctf_ipc_delete, ctf_ipc_lkup (and struct ctf_ipc)
Could they implement NAT in the IP layer (3rd OSI network layer) in
some magic way that is faster than Linux's IP NAT?

If you know some document explaining net subystem including IP NAT,
MAC NAT, hacking VLAN ids, etc. I would love to see it.
--
Rafał
Kristian Evensen
2013-08-26 07:26:07 UTC
Permalink
Hi Rafael,

I will just reply to both emails here. First, it seems as though my
ebtables knowledge has gotten a bit rusty and there were some details
I forgot. The tool is used for firewalling bridges, so, the LAN and
WAN interface has to make up a bridge. I succeeded with a simple
configuration on my device, but it is not really usable for anything.
If something comes out of it, I will let you know.
Post by Rafał Miłecki
I guess you got some idea of what Broadcom can be doing in their magic
ctf.ko. Could you share some details on that, please?
What I suspect is that the Brodcom-modules does, and why I thought of
ebtables, is some sort of static routing. Since a normal home router
only has a single WAN-connection, all traffic will go out through the
same port and, thus, full routing is not needed. Something similar to
switching would be sufficient. One would still have to do NAT though,
so it could be that the Broadcom module also does NAT. I am not sure
which device you are using, but if it one of these that have hardware
NAT, that would explain why the NAT calls are modified.

I am currently working on figuring out how to deal with a similar
problem. I will let you know if I come up with something.

-Kristian
Rafał Miłecki
2013-09-02 20:41:22 UTC
Permalink
Post by Kristian Evensen
I am currently working on figuring out how to deal with a similar
problem. I will let you know if I come up with something.
Can I ask you about the progress? Did you figure out anything? I
really would love to get that Ethernet fully supported (including
performance) and focus on different stuff :(
--
Rafał
Loading...