How to build your own multicast capable CPE
Recently, I was faced with a challenge. I needed a CPE which was able to receive multicast over PPPoE session and send it to a client behind NAT. To the best of my knowledge, no commercially available CPE can perform this task. Yes, I know that dd-wrt should be able to do the trick but I did not have an old Linksys laying around. So I decided to build my own CPE based on a Soekris net5501.
My OS of choice has been FreeBSD for 10 years now so I installed FreeBSD 8.2 on a 16GB compact-flash card. By default, a working PPPoE client is installed, so I only had to configure it. My /etc/ppp/ppp.conf looks like this:
default: set log Phase tun command # you can add more detailed logging if you wish set ifaddr 10.0.0.1/0 10.0.0.2/0
client: set device PPPoE:vr0 # replace xl1 with your Ethernet device set authname my-user set authkey my-password set dial set login add default HISADDR
After configuring the PPPoE client to start-up upon boot, it connects automatically and performs NAT. When this was working, I installed isc-dhcp41-server to enable DHCP on the “LAN” side of the network. No problem of course, but for your reference here is my configuration file:
option domain-name "cluecentral.net";
option domain-name-servers 208.67.222.222, 208.67.220.220;
default-lease-time 600;
max-lease-time 7200;
ddns-update-style none;
authoritative;
log-facility local7;
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.10 192.168.0.200;
option routers 192.168.0.1;
}
The next challenge was to enable multicast traffic. In order to allow multicast traffic to traverse the router, the kernel module ip_mroute.ko must be loaded. Initially, I configured /boot/loader.conf to handle this, but after a reboot my kernel kept crashing. I eventually move this part to /etc/rc.local.
Now that we have PPPoE, DHCP and general multicast working, the difficult part was waiting. If you know how multicast work, you will know that in sparse-mode, IGMP is required to request a multicast stream. This is the problem that I was encountering with commercially available hardware: IGMP proxying is generally not supported. The FreeBSD ports have igmpproxy, written by Constantin Baranov and Johnny Egeland. I installed igmpproxy, and here is my configuration file:
quickleave phyint tun0 upstream ratelimit 0 threshold 1 altnet 192.168.0.0/16 phyint vr1 downstream ratelimit 0 threshold 1 phyint vr2 disabled phyint vr3 disabled
Now I had another problem: due to some bug, it would not startup correctly the first time. So I enabled a restart in /etc/rc.local and voila: it works!. For your reference, my /etc/rc.local is below:
/sbin/kldload ip_mroute.ko /usr/local/etc/rc.d/igmpproxy start sleep 2 /usr/local/etc/rc.d/igmpproxy stop sleep 2 /usr/local/etc/rc.d/igmpproxy start
And for even more reference, my /etc/rc.conf
keyrate="fast" sshd_enable="YES" hostname="CPE" ifconfig_vr0="up" ifconfig_vr1="192.168.0.1/24" sendmail_enable="NONE" igmpproxy_enable="YES" mrouted_enable="NO" cloned_interfaces="tun0" ppp_enable="YES" ppp_mode="ddial" ppp_nat="YES" ppp_profile="client" dhcpd_enable="YES" dhcpd_flags="-q" dhcpd_conf="/usr/local/etc/dhcpd.conf" dhcpd_ifaces="vr1" dhcpd_withumask="022" gateway_enable="YES"
Comments are welcome.