Interacting with the Batfish service
Python Imports
In your Python program (or shell) you will need to import Pybatfish modules. The most common imports are shown below. Depending your needs, this list may vary.
[1]:
import pandas as pd
from pybatfish.client.session import Session
from pybatfish.datamodel import *
from pybatfish.datamodel.answer import *
from pybatfish.datamodel.flow import *
Sessions
The Batfish service may be running locally on your machine, or on a remote server. The first step to analyzing your configurations is setting up the connection to the Batfish service.
[4]:
bf = Session(host="localhost")
Uploading configurations
Batfish is designed to analyze a series of snapshots of a network.
A network is a logical grouping of devices – it may mean all of the devices in your network, or a subset (e.g., all devices in a single datacenter.)
A snapshot is a state of the network at a given time. A network may contain many snapshots, allowing you to understand the evolution of your network.
Let’s say we will be working with our example datacenter:
[5]:
bf.set_network('example_dc')
[5]:
'example_dc'
Now you are ready to create your first snapshot. Batfish can ingest a variety of data in order to model your network, so let’s look at how you can package it as a snapshot.
Packaging snapshot data
Batfish expects snapshot data to be organized in a specific folder structure.
snapshot [top-level folder]
configs [folder with configurations files of network devices]
router1.cfg
router2.cfg
…
batfish [supplemental information (not device configurations)]
isp_config.json
…
See this snapshot for an example. For illustration, it contains some files that are not used by Batfish, e.g., example-network.png
(network diagrams are not needed). It also contains information for host modeling, which need not be provided if you are not modeling hosts.
When you supply the snapshot as a zipped file, the top-level folder (called “snapshot” above) should be part of the zip archive.
Details on the format of configuration files and supplemental information are described here
Initializing a new snapshot
[6]:
SNAPSHOT_DIR = '../../networks/example'
bf.init_snapshot(SNAPSHOT_DIR, name='snapshot-2020-01-01', overwrite=True)
[6]:
'snapshot-2020-01-01'
Analyzing an existing snapshot
If you would like to analyze a previously-initialized snapshot, you do not need to re-initialize it. Simply set the network and snapshot by name:
[7]:
bf.set_network('example_dc')
bf.set_snapshot('snapshot-2020-01-01')
[7]:
'snapshot-2020-01-01'
Running Questions
After initializing (or setting) a snapshot, you can query the Batfish service to retrieve information about the snapshot.
Batfish exposes a series of questions to users. With the help of these questions you can examine data about you network as a whole, or individual devices, in a vendor-agnostic way.
The general pattern for Batfish questions is:
bf.q.<question_name>()
Creates a question (with parameters, if applicable).bf.q.<question_name>().answer()
sends the question to the Batfish service and returns the answerbf.q.<question_name>().answer().frame()
converts the answer into a Pandas dataframe for easy data manipulation
This pattern is demonstrated via the initIssues
question below.
Initialization issues
While Batfish supports a wide variety of vendors and configuration constructs, it may not fully support your configuration files. We recommend checking the status of the snapshot you just initialized, by runnning bf.q.initIssues
:
[8]:
bf.q.initIssues().answer()
[8]:
Nodes | Source_Lines | Type | Details | Line_Text | Parser_Context | |
---|---|---|---|---|---|---|
0 | ['as1border1'] | None | Convert warning (redflag) | No virtual address set for VRRP on interface: 'GigabitEthernet0/0' | None | None |
Given the answer of a question, you may want to focus on certain rows/columns or ignore certain rows. This is easy via Pandas dataframe manipulation. For instance, if you want to ignore all rows that warn about BGP update source, you may do the following.
[9]:
issues = bf.q.initIssues().answer().frame()
issues[issues['Details'].apply(lambda x: "Could not determine update source for BGP neighbor:" not in x)]
[9]:
Nodes | Source_Lines | Type | Details | Line_Text | Parser_Context | |
---|---|---|---|---|---|---|
0 | ['as1border1'] | None | Convert warning (redflag) | No virtual address set for VRRP on interface: 'GigabitEthernet0/0' | None | None |
Now that you know the basics of interacting with the Batfish service, you can 1) explore a variety of questions that enable you to analyze your network in great detail; and 2) check out code examples for a range of use cases.
Logging
The server-side logs are accessible via Docker. Assuming your container is named “batfish”, run docker logs batfish
to view the logs. See documentation for docker logs command for helpful command line options.
The default client-side logging (by pybatfish) is verbose to inform new users about what is happening. To control logging verbosity, use the following snippet toward the top of your Python script. Replace logging.WARN
with your preferred logging level.
[10]:
import logging
logging.getLogger("pybatfish").setLevel(logging.WARN)