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.

Leave a Reply