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 answer

  • bf.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)