Archive

Category Archives for "Packetswitch"

Source Specific Multicast (SSM) VII

Source Specific Multicast (SSM) VII

In this post, we will look at Source Specific Multicast, or SSM. This is a different approach to multicast that simplifies the overall architecture by removing the need for an RP entirely.

In the previous posts, we covered PIM Sparse Mode, where receivers join a shared tree rooted at the RP and then optionally switch to the shortest path tree toward the source. We also looked at Auto-RP and BSR, which solve the problem of dynamically distributing RP information to all routers. SSM takes a different approach by eliminating the shared tree concept altogether.

Multicast PIM Sparse Mode
Sparse Mode only sends traffic to parts of the network that explicitly request it. Routers with interested receivers send Join messages toward

Any Source Multicast (ASM)

Before we look at SSM, let's briefly talk about Any Source Multicast, or ASM. This is the traditional multicast model we have been using throughout this series.

With ASM, receivers join a multicast group without specifying a source. They simply say 'I want traffic for group 239.1.1.1' and the network figures out how to deliver traffic from any source sending to that group. This is why it is called Any Source Multicast.

Continue reading

Python Pre and Post-Change Validation

Python Pre and Post-Change Validation

If you have made a change on a network device, you have probably done the pre and post check dance at some point. You SSH into the device, run a few show commands, save the output somewhere, apply the change, then run the same commands again and compare the two by eye. It works, but it is slow and easy to get wrong. I have missed things this way, and I know most of you have too.

Once you get comfortable with Python, this is one of the first tasks you will want to automate. Instead of copy-pasting output into a text file and squinting at it, you can pull the data with a script, save it to a JSON file, and then run another script that tells you exactly what changed.

In this chapter, we will build a small pre and post check for BGP. I will show you how to grab BGP neighbor state from a device using NAPALM, save it to a JSON file as the pre snapshot, and then do the same again after the change to get the post snapshot. Once we have both, we will compare them with a library called deepdiff, which Continue reading

Python Working with Structured Data Files

Python Working with Structured Data Files

In the previous sections, we looked at reading and writing plain text files. That was a good starting point, and plain text is still the right choice for things like config backups or log files. But most of the data you deal with in network automation is not plain text, it has structure. A list of devices with their IPs, usernames, and roles. A dictionary of device facts. A nested set of configuration values with groups and per-device overrides.

When your data has structure, you need a format that can represent that structure in a way both humans and computers can understand. This is where structured data files can help. The three main formats you will run into as a network engineer are CSV, JSON, and YAML.

CSV Files

CSV stands for Comma-Separated Values. A CSV file is just a plain text file where each line is a row, and each value in the row is separated by a comma. The first row usually contains column headers.

Here is what a CSV file looks like, saved as devices.csv.

hostname,ip,vendor,role
r1,192.168.202.101,cisco,edge
r2,192.168.202.102,juniper,core
r3,192.168.202.103,arista,edge

If you have ever exported data Continue reading

Python Working With NAPALM

Python Working With NAPALM

At the end of the last part, we looked at the multi-vendor problem. Every time you support a new vendor with Netmiko, you have to remember its command syntax, keep track of the differences, and add more branching logic to your scripts. It works, but it gets messy fast.

NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) is a Python library that solves exactly this problem. Instead of sending vendor-specific commands and dealing with the differences yourself, you use NAPALM's standard set of methods, and NAPALM figures out what to do for each platform behind the scenes. Ask NAPALM to get_config(), and it will send the right command to a Cisco IOS device, the right command to a Juniper device, and the right command to an Arista device, all through the same Python method call.

NAPALM currently supports Cisco IOS, Cisco IOS-XR, Cisco NX-OS, Arista EOS, Juniper Junos, and a few others. It is not as broad as Netmiko in terms of vendor coverage, but for the vendors it does support, the abstraction it provides is well worth it.

There is one more thing worth understanding upfront. NAPALM is not a replacement for Netmiko, it actually uses Continue reading

Python Working with Files

Python Working with Files

