Netdiff is a simple Python library that provides utilities for parsing network topology data of open source dynamic routing protocols and detecting changes in these topologies.
Current features:
- parse different formats
- detect changes in two topologies
- return consistent NetJSON output
- uses the popular networkx library under the hood
Goals:
- provide an abstraction layer to facilitate parsing different network topology formats
- add support for the most popular dynamic open source routing protocols
- facilitate detecting changes in network topology for monitoring purposes
- provide standard NetJSON output
- keep the library small with as few dependencies as possible
Currently used by
Install from pypi:
pip install netdiff
Install tarball:
pip install https://github.com/ninuxorg/netdiff/tarball/master
Alternatively you can install via pip using git:
pip install -e git+git://github.com/ninuxorg/netdiff#egg=netdiff
If you want to contribute, install your cloned fork:
git clone git@github.com:<your_fork>/netdiff.git
cd netdiff
python setup.py develop
Calculate diff of an OLSR 0.6.x topology:
from netdiff import OlsrParser
from netdiff import diff
old = OlsrParser(file='./stored-olsr.json')
new = OlsrParser(url='http://127.0.0.1:9090')
diff(old, new)
In alternative, you may also use the subtraction operator:
from netdiff import OlsrParser
from netdiff import diff
old = OlsrParser(file='./stored-olsr.json')
new = OlsrParser(url='http://127.0.0.1:9090')
old - new
The output will be an ordered dictionary with three keys:
- added
- removed
- changed
Each key will contain a dict compatible with the NetJSON NetworkGraph format representing respectively:
- the nodes and links that have been added to the topology
- the nodes and links that have been removed from the topology
- links that are present in both topologies but their cost changed
If no changes are present, keys will contain None
.
So if between old
and new
there are no changes, the result will be:
{
"added": None
"removed": None,
"changed": None
}
While if there are changes, the result will look like:
{
"added": {
"type": "NetworkGraph",
"protocol": "OLSR",
"version": "0.6.6",
"revision": "5031a799fcbe17f61d57e387bc3806de",
"metric": "ETX",
"nodes": [
{
"id": "10.150.0.7"
},
{
"id": "10.150.0.6"
}
],
"links": [
{
"source": "10.150.0.3",
"target": "10.150.0.7",
"cost": 1.50390625
},
{
"source": "10.150.0.3",
"target": "10.150.0.6",
"cost": 1.0
}
]
},
"removed": {
"type": "NetworkGraph",
"protocol": "OLSR",
"version": "0.6.6",
"revision": "5031a799fcbe17f61d57e387bc3806de",
"metric": "ETX",
"nodes": [
{
"id": "10.150.0.8"
}
],
"links": [
{
"source": "10.150.0.7",
"target": "10.150.0.8",
"cost": 1.0
}
]
},
"changed": {
"type": "NetworkGraph",
"protocol": "OLSR",
"version": "0.6.6",
"revision": "5031a799fcbe17f61d57e387bc3806de",
"metric": "ETX",
"nodes": [],
"links": [
{
"source": "10.150.0.3",
"target": "10.150.0.2",
"cost": 1.0
}
]
}
}
Parsers are classes that extend netdiff.base.BaseParser
and implement a parse
method
which is in charge of converting a python data structure into networkx.Graph
object and return the result.
Parsers also have a json
method which returns valid NetJSON output.
The available parsers are:
netdiff.OlsrParser
: parser for the olsrd jsoninfo plugin or the older txtinfo pluginnetdiff.BatmanParser
: parser for the batman-advanced alfred tool (supports also the legacy txtinfo format inherited from olsrd)netdiff.Bmx6Parser
: parser for the BMX6 b6m toolnetdiff.CnmlParser
: parser for CNML 0.1netdiff.NetJsonParser
: parser for the NetJSON NetworkGraph formatnetdiff.OpenvpnParser
: parser for the OpenVPN status file
Data can be supplied in 3 different ways, in the following order of precedence:
data
:dict
orstr
representing the topology/graphurl
: URL to fetch data fromfile
: file path to retrieve data from
Other available arguments:
- timeout: integer representing timeout in seconds for HTTP or telnet requests, defaults to
None
- verify: boolean indicating to the request library whether to do SSL certificate verification or not
Local file example:
from netdiff import BatmanParser
BatmanParser(file='./my-stored-topology.json')
HTTP example:
from netdiff import NetJsonParser
url = 'https://raw.githubusercontent.com/interop-dev/netjson/master/examples/network-graph.json'
NetJsonParser(url=url)
Telnet example with timeout
:
from netdiff import OlsrParser
OlsrParser(url='telnet://127.0.1', timeout=5)
HTTPS example with self-signed SSL certificate using verify=False
:
from netdiff import NetJsonParser
OlsrParser(url='https://myserver.mydomain.com/topology.json', verify=False)
Netdiff parsers can return a valid NetJSON NetworkGraph
object:
from netdiff import OlsrParser
olsr = OlsrParser(url='telnet://127.0.0.1:9090')
# will return a dict
olsr.json(dict=True)
# will return a JSON formatted string
print(olsr.json(indent=4))
Output:
{
"type": "NetworkGraph",
"protocol": "OLSR",
"version": "0.6.6",
"revision": "5031a799fcbe17f61d57e387bc3806de",
"metric": "ETX",
"nodes": [
{
"id": "10.150.0.3"
},
{
"id": "10.150.0.2"
},
{
"id": "10.150.0.4"
}
],
"links": [
{
"source": "10.150.0.3",
"target": "10.150.0.2",
"cost": 2.4
},
{
"source": "10.150.0.3",
"target": "10.150.0.4",
"cost": 1.0
}
]
}
All the exceptions are subclasses of netdiff.exceptions.NetdiffException
.
netdiff.exceptions.ConversionException
Raised when netdiff can't recognize the format passed to the parser.
Not necessarily an error, should be caught and managed in order to support additional formats.
The data which was retrieved from network/storage can be accessed via the "data" attribute, eg:
def to_python(self, data):
try:
return super(OlsrParser, self).to_python(data)
except ConversionException as e:
return self._txtinfo_to_jsoninfo(e.data)
netdiff.exceptions.ParserError
Raised when the format is recognized but the data is invalid.
netdiff.exceptions.NetJsonError
Raised when the json
method of netdiff.parsers.BaseParser
does not have enough data
to be compliant with the NetJSON NetworkGraph format specification.
netdiff.exceptions.TopologyRetrievalError
Raised when it is not possible to retrieve the topology data (eg: the URL might be temporary unreachable).
If you get a similar error when performing a request to the jsoninfo plugin of olsrd (version 0.6 to 0.9) chances are high that http headers are disabled.
To fix it turn on http headers in your olsrd configuration file, eg:
LoadPlugin "olsrd_jsoninfo.so.0.0" { PlParam "httpheaders" "yes" # add this line PlParam "Port" "9090" PlParam "accept" "0.0.0.0" }
Install your forked repo:
git clone git://github.com/<your_fork>/netdiff
cd netdiff/
python setup.py develop
Install test requirements:
pip install -r requirements-test.txt
Run tests with:
./runtests.py
Alternatively, you can use the nose
command (which has a ton of available options):
nosetests
nosetests tests.test_olsr # run only olsr related tests
nosetests tests/test_olsr.py # variant form of the previous command
nosetests tests.test_olsr:TestOlsrParser # variant form of the previous command
nosetests tests.test_olsr:TestOlsrParser.test_parse # run specific test
See test coverage with:
coverage run --source=netdiff runtests.py && coverage report
- Join the ninux-dev mailing list
- Fork this repo and install it
- Follow PEP8, Style Guide for Python Code
- Write code
- Write tests for your code
- Ensure all tests pass
- Ensure test coverage is not under 90%
- Document your changes
- Send pull request