Cape Evans

Last week I was fortunate enough to take a trip out to Cape Evans, the site of Scott’s Hut, where Scott staged for his failed trip to the geographic south pole.

Cape Evans is a few miles north of McMurdo Station. Two drivers were kind enough to volunteer their time to shuttle a small group of us to this historic site. We drove across the ice shelf for about one hour each way, passing beautiful glaciers and dramatic islands on our trip.

The Hut itself has been amazingly well preserved; it is truly taking a walk through history. The expedition’s supplies look undisturbed, you can still see their scientific equipment, bedding, dining table, food, and even their supply of seal blubber they used for fuel remains.

From the Cape their are stunning views of Mount Erebus and nearby glaciers. Near the site there is a hill with a cross commemorating the members of Shackleton’s expedition who did not return.

It was an amazing experience to see such an important place of Antarctic history so well preserved!


Working in Antarctica

I’m starting my dream job – working as a Network Engineer at McMurdo Research Station in Antarctica!

I arrived in Christchurch, New Zealand to receive my cold weather gear and training and was quickly ferried to McMurdo in a C-17 cargo plane which landed on an ice runway a few miles from the main base.

The station is very impressive, it houses over 1000 contractors and scientists in the peak of the summer, who support science across the continent. Its very comfortable here, with modern facilities, hot showers, and great food.

Everyone I have met has been amazing, interesting people from all over the US with different skill sets and backgrounds. Many of them have been working in Antarctica for many seasons.

The environment here is beautiful, the trails on Ross Island offer breathtaking views of the natural beauty of the environment. It is hard to capture in photographs, but I’ve included a few photos from my first few days here.

There is still so much to see and explore, and I’m truly grateful for this amazing experience!

Using Ansbile for Junos Configuration Automation


Managing networking equipment can be difficult. Many organizations have hundreds or even thousands of routers, switches, and firewalls deployed, which can be quite a hassle to manage.

In the past network engineers programmed devices one by one – maybe using manually curated templates to create some level of consistency. But with this model, mistakes are almost inevitable, causing some devices to have slightly different configurations than others.

Modern organizations use configuration management and automation tools such as Ansible, Puppet, and Chef for centralizing their management of their Linux systems infrastructure – isn’t it time these technologies are applied to these organization’s underlying network infrastructure?

Ansible and a Juniper provided Python library, PyEZ are one possible method of bringing this type of automation to the networking world.

Ansible can be used to create Juniper configuration files via Jinja2 templates. Jinja2 is a templating language, which allows the user to create templates which can be populated dynamically with variables defined on a host or group basis.

Using templates, you can ensure all of your equipment has the exact same configuration. This can help reduce downtime due to incorrectly configured equipment, and allows you to know the state of all of your equipment.

These templates are written just like normal Junos code, but with the addition of logic statements (for, while, if, etc) and variables.

Here is a simple example of Jinja2 code, which replaces the system login banner configuration with another that includes the variable {{hostname}}.