Almost every Python script eventually needs to read from or write to a file. You might want to save the output of a command for later, back up device configs to disk, load a list of devices from a text file instead of hardcoding them, or write a log of what your script did. Python makes all of this straightforward once you know how it works.

In this part, we will start with reading text files, cover the proper way to open files using context managers, and then move on to writing and appending. Once we have the basics down, we will build a small config backup script that connects to devices, pulls the running config, and saves each one to its own file on disk.

Reading a Text File

To read a file in Python, you use the built-in open() function. It takes the path to the file as the first argument and returns a file object that you can read from.

Let's say you have a file called devices.txt in the same folder as your script, with the following contents.

192.168.202.101
192.168.202.102
192.168.202.103

Here is the most basic Continue reading

Python Parsing Command Output with TextFSM

Python Parsing Command Output with TextFSM

So far, whenever we have run a command with Netmiko, the output has come back as one big string. That is fine when you just want to print it or eyeball it, but the moment you want to actually do something with the output, filter interfaces that are down, count the number of routes in the table, extract the software version from a show version, you hit a wall. Raw text is hard to work with.

You could split it, use string methods, write clever slicing logic, or reach for regular expressions. Some people do this including myself, and it works, but it is not ideal. The moment the output format changes even slightly, your parsing breaks. And every command needs its own custom parsing code, which quickly becomes a maintenance nightmare.

This is where TextFSM comes in. It is a small library that turns messy device output into clean, structured data, usually a list of dictionaries. Instead of one big blob of text, you get proper Python objects you can loop through, filter, and index. And you do not have to write the parsing logic yourself, because there is a huge community-maintained library of ready-made templates called ntc-templates Continue reading

Python Managing Credentials and Secrets

Python Managing Credentials and Secrets

If you look back at every Netmiko script we have written in this series, you will notice something (very ) uncomfortable, the username and password are sitting right there in the script as plain text. That has been fine for learning, but it is not something you want to do in real scripts.

In this part, we will look at safer ways to manage credentials in your scripts. We will cover a few different approaches, from the simplest (asking the user to type the password when the script runs) to the more common patterns used in real projects (environment variables and .env files). We will also touch on .gitignore

There is no single "correct" way to manage credentials. Different projects and different environments call for different approaches. What matters is that you understand the trade-offs and stop hardcoding passwords into your scripts.

The Problem with Plain Text Credentials

Let's start by being clear about why this matters. Take a look at a script you have written in the last couple of chapters.

device = {
    "device_type": "cisco_ios",
    "host": "192.168.202.101",
    "username": "admin",
    "password": "admin"
}

This looks harmless on your own machine, but think about everything that could Continue reading

Rebuilding My Proxmox Cluster for the Version 9 Upgrade

Rebuilding My Proxmox Cluster for the Version 9 Upgrade

I've been running Proxmox for maybe two years now, and I'd consider myself somewhat of a beginner. I set it up once using Proxmox version 8.x alongside Proxmox Backup Server and pretty much forgot about it. I can spin up new VMs and CTs, or remove existing ones, and that's about it. Fast forward to mid-2026, Proxmox released version 9, and I'd been meaning to upgrade. I went through a few guides and forum posts, and people tended to recommend backing up the VMs and CTs using PBS, then reinstalling Proxmox with the new version and restoring from backup.

TL;DR

I upgraded my Proxmox setup from version 8.x to 9 without doing an in-place upgrade. Instead, I used a spare node already on version 9 as a temporary home and rebuilt the other two nodes one at a time. The idea was to back up everything with PBS, restore onto the spare, then wipe and fresh install version 9 on each node before joining them into a new three-node cluster. Once the cluster was sorted, I also rebuilt pbs-01 to version 4 and cleaned up the old backups. The whole thing was seamless, I didn't lose anything, and Continue reading

Python – Working With Netmiko

Python - Working With Netmiko

In the last part, we got Netmiko up and running, connected to a device, ran a show command, and printed the output. That is enough to write some genuinely useful scripts, but Netmiko can do a lot more than just run a single command.

