BSD Router Project - Customised for HUBS
At various nodes on the network, where non-trivial routing decisions must be made, we have put in some small embedded systems running on the Soekris net5501 as it is inexpensive, comes with four 10/100baseT ethernet ports and has a reputation as a solid, reliable device. To try and stay consistent with the previous deployment which ran OpenWRT, a kind of Linux, we initially ran the same software on these routers. This led to some bad experiences which proved to be traceable to a bug in the Linux driver for the VIA Rhine III ethernet chip. Given the choice between sinking a lot of time into figuring out what's wrong with Linux and trying to fix it, or running BSD UNIX on these things, which is known to work well, the choice is obvious.
What follows is an introduction to FreeBSD as set up on these routers, where to look for configuration files, how to modify them and save or revert the changes, what tools are available for troubleshooting and diagnosing network problems, and so forth.
The Hardware
Most of the material here really doesn't depend very much on the hardware that is used, but just to have an idea of what we're working with, here's a photograph:
Along the top is a USB port (unsed), the connector for an external power supply, a good old-fasioned DB9 serial port connector and four 10/100 ethernet interfaces. On the left there is a connector for an internal hard drive (unused) and a miniPCI slot that could take a wireless NIC or a cryptography ASIC (also unused) and on the right hand side there is a PCI slot that could take, for example, a gigabit ethernet card. In the lower left corner there is a Compact Flash card to provide stable storage for the operating system, and there are blinking lights along the bottom.
From the external connector it can be powered with anything from 6-20VDC. The CF slot is convenient. Many embedded systems have their flash storage surface mounted, soldered directly onto the board. The CF card can be easily swappeded if necessary with a readily available replacement and the operation does not require a soldering iron. These things do eventually wear out.
The big chip in the centre is an AMD Geode LX running at 433MHz or 500MHz depending on which board is purchased. We actually run the 433MHz variety. This is just a relatively normal i586 class CPU.
The Operating System
  It would be possible to do a regular BSD install onto the CF
  disk but it wouldn't be a very good idea for two
  reasons. Firstly, flash storage is not like using a disk with
  spinning magnetic platters. It wears out rather more quickly. A
  regular installation will result in write operations,
  particularly in /var (the volatile data filesystem)
  and this is not good for the disk. Less obviously, it should be
  possible not only to field-upgrade the system, but to revert to
  the previous version if the upgrade goes badly. As well, it is
  nice to be able to modify the running system's configuration
  but not have it "stick" until explicitly saved.
The basic mechanisms for accomplishing the above are implemented in the NanoBSD shell script. This script builds a system out of the standard FreeBSD source tree and prepares it to be written to the CF disk.
But NanoBSD is pretty basic. It is just a bare-bones FreeBSD install and one of the things that the BSD school does purposefully is not install the kitchen sink. The basic operating system contains basic things that are needed on most systems, and anything else is provided by third party pakages. NanoBSD provides the basic framework for adding these packages, but the choice of which ones to add is left up to whomever is building the image. Because NanoBSD on its own is not exceptionally useful, one won't find very many pre-built plain images floating around, for example.
The BSD Router Project uses NanoBSD with a configuration that adds in the extra software that one might typically want to have on a router, as well as providing a couple of extra tools and scripts to help with administration. This gets us most of what we need. There are still some minor tweaks, mostly in the way of pre-made configuration files to minimise the amount of work necessary to provision a new router, so we've made some minor modifications to facilitate this (available in this git repository). Pre-built images may be downloaded here.
Installation
The easiest way to install the system is to use a CF reader and a PC and to simply download an image and run,
dd if=BSDRP_1.2_full_i386_serial.img of=/dev/da0 bs=64k conv=syncsubstituting the appropriate image name (having been decompressed with
unxz(1))
  and device file for your CF reader. Then simply remove the
  card from the reader and install it into the router.
  It is most likely that the first time the router starts from a
  blank image, it will not have an IP address anywhere that is
  of any use at all. So to do any initial setup a serial console
  is required. Use a null modem cable between your computer and
  ther router and a terminal program such as cu(1),
  minicom, or hyper terminal and set the line to 38400 baud, 8
  bits data, no parity and one stop bit.
  The first thing to do is set the root password using
  the passwd(1) program otherwise it will not be
  possible to log in over the network.  Once the router is up
  and running and has an IP address, and has had the root
  password set, it can be connected to using ssh(1)
  (or Putty or the like).