system {
 login {
 replace: message "This switch is named {{hostname}}";

Once your templates have been populated, Ansible can call the Juniper PyEZ Library to push these configuration files via NETCONF, a protocol used to “install, manipulate, and delete the configuration of network devices.”

Essentially NETCONF allows a user to program a network device without creating a interactive ssh session.

One of my favorite things about Junos is its “load replace” command – which allows the user to replace parts of the configuration and allowing idempotence, meaning no matter how many times we “load replace” we always end up with the same configuration.

Using Ansible and PyEZ, networking equipment configurations can be automatically generated and deployed centrally for ease of management and ensure an entirely consistent environment!

Getting Started

Great! So how should we get started with Ansible and PyEZ? I would begin by reading the excellent Juniper documentation here.

I’ve created a test environment which you can clone to try it out on my github account here. Keep reading if you’d like to test it out!

First we need to create a Python virtual environment with the following command.

virtualenv --system-site-packages --python /usr/bin/python2.7 ~/venv/ansible

Clone the git repository here into the ~/venv folder, which will pull down my test environment.

Once you have your virtual environment set up, we’ll need to activate it with the following command. You should see the name of the virtual environment appear in front of your bash prompt once you have activated it.

source ~/venv/ansible/bin/activate

Next we need to install the dependencies, using the Python package manager, pip.

pip install -r ~/venv/ansible_junos/requirements.txt

Once we have the dependencies, we can run the actual Ansible playbook.

The example below is a simple playbook with two tasks.

The first task creates folders to store the generated configurations, and then calls a role (a sort of sub playbook) which generates the configuration from the Jinja2 template we saw above.

The second task takes the compiled Jinja2 code, and uses the PyEZ library to actually load the configuration on devices defined in the hostfile via NETCONF.

- name: Prepare Environment
 hosts: all
 connection: local
 gather_facts: no

 - name: Create dir for compiled configurations
 file: path=compiled/{{ inventory_hostname }}/ state=directory
 always_run: yes
 changed_when: False
 register: baseconfdir
 - base
 - name: Create empty diffs folder
 file: path=diffs state=directory
 always_run: yes
 changed_when: False
 - base

- name: push config
 hosts: all
 - Juniper.junos
 - banner
 connection: local
 gather_facts: no

 - name: Load the compiled configuration via "load replace"
 host={{ inventory_hostname }}
 user={{ user }}
 file=compiled/{{ inventory_hostname }}/{{ inventory_hostname }}.conf
 diffs_file=diffs/{{ inventory_hostname }}.diff

The command to run the playbook is inside of the Makefile. The Makefile allows us to store many scripts in one file, calling one or more from a simple command.

 rm -f ./diffs/*; rm -rf ./compiled/*; rm -rf ./logs/*

deploy_compare: clean
 ansible-playbook -i lab.hosts deploy.yml -e user=$(USER) --check

deploy: clean
 ansible-playbook -i lab.hosts deploy.yml -e user=$(USER)

To compile the Jinja2 code and deploy it to the device, we use the “deploy” line of the Makefile like this:

make deploy

The deploy line first calls “clean” which removes all diffs, logs, and compiled configs. Then it calls ansible-playbook to run the deploy.yml playbook shown above, specifying the inventory file and the username to use when logging into the devices.

You’ll need to modify the hostfile with the address of your device, and enable netconf on the device as well before you try this at home.

Thats it! I hope this helps you get started with Ansible and PyEZ!


Junos MPLS L3VPN Lab

peterp lab - L3VPN MPLS Design - New Page

We are running a provider level MPLS network on Juniper gear at my current organization, so to get a better understanding of the ins and outs of MPLS I created a small lab to play with.

I didn’t have any spare MX series routers, so instead I used three physical SRX 240s configured to be packet-based to simulate a router.

The lab design has two Provider Edge routers (R1 and R3)  with two customer VRFs each, and one Core router (R2) to illustrate a BGP free core network.

I used OSPF on the 192.168.x.x networks to learn the 172.16.0.x loopback addresses for MP-BGP. LDP is used on the 192.168.x.x interfaces for label distribution. The customer ranges are in the 10.x.x.x address space.

I very creatively used Route Distinguisher 1 and 2 for customers 1 and 2 respectively.

Check out the above network diagram, the device configurations on github, and the Amazing Juniper Documentation if you’d like to try this at home!

Below are the routing tables on R1, which shows each customers routing table, MPLS labels, and MP-BGP routes.


Aruba Wireless Controller CLI Configuration Made Easy


I’ve been working extensively with Aruba Networks Mobility Controllers at my current job and I’ve put together some quick documentation to go over the basics of the CLI configuration.

While some parts of the Aruba configuration are easily managed from the GUI, I usually find it much easier to work with the Cisco-like CLI.


Parts of the Configuration

The Top of the Hierarchy – AP Groups

AP groups are the configuration that is ultimately assigned to APs. You can see this as the “root” of the configuration, as this section ultimately references many other sections of the configuration.

AP Groups define which SSIDs are broadcast, which channels are used, traffic shaping, HA information, and more. All subsequent configuration is referenced from AP Groups.

Here we see two virtual-aps (SSID Configuration) to broadcast, the radio-profiles (Radio Rates),  ap-system-profiles (HA info), traffic-mgmt-profiles (QOS), and the regulatory-domain-profile (which wireless channels can be used).

ap-group "test_ap_group"                                        
virtual-ap "vap_psktest"
virtual-ap "vap_authtest"
dot11a-radio-profile "test_rf_radio-profile-dot11a"              
dot11g-radio-profile "test_rf_radio-profile-dot11g"
ap-system-profile "test_prof"                                  
dot11a-traffic-mgmt-profile "TrafficShapingFair"                    
dot11g-traffic-mgmt-profile "TrafficShapingFair"
regulatory-domain-profile "test_Reg_Domain-DFS"


Radio Profiles

Radio profiles point to ARM (Adaptive Radio Management) Profiles.

Here we also enable beacon regulation to synchronize the timing of beacon advertisements.

rf dot11a-radio-profile "test_rf_radio-profile-dot11a"
 arm-profile "test_arm-profile-dot11a"


ARM Profiles

ARM (Adaptive Radio Management) Profiles automatically select the best channel and transmission power settings for each AP on your WLAN. Learn more here.

rf arm-profile "test_arm-profile-dot11a"
 max-tx-power 12

AP System Profiles

AP System Profiles are used to create HA controller pairs, defining both “LMS” (local mobility switch) IP address and the password used for syncing them.

It’s important to note there is more to the HA configuration as well.

ap system-profile "test_prof"
 bkup-passwords 1bc9120f3c9f85123123eff2e6794b4590cbdc64717c4e2a3

Traffic Management Profiles

This part of the configuration allows you to define traffic shaping policies.

The “fair-access” shaping policy forces airtime to be shared equally among all clients regardless of their capabilities (b,g,n,ac,etc).

wlan traffic-management-profile "TrafficShapingFair"
 shaping-policy fair-access

Regulatory Domain Profiles

This section sets the radio channels that can be used by clients. The channels that can be used in each country are subject to local law. Here we enable all the US channels.

ap regulatory-domain-profile "test_Reg_Domain-DFS"
 country-code US
 valid-11g-channel 1
 valid-11g-channel 6
 valid-11g-channel 11
 valid-11a-channel 36
 valid-11a-channel 40
 valid-11a-channel 44
 valid-11a-channel 48
 valid-11a-channel 52
 valid-11a-channel 56
 valid-11a-channel 60
 valid-11a-channel 64
 valid-11a-channel 100
 valid-11a-channel 104
 valid-11a-channel 108
 valid-11a-channel 112
 valid-11a-channel 116
 valid-11a-channel 132
 valid-11a-channel 136
 valid-11a-channel 140
 valid-11a-channel 144
 valid-11a-channel 149
 valid-11a-channel 153
 valid-11a-channel 157
 valid-11a-channel 161
 valid-11a-channel 165
 valid-11a-40mhz-channel-pair 36-40
 valid-11a-40mhz-channel-pair 44-48
 valid-11a-40mhz-channel-pair 52-56
 valid-11a-40mhz-channel-pair 60-64
 valid-11a-40mhz-channel-pair 100-104
 valid-11a-40mhz-channel-pair 108-112
 valid-11a-40mhz-channel-pair 132-136
 valid-11a-40mhz-channel-pair 140-144
 valid-11a-40mhz-channel-pair 149-153
 valid-11a-40mhz-channel-pair 157-161
 valid-11a-80mhz-channel-group 36-48
 valid-11a-80mhz-channel-group 52-64
 valid-11a-80mhz-channel-group 100-112
 valid-11a-80mhz-channel-group 132-144
 valid-11a-80mhz-channel-group 149-161

Virtual AP Configuration Examples

Virtual AP Example 1: psktest (Basic WPA2 PSK):

This SSID is a simple WPA2 PSK network, where all users get assigned to the same vlan.

Virtual-AP Configuration

The Virtual-AP contains the configuration for an SSID.

Here we set the aaa-profile (which defines which ACLs get applied), the ssid-profile (ssid name & psk), and vlan assignment.

The broadcast-filter all option drops all multicast and broadcast traffic in the air. Band-steering tries to force clients onto the preferred 5 GHz band, but allows them to connect to 2.4 GHz if unable.

wlan virtual-ap "vap_psktest"
 aaa-profile "default-dot1x-psk"
 ssid-profile "ssid_psktest"
 broadcast-filter all

SSID Profile

Used to define minimum rates, the broadcast SSID, and the PSK.

Here we set the lowest supported rates to 12 mbps, for 5 GHz and 2.4 GHz respectively. This removes support for very old clients (802.11b), which can help improve performance.

wlan ssid-profile "ssid_psktest"
 essid "psktest"
 opmode wpa2-psk-aes
 a-basic-rates 12 18 24
 a-tx-rates 12 18 24 36 48 54
 g-basic-rates 12 18 24
 g-tx-rates 12 18 24 36 48 54
 wpa-passphrase 78a785789845d3d07deed9516c54e5627e237e3cb19335b3604538eecb61102c

AAA Profiles

Here we define the role the user is assigned, which in turn defines the ACLs applied to them.

The defualt-psk authentication mode is built-in to ArubaOS, and it tells the controller to authenticate using the wpa-passphrase assigned above.

aaa profile "default-dot1x-psk"
   initial-role "authenticated"
   authentication-dot1x "default-psk"


The user role defines the ACLs assigned to users on this SSID.

user-role authenticated
 access-list session global-sacl
 access-list session apprf-authenticated-sacl
 access-list session ra-guard
 access-list session allowall

ACLs applied to the Authenticated User Role

The first two ACLs are predefined, and are empty by default.

global-sacl applies to all user roles, and  apprf-authenticated-sacl was created when the new user role was defined.

ra-guard is intended to prevent wireless clients from becoming IPv6 Routers. allowall permits all ipv4 and ipv6 traffic.

ip access-list session global-sacl  
ip access-list session apprf-authenticated-sacl
ip access-list session ra-guard 
 ipv6  user any icmpv6 rtr-adv  deny 
ip access-list session allowall 
  any any any  permit 
  ipv6  any any any  permit

Virtual AP Example 2: authtest – 802.1x authentication via a RADIUS Server

This SSID has a more complex 802.1x configuration.

In the 802.1x authentication process, a RADIUS server is queried and upon successful authentication returns a variable which is used to place users in the correct user-role. In this way you can have different users assigned to different VLANs.

Virtual-AP Configuration

Here we place users in a NULL vlan (666) during the 802.1x authentication process, where they are essentially black holed until authentication completes.

Unlike our last config, this SSID is only broadcast on the “a band” (5 GHz).

wlan virtual-ap "vap_authtest"
 aaa-profile "aaa_authtest"
 ssid-profile "ssid_authtest"
 vlan 666
 allowed-band a
 steering-mode force-5ghz
 broadcast-filter all


SSID Profile

Used to define minimum rates and broadcast SSID, just like our last config.

wlan ssid-profile "ssid_authtest"
 essid "authtest"
 opmode wpa2-aes
 a-basic-rates 12 18 24
 a-tx-rates 12 18 24 36 48 54
 g-basic-rates 12 18 24
 g-tx-rates 12 18 24 36 48 54

AAA Profiles

This time we connect to a RADIUS server to authenticate. The RADIUS server returns an attribute which is used to assign the user to the correct role.

Here we define the RADIUS server groups which we are authenticating against.

aaa profile "aaa_authtest"
authentication-dot1x "dot1x_authtest"
dot1x-server-group "radius"
radius-accounting "radius"

802.1x Settings

Nothing is defined here.

aaa authentication dot1x "dot1x_authtest"

AAA Server Settings

Here we define our RADIUS server’s IP addresses and passwords, and we place them in a server-group with instructions to load balance across them.

aaa server-group "radius"
 auth-server radius1
 auth-server radius2
aaa authentication-server radius "radius1"
 host ""
 key 78b18f4e47e8c113bef38c91231345aff1c7e2cbc6b3958cb
aaa authentication-server radius "radius2"
 host ""
 key 84c519342621c863asdfe451920f9e47bb54aeb89ecf73d4

User-Role Settings

This is the role we will assign the user, based on the attribute received by the RADIUS server (in this case, “systems”).

The role defines the VLAN assignment and the ACLs applied. The same ACLS as above are used.

user-role systems
 access-list session global-sacl
 access-list session apprf-systems-sacl
 access-list session ra-guard
 access-list session allowall



And that’s all there is to it. Hopefully someone will finds this useful when getting started with ArubaOS!

Running BitTorrent on an OpenWRT Router

Over the weekend I decided to set up my OpenWRT router with a BitTorrent client. Thanks to opkg, its really easy to install the Transmission BitTorrent client on your router.


Before you can get transmission running you’ll need to set up a USB drive for storage. Most routers have very little flash storage so you’ll have to add USB storage to store your downloaded content.

Setting up USB support is fairly simple, it just requires a few packages to be installed. Let’s install all the packages we’ll need first.

opkg update
opkg install transmission-web e2fsprogs cfdisk kmod-fs-ext4 kmod-usb-storage block-mount

These utilities enable usb support (kmod-usb-storage), allow mounting external storage (block-mount), partition your usb drive (cfdisk), and create/use the ext4 file system  (e2fsprogs, kmod-fs-ext4).

First plug in your USB drive and create one big Linux partition. I used cfdisk for this; just delete the existing partition (/dev/sda1 on my router) and create a new primary partition. By default it selects the right partition type (Linux).


Next you need to create a file system on the USB drive. mkfs.ext4 will create an ext4 file system on the drive. I mounted the new file system under /mnt.

mkfs.ext4 -F /dev/sda1
mount /dev/sda1 /mnt

Next lets make sure the drive is mounted automatically on boot. We’ll need to make a /etc/config/fstab file for this, and then enable the fstab process on boot. I also made the directories Transmission will use in /mnt.

cat <<EOT >> /etc/config/fstab
config 'mount'
 option 'device' '/dev/sda1'
 option 'options' 'rw,sync'
 option 'enabled_fsck' '0'
 option 'enabled' '1'
 option 'target' '/mnt'

/etc/init.d/fstab enable

mkdir /mnt/downloads
mkdir /mnt/watch

Once we’ve got the drive set up we can start configuring Transmission. We’ll need to create a Transmission config file which downloads torrents to our USB drive and we’ll need to configure Transmission to start automatically on boot.

#Load Transmission Config File

rm -rf /etc/config/transmission

cat <<EOT >> /etc/config/transmission
config transmission
 option enabled 1
 option config_dir '/mnt/transmission'
 #option user 'nobody'
 option alt_speed_down 0
 option alt_speed_enabled false
 option alt_speed_time_begin 540
 option alt_speed_time_day 127
 option alt_speed_time_enabled false
 option alt_speed_time_end 1020
 option alt_speed_up 0
 option bind_address_ipv4 ''
 option bind_address_ipv6 '::'
 option blocklist_enabled false
 option blocklist_url ''
 option cache_size_mb 2
 option dht_enabled true
 option download_dir '/mnt/downloads/'
 option download_queue_enabled true
 option download_queue_size 2
 option encryption 1
 option idle_seeding_limit 0
 option idle_seeding_limit_enabled false
 option incomplete_dir '/mnt/incomplete'
 option incomplete_dir_enabled false
 option lazy_bitfield_enabled true
 option lpd_enabled false
 option message_level 1
 option peer_congestion_algorithm ''
 option peer_limit_global 240
 option peer_limit_per_torrent 60
 option peer_port 33333
 option peer_port_random_high 65535
 option peer_port_random_low 50000
 option peer_port_random_on_start false
 option peer_socket_tos 'default'
 option pex_enabled true
 option port_forwarding_enabled true
 option preallocation 1
 option prefetch_enabled true
 option queue_stalled_enabled true
 option queue_stalled_minutes 30
 option ratio_limit 2.0000
 option ratio_limit_enabled false
 option rename_partial_files true
 option rpc_authentication_required false
 option rpc_bind_address ''
 option rpc_enabled true
 option rpc_password ''
 option rpc_port 9091
 option rpc_url '/transmission/'
 option rpc_username ''
 option rpc_whitelist ',192.168.1.*'
 option rpc_whitelist_enabled true
 option scrape_paused_torrents_enabled true
 option script_torrent_done_enabled false
 option script_torrent_done_filename ''
 option seed_queue_enabled false
 option seed_queue_size 10
 option speed_limit_down 0
 option speed_limit_down_enabled false
 option speed_limit_up 500
 option speed_limit_up_enabled false
 option start_added_torrents true
 option trash_original_torrent_files false
 option umask 18
 option upload_slots_per_torrent 20
 option utp_enabled true
 option scrape_paused_torrents true
 option watch_dir_enabled true
 option watch_dir '/mnt/watch'

#Automatically load transmission on boot

/etc/init.d/transmission enable
/etc/init.d/transmission start

After you’ve set up Transmission you can access it at and start downloading!


Most routers have very limited CPU and Memory resources. I saw not-so-stellar performance when downloading using OpenWRT, but seeding performance was pretty good – I was able to saturate my upload link.

I think this would be a great setup if you’d like to seed files for a long time, or if you’d like to download overnight while your main computer is off to save some electricity. Plus its really cool running BitTorrent directly on your router!

I created a script to set up an OpenWRT router with Transmission, hosted on my github account. It does everything aside from partition the USB drive for you, which you can do with cfdisk. Feel free to check out the script here.

IPv6 Support on Comcast using OpenWrt

I’ve recently moved to an area covered by Comcast’s IPv6 Network, and I was surprised to learn how difficult it was to get my aging router working with Comcast’s IPv6 Implementation.

I had an old Buffalo WZR-HP-G300NH and a newer TP-Link TL-WDR3600 lying around, but I had trouble getting either to pull IPv6 addresses on Comcast with my trusty Mortotola SB6121, though my laptop connected directly worked just fine.

The Buffalo router has an official DD-WRT build for it which ostensibly supports IPv6, and the TP-Link Official documentation also claims IPv6 support although neither worked for me, even with firmware updates.

I’ve loved using DD-WRT in the past, but its countless versions, or “builds” are extremely confusing. This article tries to somewhat clarify their release system. For starters, you have to search their outdated database for which build to use on each router, but look around in the forums and most people agree that these recommendations are typically outdated or wrong. Unlike OpenWRT, there are no “stable releases” so which version to use can be very confusing.

After doing some digging I decided to give OpenWRT a try. OpenWRT is a Linux based firewall distribution, which supports a large quantity of commercial home routers. It’s a full baked Linux distro – offering Web Management Interface, A simple configuration system, and is extremely versatile due to the large amount of packages available via its package manager, opkg. Best of all, it supported IPv6 right out of the box!


I installed the current stable release, Chaos Calmer 15.05, on both routers. The install was easy – The TP-Link was updated directly from the official firmware and I updated my Buffalo from DD-WRT from the command line.

The default LuCi Web interface is simple but intuitive. All the typical configuration options exist, such as port forwarding, static DHCP reservations, and wifi configuration (Hint: wifi is off by default).


Many more settings can be configured via simple configuration files, just enable the ssh server and fire up your editor of choice to make changes to the configuration files under /etc/config.


The real beauty was how easy it was to add functionality in OpenWRT –  I wanted to set up a dynamic DNS agent and enable some statistics collection. No problem – just install a package via opkg and you’ll be set up in minutes.

How about setting up remote access via OpenVPN? Or installing a torrent client so you can download all of your favorite torrents? All this and more is possible via the huge package repository and great documentation.

I came to OpenWRT for the IPv6 support and I’ve really impressed with it so far. Hopefully it will work for you as well!