In this part, we will look at what else Netmiko has to offer. We will cover how to run multiple commands, push configuration changes, load config from a file, save the running config, and use enable mode when the device requires it. We will also look at how to parse command output into structured data instead of raw text, which is a huge time-saver when you are trying to actually use the output for something.

By the end of the chapter, you will have a much better feel for what Netmiko can do, and you will be ready to start writing scripts that actually make changes to your network instead of just reading from it. For the examples in this chapter, I will be using three real Cisco IOS devices in my lab.

devices = [
    {
        "device_type": "cisco_ios",
        "host": "192.168.202.101",
        "username": "admin",
        "password": "admin"
    },
    {
        "device_type": "cisco_ios",
        "host": "192.168.202. Continue reading

Automating Palo Alto HA Firewall Upgrades with Ansible

Automating Palo Alto HA Firewall Upgrades with Ansible

In this blog post, we will cover upgrading Palo Alto firewalls in HA using Ansible. This only covers upgrading minor versions, so it won't work if you are going from 10.x to 11.x, for example. This also only supports an HA pair.

This playbook is based on the repo from Palo Alto itself. There are many playbooks there covering scenarios like upgrading the major version, upgrading the content, and so on, but we will only focus on one specific playbook for HA, which I tweaked a little bit to suit my own setup.

Manual Upgrade Process

Of course, this post assumes you already know how to upgrade the firewalls manually. In case you don't, here are the steps. Palo Alto also recommends upgrading the active unit first and then the passive. You download the image to the active unit and tick the box to sync it to the peer, then suspend the active unit to trigger a failover so the passive takes over. Install the image on the suspended unit, reboot it, and wait for it to come back online so the HA pair syncs again. Once it is back, suspend the current active unit (the original passive) Continue reading

Automatic SSL with Caddy, Cloudflare and Let’s Encrypt

Automatic SSL with Caddy, Cloudflare and Let's Encrypt

I run a lot of applications and services in my homelab, and they usually look something like http://10.10.10.10:8000, http://10.10.10.11:8006, and so on. It works, but it comes with a few annoyances. Browsers constantly complain you about insecure connections, and remembering which IP and port maps to which service gets old fast.

The ideal setup is something like https://netbox-lab.yourdomain.com - a proper domain name with a valid SSL certificate and no port numbers to remember. In this post, I'll show you how to get there using Caddy, Cloudflare, and Let's Encrypt with very minimal effort.

Overview

To make this work, we need the following.

  • A Cloudflare account with a domain (You don't necessarily need Cloudflare. Other DNS providers should work the same way, but this post uses Cloudflare as the example.)
  • An LXC or VM to run Caddy
  • A Cloudflare API token with DNS edit permissions
  • Let's Encrypt Certificates are automatically managed by Caddy

Cloudflare Setup

I already have a domain that I use in my homelab, so I name my services like app.yourdomain.com. I purchased this domain through Cloudflare and manage it there.

To generate an API Continue reading

Using NetBox as a Dynamic Inventory Source for Nornir

Using NetBox as a Dynamic Inventory Source for Nornir

If you have used Nornir before, you already know that the most common way to define your inventory is through YAML files. You list your hosts, groups, and defaults in separate files, and Nornir reads them at runtime. This works fine for small labs or quick scripts, but as your network grows, maintaining those files by hand becomes a problem. Every time you add a device, change an IP, or update a site, you have to remember to update your inventory files as well. It is easy to get out of sync.

This is where a source of truth tool like NetBox can help. NetBox is an open source network source of truth. It is a place to document your devices, IP addresses, sites, roles and pretty much anything about your network. Instead of maintaining a separate YAML inventory alongside NetBox, you can pull your inventory directly from NetBox at runtime. That way, Nornir always works with up to date data, and you only have to manage one source of truth.

In this post, we will cover how to use NetBox as a dynamic inventory source for Nornir using the nornir_netbox plugin. If you are new to Nornir, we have Continue reading

Pytest for Automated Network Testing (II)

Pytest for Automated Network Testing (II)

In part one, we covered the basics of pytest and wrote our first network tests. We tested BGP and OSPF on a single device, then extended it to multiple devices. We also looked at parametrization and how it helps treat each device and each neighbour as an independent test.

In this part, we will cover inventory management with Nornir and pytest fixtures.

Pytest for Automated Network Testing
Pytest gives you full control. You write the test, you decide exactly what to check, and you get a clear pass or fail result. You can test one device
Pytest for Automated Network Testing (II)

Nornir Introduction

Nornir is a Python automation framework designed for network engineers. Instead of writing your own logic to connect to devices, manage inventory, and run tasks in parallel, Nornir handles all of that for you. We have a dedicated series on Nornir, which you can check out here, so we are not going to do a deep dive in this post.

The reason we are using Nornir here is for inventory and task management. Instead of hardcoding a list of IP addresses in our collection file, we define our devices in a hosts file with groups, credentials, and Continue reading

Simple Wireguard VPN Setup with wg-easy

Simple Wireguard VPN Setup with wg-easy

WireGuard is a modern VPN protocol that is fast, lightweight, and much simpler to set up compared to other options like OpenVPN. It runs in the Linux kernel, uses modern cryptography, and the configuration is just a few lines, which makes it a great choice for personal use.

The problem is, even though WireGuard itself is simple, managing peers can get tedious. You have to generate key pairs, edit config files, hand out configs to each device, and keep track of who has access to what. If you have a few family members or friends who want to use your VPN, this quickly becomes a hassle.

This is where wg-easy can help. It is a simple open-source web UI that sits on top of WireGuard and takes care of all the boring bits for you. You can add or remove clients with a single click, generate QR codes for mobile devices, and see who is connected, all from a clean web interface.

In this post, I will walk you through how to set up wg-easy so you can have your own self-hosted VPN running in just a few minutes.

Lab Topology

Before we get into the setup, let me quickly Continue reading

I Vibe-Coded My CV Into a CLI

I Vibe-Coded My CV Into a CLI

UPDATE - Since publishing this post, I have also added a Palo Alto style CV to the site. I will update the post with more details on that later.

If you do not have the patience to read the rest of this post, here is the site. Type enable and then run any of the usual commands like show version, show ip interface brief, or show ip route to browse through the CV. It is still early days, but I am hoping to make some improvements over time. If you like it, give me a clap on the right.

I Vibe-Coded My CV Into a CLI
cv cli

Overview

I have been thinking about doing this for a long time, but I always assumed it would be a difficult task. I was wrong. I think I had it up and running in about an hour. The idea is that a site that looks and feels like a CLI, where you can run the usual show commands and get output, except the output is my CV.

I have no web development experience, so I used Claude for the entire thing. I started by giving Claude a prompt explaining what I wanted, and asked it to generate Continue reading

Pytest for Automated Network Testing (I)

Pytest for Automated Network Testing (I)

Pytest is a Python testing framework. It is primarily used by developers to test their code and make sure it behaves as expected. For example, if you write a function that adds two numbers, you can write a test to verify that the function returns the correct result. If it does, the test passes. If not, the test fails, and pytest tells you exactly where things went wrong.

That is the traditional use case, but pytest is not limited to testing code. You can use it to test anything that can be scripted in Python, and that includes testing your network.

In this series, we will use pytest to write tests that connect to network devices and verify their state. For example, we can write a test that connects to a router and checks whether BGP is up. If BGP is up, the test passes. If not, the test fails. We can also check things like interface states, routing table entries, OSPF neighbours, or really anything else you can pull from a device.

💡
Pytest is not the only testing framework available in Python. unittest is another popular option and is actually built into the Python standard library, so you Continue reading

Multicast PIM Bootstrap Router (BSR) (VI)

Multicast PIM Bootstrap Router (BSR) (VI)

We are at the tail end of our multicast series. So far, we have covered multicast basics, IGMP, PIM Dense Mode, PIM Sparse Mode, and Auto-RP. In this post, we will look at Bootstrap Router, or BSR.

Multicast PIM Auto RP
AutoRP solves this problem by allowing routers to dynamically learn the RP address. Instead of manually configuring the RP on each router
Multicast PIM Bootstrap Router (BSR) (VI)

Bootstrap Router (BSR) Overview

In the previous post, we looked at Auto-RP, which is Cisco's proprietary method for dynamically distributing RP information to all routers in the network. BSR solves the same problem but is defined in the PIM standards (RFC 5059), making it vendor-neutral and interoperable across different platforms. The core idea is the same. Instead of manually configuring the RP address on every router, BSR allows routers to learn RP information automatically. A router called the Bootstrap Router collects RP information from Candidate RPs and distributes it to all PIM routers in the network.

The key difference is in how this information flows. With Auto-RP, the Mapping Agent sends RP mappings to the specific multicast group 224.0.1.40. This creates the chicken-and-egg problem we discussed in the previous post Continue reading

UniFi UTR Initial Impressions, Setup and Review

UniFi UTR Initial Impressions, Setup and Review

Even though UniFi released the UTR (UniFi Travel Router) a while back, I've been researching it and trying to find a use case for myself. Fast forward to today, and even though I still don't have a clear use case for it, I bought it purely based on vibes.

It was out of stock pretty much all the time in the UK store, and even when it came back in stock, it would sell out within minutes. I happened to be checking their site one day and noticed it was available, so I ordered it right away. It costs £90 including delivery.

UniFi UTR Initial Impressions, Setup and Review
utr arrived

So, what is it?

The UTR is a small (like very tiny), portable router that you can take anywhere with you. It fits in your pocket. It supports both 2.4GHz and 5GHz bands and can connect to an upstream network via Wi-Fi or Ethernet. If you are into the UniFi ecosystem, in a nutshell, it can extend your home network wherever you go.

It is a small device, measuring 95.95 x 65 x 12.5 mm and weighing just 89g, so it genuinely fits in your pocket. It runs WiFi 5 with 2x2 MIMO Continue reading

Multicast PIM Auto RP (V)

Multicast PIM Auto RP (V)

In the previous posts in this series, we covered the basics of multicast, IGMP, PIM Dense Mode, and PIM Sparse Mode. In the Sparse Mode post, we manually configured the RP address on every router in the network. This works fine in a small lab, but in a larger network with many routers, it becomes difficult to manage. If the RP changes, you have to update the configuration on every single router.

Multicast PIM Sparse Mode
Sparse Mode only sends traffic to parts of the network that explicitly request it. Routers with interested receivers send Join messages toward
Multicast PIM Auto RP (V)

AutoRP solves this problem by allowing routers to dynamically learn the RP address. Instead of manually configuring the RP on each router, you configure one or more routers to announce themselves as Candidate RPs. A separate router (or the same as the Candidate RP router) called the Mapping Agent collects these announcements and distributes the RP information to all other routers in the network. This makes RP management much easier and also provides a way to implement RP redundancy.

There are two methods to dynamically learn the RP address, which are Auto-RP and Bootstrap Router (BSR). In this Continue reading

Multicast PIM Sparse Mode (IV)

Multicast PIM Sparse Mode (IV)

In the previous post, we covered PIM Dense Mode and mentioned that it is not widely used in production because of its flood and prune behaviour. Every router in the network receives the multicast traffic first, and then routers without interested receivers have to send prune messages. This is inefficient, especially in large networks.

Multicast PIM Dense Mode
PIM Dense mode assumes that every subnet in the network has interested receivers, so it floods multicast traffic everywhere first. Routers that
Multicast PIM Sparse Mode (IV)

In this post, we will look at PIM Sparse Mode, which takes the opposite approach. Instead of flooding traffic everywhere and pruning where it is not needed, Sparse Mode only sends traffic to parts of the network that explicitly request it. Routers with interested receivers send Join messages and only then does the multicast traffic start flowing. This makes Sparse Mode much more efficient and scalable, which is why it is the preferred mode in most production networks today.

PIM Spare Mode Overview

In Dense Mode, we saw two main problems. Multicast traffic is flooded everywhere, and every router has to maintain state for every multicast group, even if all its interfaces are pruned. Sparse Mode Continue reading