Disk layout
The disk is separated into four partitions:
- operating system 1
 - operating system 2
 - configuration
 - data
 
/etc directory, and the data partition is for
  backups and suchlike.
  When the system starts up, one of the first things it does is
  create two memory disks, volatile areas in RAM that behave
  like a disk but whose contents are lost on reboot. The first
  one is mounted on /etc and is populated with
  a default configuration. Any changes from the default, which
  are preserved across reboots are then copied in from the
  configuration partition. The second memory disk is mounted
  on /var where any runtime state that never needs
  to be preserved across reboots is kept. The result looks like
  this: 
  
[root@router]~# df -h Filesystem Size Used Avail Capacity Mounted on /dev/ufs/BSDRPs1a 100M 56M 43M 57% / devfs 1.0k 1.0k 0B 100% /dev /dev/md0 4.6M 1.3M 2.9M 31% /etc /dev/md1 9.2M 568k 8M 7% /var(Note that the root filesystem,
/ is mounted
  read-only).
The point of this is that the system runs entirely from a read-only partition on disk, and from volatile data in RAM. In the event of a configuration error or runaway process, it may be restored to exactly how it was previously by a simple reboot.
Startup
  In times gone by, all of the things that needed done to bring
  up a BSD system were done by a shell script
  called /etc/rc. This was typically shipped by the
  operating system vendor and not really intended to be changed
  by users or system administrators. Instead, the last thing
  that this script would do is run another script,
  called /etc/rc.local. Any site-specific setup was
  done in there. This was a quite different and far simpler
  system than what was in System V UNIX which had a complicated
  arrangement of different runlevels and sets of scripts that
  would start and stop individual programs in the different
  runlevels (most Linux systems have a SysV-like setup). Still,
  it has always been very common to want to stop and start a
  particular background process or daemon on its own and the BSD
  systems gradually migrated to a middle ground. They still
  don't have the complicated system of runlevels, but they do
  have couple of directories full of
  scripts, /etc/rc.d
  and /usr/local/etc/rc.d that are each responsible
  for starting and stopping a particular aspect of the running
  system.
  Which of these scripts are run, and any parameters their
  programs might take is governed by the
  file /etc/rc.conf. This is the basic, most
  important configuration file on the system. It is where you
  set the hostname of the system, specify which IP addresses go
  on which interfaces or whether you want to run
  the Quagga
  or BIRD routing daemons,
  etc. Here is a minimal, working example:
# Hostname hostname="router.example.net" # Enable SSHd sshd_enable="YES" # Enable routing gateway_enable="YES" # Enable RFC1323 extensions tcp_extensions="YES" #Waiting for a default route defaultroute_delay="5" defaultrouter="NO" bird_enable="YES" pf_enable="YES" ipv4_addrs_lo0="127.0.0.1/8 10.255.255.1/32" ipv4_addrs_vr0="10.0.0.1/24" ipv4_addrs_vr1="10.0.1.1/24" ipv4_addrs_vr2="10.0.2.1/24" ipv4_addrs_vr3="10.0.3.1/24"There are a couple of things to note about this setup. First is that, in addition to the normal localhost / 127.0.0.1 address on the loopback interface, there is a second address, 10.127.255.1. This is a useful thing to do on routers because it gives you a stable, predictable IP address that they can be identified with, that isn't tied to a physical interface that might be up or down or unreachable or have to be renumbered. If you have a network management system, this is the address that is used to poll the router to see if it is up and to collect any traffic or usage statistics.
The other thing is that usually on a workstation or server we would put a default route in this configuration file. Because this is a router and we have specialised software to keep track of routes and such, this bit of configuration is done there instead. This will be explained in considerable detail below.
Also worth noting, pf is the packet filter that comes from OpenBSD. With FreeBSD there is actually a choice of no less than three different packet filtering / address translation mechanisms, the other two being ipfilter and ipfw. The choice between them more or less comes down to preference.
Author's note: I like pf because when I had to extend address translation to a specialised use case in the past, I found that it was the easiest to understand and modify.
Basic Administration
Before going into detail about the different parts of the system and how to set them up, a couple of things need to be understood, how to save a working configuration and how to upgrade the system to a new operating system image.
config(1)
  The config(1) command is a script that comes from
  the BSD Router Project. What it does is mount the
  configuration and data partitions, make a backup of the old
  configuration, and save the contents of the /etc
  directory. At any rate that is what the config
  save command does. The script will also do related
  things like tell you which files have been modified, roll back
  to a previous configuration, reset to factory defaults,
  etc. Run it on its own to see the help message:
  
[root@router]~# config
BSD Router Project configuration tool
Usage: /usr/local/sbin/config option
  - diff     : Show diff between current and saved config
  - save     : Save current config
  - apply    : Apply current config
  - rollback : Revert to previous config
  - put      : Put the saved config to a remote server
  - get      : Get config from remote server
  - factory  : Return to default configuration
  - help (h) [option]  : Display this help message.
                   If [option] given, display more detail about
                   the option
There is an idiom that is extremely useful when working with remote systems over a network and is made so much more effective by the fact that if you don't explicitly save the configuration, the router will come back online in its previous setup on a reboot. So if you're going to do something dangerous, particularly something that might cut off your access to the router if it goes wrong or you make a mistake,
[root@router]~# shutdown -r +5 Shutdown at Wed Jul 18 08:23:47 2012. shutdown: [pid 3626] [root@router]~# *** System shutdown message from root@router.example.net *** System going down in 5 minutes [root@router]~# .... now do your dangerous stuff... and if it worked ... [root@router]~# kill 3626
shutdown is just a program that waits for a
  certain amount of time and then reboots (with
  the -r flag) the system. Because it is just a
  normal program, you can kill it while it is waiting around for
  the timeout to expire, and the reboot will never happen. If
  you lock yourself out, unless you've done
  something really bad, the router will just reboot and
  you should be able to get back in for another go.
Upgrading
  Upgrading the router is simple. There is another program that
  comes from the BSD Router Project simply
  called upgrade(1). It wants an operating system
  image on its standard input, so you could run, for example,
  
[root@router]~# ftp -o - http://images.example.net/BSDRP....img.xz \
    | xzcat | upgrade
  It will take a few minutes to run and write the new image to
  the inactive operating system partition. Simply reboot and the
  system will start with the new version.
Editing Files
  From time to time to setup the system it is necessary to edit
  files. The traditional tool to do this is
  the vi(1). However, another change that has been
  made to BSDRP is to add in the nano(1) editor
  which is easier to use and provides on-screen help. Whichever
  is preferred, there is a wrapper called rvi that
  should be used to keep any changes to the config files under a
  revision control system called rcs(1). Just pay
  attention to the prompts, and this can provide useful
  information to help with any troubleshooting in the
  future. The rvi wrapper will honour
  the EDITOR environment variable which is set to
  use the nano editor by default in our
  system. This can be changed when logged in for the current
  session as,
  
setenv EDITOR viAn example of editing the
/etc/motd file for the
  first time:
  [root@router]~# rvi /etc/motd ... editor starts up ... rcsdiff: /etc/RCS/motd,v: No such file or directory /etc/RCS/motd,v <-- /etc/motd enter description, terminated with single '.' or end of file: NOTE: This is NOT the log message! >> /etc/motd -- system welcome message >> . initial revision: 1.1 doneNote that if you do not use the
