{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to Forwarding Change Validation\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Network engineers frequently have to make changes to network that can impact forwarding behavior: add new routes, open or close flows, route traffic through different devices, etc. These changes are often hard to get right and hard to validate. \n", "\n", "This notebook will show how Batfish can help validate changes to network forwarding _before_ you deploy them. We will do this using Batfish's *reachability* and *differentialReachability* questions that can provide guarantees that our changes are correct and have no unintended side-effects. As we will see, these anaylses are a powerful way to understand, test, and validate changes to the network. \n", "\n", "Check out a video demo of this notebook [here](https://youtu.be/Yje70Q8R79w).\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Import packages\n", "%run startup.py\n", "bf = Session(host=\"localhost\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this notebook we will use the network shown in the diagram below. You can view and download the device configuration files [here](https://github.com/batfish/pybatfish/tree/master/jupyter_notebooks/networks/forwarding-change-validation/base).\n", "\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Change Scenario 1: Costing out a core router\n", "\n", "The network is overprovisioned with failover redundancy for the core routers. All traffic is normally routed through `core1` but will automatically switch to `core2` in case of a failure or during maintenance. In this scenario, we want to service `core1` and thus want to shift traffic to `core2`. We'll implement a change to cost out `core1`, and verify that it does not affect end-to-end reachability. In general, we care about three classes of end-to-end traffic: external-to-host, host-to-external, and host-to-host. For simplicity, we focus on the external-to-host traffic in this notebook but similar queries can cover other classes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 1: Test current behavior\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before beginning, let's check that the network is working as expected (i.e., routing through `core1`). First we load our snapshot into Batfish." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'base'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "NETWORK_NAME = \"forwarding-change-validation\"\n", "BASE_NAME = \"base\"\n", "BASE_PATH = \"networks/forwarding-change-validation/base\"\n", "\n", "bf.set_network(NETWORK_NAME)\n", "bf.init_snapshot(BASE_PATH, name=BASE_NAME, overwrite=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Batfish will automatically compute the RIBs and FIBs from the configuration files in the snapshot, allowing us to test the forwarding behavior offline. Let's do that now, by using the `traceroute` question to see how external-to-host traffic is routed. The parameter `startLocation=\"@enter(/border/[GigabitEthernet0/0])\"` says to start the trace entering the external border router interfaces. The parameter `dstIps=\"/host/)\"` indicates that the flow should be addressed to one of the internal hosts. These two parameters are using [specifier grammar](https://github.com/batfish/batfish/blob/master/questions/Parameters.md)." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|---|---|---|
| 0 | \n", "Start Location: border1 interface=GigabitEthernet0/0 Src IP: 10.12.11.1 Src Port: 49152 Dst IP: 2.128.0.1 Dst Port: 33434 IP Protocol: UDP | \n",
" ACCEPTED 1. node: border1 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet1/0 with resolved next-hop IP: 2.12.11.2, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet1/0) 2. node: core1 RECEIVED(GigabitEthernet0/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0, Routes: [connected (Network: 2.128.0.0/30, Next Hop: interface GigabitEthernet2/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet2/0) 5. node: host-db RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "
| 1 | \n", "Start Location: border2 interface=GigabitEthernet0/0 Src IP: 10.23.21.1 Src Port: 49152 Dst IP: 2.128.0.1 Dst Port: 33434 IP Protocol: UDP | \n",
" ACCEPTED 1. node: border2 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.12.21.2, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 2. node: core1 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0, Routes: [connected (Network: 2.128.0.0/30, Next Hop: interface GigabitEthernet2/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet2/0) 5. node: host-db RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|
| \n", " | Flow | \n", "Snapshot_Traces | \n", "Snapshot_TraceCount | \n", "Reference_Traces | \n", "Reference_TraceCount | \n", "
|---|---|---|---|---|---|
| 0 | \n", "Start Location: border1 interface=GigabitEthernet0/0 Src IP: 10.12.11.1 Src Port: 49152 Dst IP: 2.128.1.1 Dst Port: 33434 IP Protocol: UDP | \n",
" NULL_ROUTED 1. node: border1 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.12.12.2, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 2. node: core2 RECEIVED(GigabitEthernet1/0) NULL_ROUTED(Discarded, Routes: [static (Network: 2.128.1.1/32, Next Hop: discard)]) | \n",
" 1 | \n", "ACCEPTED 1. node: border1 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet1/0 with resolved next-hop IP: 2.12.11.2, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet1/0) 2. node: core1 RECEIVED(GigabitEthernet0/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet3/0, Routes: [connected (Network: 2.128.1.0/30, Next Hop: interface GigabitEthernet3/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet3/0) 5. node: host-www RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "
| 1 | \n", "Start Location: border2 interface=GigabitEthernet0/0 Src IP: 10.23.21.1 Src Port: 49152 Dst IP: 2.128.1.1 Dst Port: 33434 IP Protocol: UDP | \n",
" NULL_ROUTED 1. node: border2 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet1/0 with resolved next-hop IP: 2.12.22.2, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet1/0) 2. node: core2 RECEIVED(GigabitEthernet0/0) NULL_ROUTED(Discarded, Routes: [static (Network: 2.128.1.1/32, Next Hop: discard)]) | \n",
" 1 | \n", "ACCEPTED 1. node: border2 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.12.21.2, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 2. node: core1 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet3/0, Routes: [connected (Network: 2.128.1.0/30, Next Hop: interface GigabitEthernet3/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet3/0) 5. node: host-www RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|
| \n", " | Flow | \n", "Snapshot_Traces | \n", "Snapshot_TraceCount | \n", "Reference_Traces | \n", "Reference_TraceCount | \n", "
|---|
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|---|---|---|
| 0 | \n", "Start Location: border1 interface=GigabitEthernet0/0 Src IP: 10.12.11.1 Src Port: 49152 Dst IP: 2.128.1.1 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" DENIED_IN 1. node: border1 RECEIVED(GigabitEthernet0/0) DENIED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) | \n",
" 1 | \n", "
| 1 | \n", "Start Location: border2 interface=GigabitEthernet0/0 Src IP: 10.23.21.1 Src Port: 49152 Dst IP: 2.128.1.1 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" DENIED_IN 1. node: border2 RECEIVED(GigabitEthernet0/0) DENIED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) | \n",
" 1 | \n", "
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|---|---|---|
| 0 | \n", "Start Location: border1 interface=GigabitEthernet0/0 Src IP: 10.12.11.1 Src Port: 49152 Dst IP: 2.128.1.1 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" ACCEPTED 1. node: border1 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet1/0 with resolved next-hop IP: 2.12.11.2, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet1/0) 2. node: core1 RECEIVED(GigabitEthernet0/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet3/0, Routes: [connected (Network: 2.128.1.0/30, Next Hop: interface GigabitEthernet3/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet3/0) 5. node: host-www RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "
| 1 | \n", "Start Location: border2 interface=GigabitEthernet0/0 Src IP: 10.23.21.1 Src Port: 49152 Dst IP: 2.128.1.1 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" ACCEPTED 1. node: border2 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.12.21.2, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 2. node: core1 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.1.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet3/0, Routes: [connected (Network: 2.128.1.0/30, Next Hop: interface GigabitEthernet3/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet3/0) 5. node: host-www RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|
| \n", " | Flow | \n", "Snapshot_Traces | \n", "Snapshot_TraceCount | \n", "Reference_Traces | \n", "Reference_TraceCount | \n", "
|---|---|---|---|---|---|
| 0 | \n", "Start Location: border1 interface=GigabitEthernet0/0 Src IP: 10.12.11.1 Src Port: 49152 Dst IP: 2.128.0.1 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" ACCEPTED 1. node: border1 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet1/0 with resolved next-hop IP: 2.12.11.2, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet1/0) 2. node: core1 RECEIVED(GigabitEthernet0/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0, Routes: [connected (Network: 2.128.0.0/30, Next Hop: interface GigabitEthernet2/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet2/0) 5. node: host-db RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "DENIED_IN 1. node: border1 RECEIVED(GigabitEthernet0/0) DENIED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) | \n",
" 1 | \n", "
| 1 | \n", "Start Location: border2 interface=GigabitEthernet0/0 Src IP: 10.23.21.1 Src Port: 49152 Dst IP: 2.128.0.1 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" ACCEPTED 1. node: border2 RECEIVED(GigabitEthernet0/0) PERMITTED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.12.21.2, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 2. node: core1 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet3/0 with resolved next-hop IP: 2.23.12.3, Routes: [ibgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet3/0) 3. node: spine2 RECEIVED(GigabitEthernet1/0) FORWARDED(Forwarded out interface: GigabitEthernet2/0 with resolved next-hop IP: 2.34.201.4, Routes: [bgp (Network: 2.128.0.0/30, Next Hop: ip 2.34.201.4)]) TRANSMITTED(GigabitEthernet2/0) 4. node: leaf1 RECEIVED(GigabitEthernet1/0) PERMITTED(RESTRICT_NETWORK_TRAFFIC_IN (INGRESS_FILTER)) FORWARDED(Forwarded out interface: GigabitEthernet2/0, Routes: [connected (Network: 2.128.0.0/30, Next Hop: interface GigabitEthernet2/0)]) PERMITTED(RESTRICT_HOST_TRAFFIC_OUT (EGRESS_FILTER)) TRANSMITTED(GigabitEthernet2/0) 5. node: host-db RECEIVED(eth0) ACCEPTED(eth0) | \n",
" 1 | \n", "DENIED_IN 1. node: border2 RECEIVED(GigabitEthernet0/0) DENIED(OUTSIDE_TO_INSIDE (INGRESS_FILTER)) | \n",
" 1 | \n", "
| \n", " | Flow | \n", "Traces | \n", "TraceCount | \n", "
|---|
| \n", " | Flow | \n", "Snapshot_Traces | \n", "Snapshot_TraceCount | \n", "Reference_Traces | \n", "Reference_TraceCount | \n", "
|---|