rvi
  command when editing files, the next person to edit
  them that does use it may likely overwrite your
  changes.
Routing Daemons
Whilst the actual forwarding of packets is done by the kernel, we need a program to set this up, to tell the kernel which way to send different kinds of packets. In other words, we need a program to manage the kernel's routing table.
  The basic command for altering the routing table
  is route(1). It can be used to query the routing
  table,
  
[root@router]~# route -n get 192.0.2.1or add a route,
[root@router]~# route add -net 192.0.2.0/24 192.168.0.1but it simply changes the running state of the system and any changes aren't preserved across reboots.
  To look at the state of the routing table a different
  program, netstat(1) can be used,
  
[root@router]~# netstat -f inet -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 172.16.32.1 UG1 0 601 vr0 10.0.2.0/24 link#3 U 0 0 vr2 10.0.2.1 link#3 UHS 0 0 lo0 10.0.3.1 link#4 UHS 0 0 lo0 10.11.0.0/29 link#2 U 0 14204 vr1 10.11.0.1 link#2 UHS 0 0 lo0 10.127.255.8 link#8 UH 0 0 lo0 10.127.255.9 10.11.0.2 UGH1 0 0 vr1
  These commands are good as far as they go, but
  the route(1) command is entirely manual. Its
  changes affect the running system and aren't persistent across
  restarts (of course one could easily enough write a script to
  run it), but more importantly it won't "learn" routes from
  other routers or react to changes in the network
  topology. The netstat(1) command is likewise
  useful, but where we have routes learned from other sources it
  won't say anything about from where they were learned or any
  associated details like preferences or metrics. For this we
  need a dynamic routing daemon.
  There have been several routing protocol implementations for
  UNIX for many years. The earlier ones routed
  and gated were in the tradition that tried to do
  only one job and to do that job well ("the UNIX Way").
More recently GNU Zebra and its fork Quagga and XORP have tried to implement routing protocols and at the same time emulate the look and feel of the large commercial router vendors (Cisco and Juniper respectively). XORP is probably the most advanced of these, allowing one to configure firewall rules and VLANs and the like from within its interface, in addition to routing protocols like OSPF and BGP. Though their aims are intriguing, and there would be a strong argument for using them if they didn't feel incomplete, often requiring the setup of lower-level things using the regular operating system tools and just not quite working right outside of their core areas, in practice their use can be confusing.
  A simple example: it is possible to put an IP address on an
  interface using these programs. Suppose you have a router and
  you can see that it has an address configured on some
  interface, and this address is incorrect or needs to be
  changed or something. How do you track down where it came
  from? Maybe it was set up by the usual OS startup scripts
  (e.g. through /etc/rc.conf). Maybe it came from
  Quagga or XORP. Maybe, it has been configured in both
  places because the admin thought, quite reasonably, that it
  was a good idea to have it set up in the "standard" way but
  also to have it visible when inspecting the configuration from
  the routing daemon's interface. What are all of the failure
  modes that can happen if, say, a bug forces changing from
  Quagga to XORP or to something completely different? This kind
  of thing can be avoided with some discipline when setting
  things up, and the encouragement (not to say enforcement) of
  best practices, but ideally it would be best to remove the
  temptation to do the same thing in multiple places.
There is another, current, routing protocol implementation called BIRD that is more in the tradition of the old UNIX routing daemons. It started out as a graduate school project at the Charles University in Prague and has since been adopted by the CZ NIC Labs. It has been proven stable enough to have replaced Quagga at some major Internet exchange points as a route server. Though the BSD Router Project ships with both BIRD and Quagga, we prefer BIRD, and one of the modifications that we have made to BSDRP is to run it by default instead of Quagga.
BIRD
  The BIRD configuration file lives
  in /etc/local/bird.conf (for
  IPv6, /etc/local/bird6.conf). The format is in
  the C language and ISC tradition with curly braces, and it
  also includes facilities for functions and such that can be
  used in filters. Here is a real example configuration:
  
/*
 * BIRD configuration file for SMO-CORE
 */
log syslog { debug, trace, info, remote, warning, error, auth, fatal,
 bug };
router id 10.127.255.z;
/*
 * Identify if the given network should never ever
 * be seen in the routing protocols...
 */
function is_bogon(prefix network)
{
  if (network ~ [127.0.0.0/8, 192.0.2.0/24])
          then return true;
  return false;
}
protocol kernel {
  persist;                # Don't remove routes on bird shutdown
  scan time 20;           # Scan kernel routing table every 20 seconds
  import all;             # Default is import all
  export all;             # Default is export none
}
# This pseudo-protocol watches all interface up/down events.
protocol device {
  scan time 10;           # Scan interfaces every 10 seconds
}
protocol static SMO {
  route 0.0.0.0/0 via 194.35.x.y;
}
/*
 * connected, static -> OSPF
 */
filter export_OSPF {
  if is_bogon(net) then reject;
  case source {
          RTS_DEVICE: accept;
          RTS_STATIC: accept;
  }
  reject;
}
/*
 * OSPF -> kernel
 */
filter import_OSPF {
  if is_bogon(net) then reject;
  accept;
}
protocol ospf TEGOLA {
  export filter export_OSPF;
  import filter import_OSPF;
  area 0.0.0.0 {
          interface "lo0";
          interface "vr0" {
                  authentication cryptographic;
                  password "xxx";
          };
          /* radio facing creagan-dearga */
          interface "vr1" {
                  hello 5;
                  dead count 6;
          };
          /* radio facing beinn sgritheall */
          interface "vr2" {
                  hello 5;
                  dead count 6;
          };
          /* radio facing west knoydart */
          interface "vr3" {
                 stub on;
          };
  };
}
Let's go through this in detail. The first bit sets up logging to syslog and sets the router ID to be the unique /32 address that is set up on the loopback interface.
Next we have an example of a function. This is used in filters to prevent addresses that should never appear in the routing tables as advertised to other routers, but nevertheless may be configured, e.g. for testing or some such, on the local system from time to time.
  The protocol kernel section governs the
  interaction with the system's routing table, the one that is
  actually used for forwarding traffic. It is not a given that
  routes learned via a routing protocol end up in the actual
  routing table because sometimes BIRD is used as a route
  server, simply to distribute information amongst other routers
  on a system that forwards no traffic at all. It is also
  possible to have multiple kernel routing tables for policy
  based routing although this is generally evil and breaks the
  Internet. 
  The protocol device section is necessary for
  gleaning network information from the physical interfaces and
  for checking when they are up or down or change state, vital
  information for link-state algorithms such as OSPF.
  The protocol static section is where static
  routes go.
We are only running OSPF at the moment, and want to exchange routes not only natively in the OSPF area but want to inject some static routes. Here we inject a default route, but at other places in the network we must inject more specific routes on behalf of routers that cannot run a routing protocol. This is done via a couple of filters.
  filter export_OSPF governs what routes get
  advertised by OSPF by this router. It first filters out any
  routes that have anything to do with bogus networks that
  should never be spoken of in polite company, then lets through
  anything that is directly configured on an interface and
  static routes, and rejects anything else.
  filter import_OSPF governs what routes learned
  from OSPF get set in the kernel routing table. This is a
  safety mechanism in case some other router has leaked a bogus
  route, we stop it from getting used here, and allow everything
  else through.
  Finally the protocol ospf section sets up the
  OSPF protocol. The filters are applied first and then all of
  the physical interfaces on the box (and the loopback interface
  for our special unique address) are placed in the backbone
  area with different parameters. 
  The first interface vr0 is connected to a public
  switch and talks to another of our routers there, but because
  we are not the only ones who can plug something into that
  switch, authentication is turned on for that interface. The
  next two, vr1 and vr2 are connected
  to other OSPF-speaking routers via wireless bridges and
  because the state of wireless network is slightly more
  volatile than regular ethernet, the "hello" and "dead
  interval" timers are set appropriately. The last
  interface vr3 is connected to a client or
  end-user network and is set with "stub on" so that it is
  advertised via OSPF but the router will not form an adjacency
  with another OSPF router there.
  The running state of the BIRD daemon can be inspected with
  the birdc(1) program. This is an interactive
  command line program, and an example session might look like: 
  
BIRD 1.3.7 ready. bird> show ospf neighbors TEGOLA: Router ID Pri State DTime Interface Router IP 10.127.255.x 1 full/bdr 00:30 vr1 10.11.a.b 10.127.255.y 1 full/bdr 00:28 vr2 10.11.c.d bird> show route 0.0.0.0/0 via 194.35.x.y on vr0 [SMO 05:06] * (200) 10.130.0.0/28 via 10.11.a.b on vr1 [TEGOLA 06:58] * I (150/1010) [10.127.255.9] 10.130.0.0/16 via 10.11.c.d on vr1 [TEGOLA 06:58] * E2 (150/20/10000) [10.127.255.9] ...Here we can see two OSPF neighbours, in an up and running state, as well as several routes, the first that we know via a static route (the "SMO" tag from the configuration file) and the second two via OSPF (the "TEGOLA" tag). The first OSPF route is a "native" or internal route ("I") and the second is external type 2 ("E2") and has come from another router injecting a static route into OSPF.
  If the BIRD configuration
  file, /etc/local/bird.conf the daemon can be
  caused to re-read it without being stopped and restarted by
  giving the configure command in
  the birdc(1) command line interface. If the
  system gets itself into a strange state,
  the reload or restart commands may
  be used, with great care, to kick specific protocols.  
  Remember, once /etc/local/bird.conf has been
  changed and is working correctly, to save the working
  configuration, 
  
[root@router]~# config saveand also remember to use the
shutdown -r +5 trick
  from above when making any but the most trivial changes if
  there is any risk at all that the router will become
  unreachable as a result.
Packet Filtering
A word about packet filtering. It is very different in an Internet Service Provider environment from a company network. It is not the place of an ISP to make assumptions about what the users will be doing with the network. For this reason, packet filtering to enforce some sort of global security or usage policy is not appropriate. The place for this sort of thing is at the edge, as close to the end-user as possible. It is entirely appropriate for me, for example, to have whatever security policy and packet filters I like on my home gateway router. But my ISP knows nothing about the choices I have made for this and it would restrict what I could do on the Internet if they were to foist their choices on me.
There are some exceptions to this rule. The main one is because of bulk unsolicited email, or spam. It is common practice to filter outgoing connections to port 25 (smtp, email sending) from end-user connections going to other than the ISP's own mail servers. Though this breaks the rule, it is unusual that a correctly configured end-user system would need to do this. In the case of an end-user that knows what they are doing and really wants this, the usual practice is to make an exception for them. This breaks the general rule, but is quite effective in cutting down the volume of spam on the Internet and the trade-off is generally considered to be worth it.
There is still a place for some packet filtering on routers, however. This is not to filter traffic passing through the router, but to filter traffic destined for it. Administrative traffic, such as SNMP and SSH sessions to the router, for example, might reasonably be disallowed from the wild Internet.
  As we have chosen to use the pf(4) packet filter,
  the configuration file is /etc/pf.conf. Let us
  start with an example:
  
tablepersist file "/etc/blackhole" table { 127.0.0.0/8, 192.0.2.0/24 } table { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } table { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, \ 194.35.x.y, 194.35.x.z } table { 10.127.255.8, 10.11.a.b, 10.11.c.d, 10.11.e.f, \ 194.35.p.q } ## localhost traffic, simply allow set skip on lo0 ## Basic policy pass in no state pass out no state ## sanity filters block in log from any to block in log from any to block in log from to any block in log from to any ## policy filters block in log from any to pass out from to any pass in proto icmp from any to pass in proto udp from to port snmp pass in proto tcp from any to port ssh ## stop extraneous state from OSPF pass in proto ospf no state pass out proto ospf no state 
Again, going through this in order, the first section sets up some lookup tables these are used later on to keep rules nice and succinct.
Next, we basically turn off the packet filter entirely on the local interface, for locally generated traffic. No need to waste CPU cycles here, if we can't trust traffic generated by the local system there are bigger problems that a packet filter won't solve. State is the enemy of performance.
Next come the actual filters. These are read in order and the last one to match applies. So the first thing we do is allow all traffic through, and keep no state. To the extent that we can avoid keeping state for general traffic, we should do so. Keeping state for each connection through the router takes up RAM and CPU resources and, since this is not a corporate firewall, provides little benefit.
Next we drop any obviously bogus packets. Packets with these addresses should never be seen on the network.
  Finally, we drop all traffic for the router itself, excepting
  SNMP from the internal network (this is rather permissive, it
  could reasonably be tightened to any management hosts) and ssh
  from anywhere (again, perhaps slightly permissive). ICMP is
  also allowed; many people often block "pings" in the belief
  that it is an information link. To an extent this is true, but
  this is far outweighed by the utility of
  the ping(1) command for debugging. There is also
  a rule allowing outbound connections from the router, and all
  of these rules allowing connections to the router are
  stateful so that it is possible to use the
  command pfctl -s state to see active
  connections.
  Having made a change to /etc/pf.conf to reload
  the packet filter there are two choices:
[root@router]~# /etc/rc.d/pf restart [root@router]~# /etc/rc.d/pf reload
  The difference is that the first restarts the filter
  completely, purging all state, etc. This means that since you
  are most likely connected with ssh(1), your
  session will be killed. Not to worry, it's slightly
  inconvenient, but it should be possible to log back in. So
  long as no errors were made in /etc/pf.conf that
  might cause this not to work -- you did remember
  the shutdown -r +5 trick right?
The second just reloads the rules more gently without losing state and shouldn't kill your session. In most circumstances this is the one to use.
  A nice thing about the default stateful rules of pf
  is that you start out being able to see, with pfctl -s
  state what traffic is hitting the rules. This provides a
  way to know what other rules might be necessary to get rid of
  extraneous state.
It is a good idea to put the "log" option on rules that block traffic. This way it is possible to tell what traffic is being blocked, which is useful for debugging problems. "log" doesn't mean "write to a log file" with pf, rather it means that the packets will be written to a pseudo-interface called pflog0. To watch for blocked packets simply run,
[root@router]~# tcpdump -n -i pflog0 tcpdump: WARNING: pflog0: no IPv4 address assigned tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 65535 bytes ...
Address Translation
For a border router, at the upstream edge, NAT is, sadly, necessary for us at the moment. This could be avoided with a suitable block of public IP addresses, but for now it is a necessary evil. The pf provides address translation facilities, and they are configured in the same file by adding in,
nat_if=vr0 nat_addr=194.35.x.y ... ## NAT nat on $nat_if fromto ! -> ($nat_if) 
Quite simple, and shows the use of variables that can help keep the rest of the configuration file simple and readable. The NAT rule is set up as it is because there are some public IP addresses on the internal network and they should never be translated, and it should as well be possible to talk directly between them and our RFC1918 addresses as they are on the same network.
Name Resolution Service
  As usual on UNIX hosts, the resolver used by the system is
  configured in the file /etc/resolv.conf which
  might look something like this (using Google's nameservers):
search example.net nameserver 8.8.8.8
This is all that is required for the router itself to be able to resolve names. If, however, the router is to provide DNS service to client hosts, we have added Unbound recursive server.
Network Time Service
  The simplest option is to enable NTPD and the NTP client
  in /etc/rc.conf: 
ntpdate_enable="YES" ntpd_enable="YES"
  This will cause the router to first query the time servers
  in /etc/ntp.conf to synchronise the clock roughly
  and thereafter to cause the NTP daemon to keep it
  synchronised. It is generally considered impolite to overuse
  public NTP servers, so when running a network of any size it
  is best to have a couple of time servers on the network which
  synchronise with the public ones, and then everything else
  uses them. The router will make an adequate time server for
  the network.
  It is possible to inspect the state of the time
  synchronisation using the ntpdc(8) command. This
  is an interactive interface similar in feel
  to birdc. A '?' character will list available
  commands and perhaps the most useful one is "peers":
[root@router]~# ntpdc
ntpdc> peers
     remote           local      st poll reach  delay   offset    disp
=======================================================================
*prrr.se         192.0.2.1        2   64  377 0.06036  0.038833 0.04912
=ntp2.m-online.n 192.0.2.1        2   64  377 0.05385  0.037582 0.04248
=79.99.122.29    192.0.2.1        2   64  377 0.03888  0.040549 0.05627
=host-217-69-78- 192.0.2.1        3   64  377 0.04118  0.038687 0.04434
ntpdc>
Monitoring and Statistics
  The main facility for remote monitoring is SNMP. To enable it,
  place the following in /etc/rc.conf:
  
snmpd_enable="YES" snmpd_conffile="/etc/local/snmpd.conf"and either edit the default
/etc/local/snmpd.conf
  or start with this minimal version:
  
  com2sec internalnet 10.0.0.0/8 b1gs3cr3t com2sec internalnet 172.16.0.0/12 b1gs3cr3t com2sec internalnet 192.168.0.0/16 b1gs3cr3t group MyROGroup v1 internalnet group MyROGroup v2c internalnet group MyROGroup usm internalnet view all included .1 80 access MyROGroup "" any noauth exact all none none syslocation Some place, some where syscontact Some Staffload 12 14 14 
As with the corresponding firewall rules, the internalnet access group is rather permissive and could reasonably be tightened up. Obviously the b1gs3cr3t should be changed to something suitable as well and the contact and location changed to a more helpful value.
TODO: make this configuration more automatic "out of the box"
Performance Tuning
There are some things that can be done to improve efficiency. The main thing has to do with how inbound packets are handled. By default each interface will generate an interrupt to signal the arrival of each packet. This causes a context switch and there is enough overhead associated with this (and the processor on the Soekris is slow enough) that it can have a seriously deleterious effect on performance. Even with large 1500 byte packets, 60Mbps of traffic (around 5000 packets per second) will show a CPU usage of about 30%, almost entirely in the interrupt handler. An alternative strategy is available, to set the operation of the cards to polling mode where the kernel periodically checks to see if there are any inbound packets to process and handles them in batches. This is accomplished by setting,
polling_enable="YES"in
/etc/rc.conf.misc. With this setting active, cpu 
  usage drops to around 0.5% with no noticeable impact on
  performance. The mechanism used by polling startup script is
  simply the ifconfig(8) command run, for example,
  as: 
  [root@router]~# ifconfig vr0 polling
  There are also various kernel parameters which can be tuned
  in /etc/sysctl.conf,
  particularly kern.ipc.maxsockbuf which should be
  set to a larger value than the default,
  perhaps 16777216. This may either be set directly
  using the sysctl(8) command,
  
[root@router]~# sysctl -w kern.ipc.maxsockbuf=16777216or simply changed in that file and let the startup scripts take care of it.
Building
In many cases it will be sufficient to simply run the provided images. However there is a document that explains how to build our customised BSDRP distribution from source code.

	    
	    
 
	    
	    
	    
            