Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions netdiff/batman.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import json
import networkx
from netdiff.nxparser import Parser


class BatmanParser(Parser):
""" Batman Topology Parser """
def _get_primary(self, mac, collection):
for node in collection:
for interface in node:
if mac == interface:
return node[0]
return 0

def _get_ag_node_list(self, data):
agn = []
for node in data:
agi = []
agi.append(node['primary'])
if('secondary'in node):
for interface in node['secondary']:
agi.append(interface)
agn.append(agi)
return agn

def _parse(self, data):
"""
Converts a topology in a NetworkX MultiGraph object.

:param str topology: The OLSR1 topology to be converted (JSON or dict)
:return: the NetworkX MultiGraph object
"""
# if data is not a python dict it must be a json string
if type(data) is not dict:
data = json.loads(data)
# initialize graph and list of aggregated nodes
graph = networkx.MultiGraph()
agn = self._get_ag_node_list(data['vis'])
# loop over topology section and create networkx graph
for node in data["vis"]:
for neigh in node["neighbors"]:
p_neigh = self._get_primary(neigh['neighbor'], agn)
if not graph.has_edge(node['primary'], p_neigh):
graph.add_edge(node['primary'],
p_neigh,
weight=neigh['metric'])
return graph
52 changes: 52 additions & 0 deletions netdiff/nxparser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import json
import networkx


class Parser(object):
""" Generic Topology Parser """

def __init__(self, old, new):
"""
Initializes a new Parser

:param str old: a JSON or dict representing the old topology
:param str new: a JSON or dict representing the new topology
"""
self.old_graph = self._parse(old)
self.new_graph = self._parse(new)

def diff(self):
"""
Returns netdiff in a python dictionary
"""
return {
"added": self._make_diff(self.new_graph, self.old_graph),
"removed": self._make_diff(self.old_graph, self.new_graph)
}

def diff_json(self, **kwargs):
"""
Returns netdiff in a JSON string
"""
return json.dumps(self.diff(), **kwargs)

# --- private methods --- #

def _make_diff(self, old, new):
"""
calculates differences between topologies 'old' and 'new'
returns a list of links
"""
# make a copy of old topology to avoid tampering with it
diff = old.copy()
not_different = []
# loop over all links
for oedge in old.edges():
# if link is also in new topology add it to the list
for nedge in new.edges():
if ((oedge[0] == nedge[0]) and (oedge[1] == nedge[1])) or ((oedge[1] == nedge[0]) and (oedge[0] == nedge[1])):
not_different.append(oedge)
# keep only differences
diff.remove_edges_from(not_different)
# return list of links
return diff.edges()
49 changes: 2 additions & 47 deletions netdiff/olsr1.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
import json
import networkx
from netdiff.nxparser import Parser


class Olsr1Parser(object):
class Olsr1Parser(Parser):
""" OLSR v1 Topology Parser """

def __init__(self, old, new):
"""
Initializes a new Olsr1Parser

:param str old: a JSON or dict representing the old OLSR1 topology
:param str new: a JSON or dict representing the new OLSR1 topology
"""
self.old_graph = self._parse(old)
self.new_graph = self._parse(new)

def diff(self):
"""
Returns netdiff in a python dictionary
"""
return {
"added": self._make_diff(self.new_graph, self.old_graph),
"removed": self._make_diff(self.old_graph, self.new_graph)
}

def diff_json(self, **kwargs):
"""
Returns netdiff in a JSON string
"""
return json.dumps(self.diff(), **kwargs)

# --- private methods --- #

def _parse(self, topology):
"""
Converts a topology in a NetworkX MultiGraph object.
Expand All @@ -50,21 +23,3 @@ def _parse(self, topology):
link["destinationIP"],
weight=link["tcEdgeCost"])
return graph

def _make_diff(self, old, new):
"""
calculates differences between topologies 'old' and 'new'
returns a list of links
"""
# make a copy of old topology to avoid tampering with it
diff = old.copy()
not_different = []
# loop over all links
for edge in old.edges():
# if link is also in new topology add it to the list
if edge in new.edges():
not_different.append(edge)
# keep only differences
diff.remove_edges_from(not_different)
# return list of links
return diff.edges()
1 change: 1 addition & 0 deletions tests/batman/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .tests import TestBatmanParser
88 changes: 88 additions & 0 deletions tests/batman/batman-1+1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"source_version" : "2014.3.0",
"algorithm" : 4,
"vis" : [
{ "primary" : "a0:f3:c1:96:94:10",
"neighbors" : [
{ "router" : "a0:f3:c1:96:94:10",
"neighbor" : "90:f6:52:f2:8c:2d",
"metric" : "1.000" }
],
"clients" : [
"86:a6:e8:ff:fd:6c",
"64:76:ba:7e:06:44",
"68:72:51:05:79:10",
"86:a6:e8:ff:fd:6c",
"a0:f3:c1:96:94:05"
]
},
{ "primary" : "a0:f3:c1:ac:6c:44",
"neighbors" : [
{ "router" : "a0:f3:c1:ac:6c:44",
"neighbor" : "10:fe:ed:37:3a:39",
"metric" : "1.000" }
],
"clients" : [
"a0:f3:c1:ac:6c:4c",
"dc:9f:db:f1:d7:a9",
"46:1f:b2:8b:c2:a1",
"46:1f:b2:8b:c2:a1"
]
},
{ "primary" : "90:f6:52:f2:8c:2c",
"secondary" : [ "90:f6:52:f2:8c:2b","90:f6:52:f2:8c:2d"
],
"neighbors" : [
{ "router" : "90:f6:52:f2:8c:2c",
"neighbor" : "00:05:1c:06:35:8e",
"metric" : "1.000" },
{ "router" : "90:f6:52:f2:8c:2b",
"neighbor" : "10:fe:ed:37:3a:39",
"metric" : "1.000" },
{ "router" : "90:f6:52:f2:8c:2d",
"neighbor" : "a0:f3:c1:96:94:10",
"metric" : "1.000" }
],
"clients" : [
"ee:74:50:85:fd:67",
"dc:9f:db:f1:d8:aa",
"68:72:51:05:7c:86",
"90:f6:52:f2:8c:2a",
"ee:74:50:85:fd:67",
"24:a4:3c:6d:fd:81"
]
},
{ "primary" : "00:05:1c:06:35:8e",
"neighbors" : [
{ "router" : "00:05:1c:06:35:8e",
"neighbor" : "90:f6:52:f2:8c:2c",
"metric" : "1.000" }
],
"clients" : [
"00:ff:aa:00:00:01",
"00:18:7d:0b:b3:31",
"52:fe:31:1d:aa:4e",
"24:a4:3c:47:53:9a",
"dc:9f:db:0b:af:b9",
"52:fe:31:1d:aa:4e",
"dc:9f:db:f1:d8:a7"
]
},
{ "primary" : "10:fe:ed:37:3a:39",
"neighbors" : [
{ "router" : "10:fe:ed:37:3a:39",
"neighbor" : "90:f6:52:f2:8c:2b",
"metric" : "1.000" },
{ "router" : "10:fe:ed:37:3a:39",
"neighbor" : "a0:f3:c1:ac:6c:44",
"metric" : "1.016" }
],
"clients" : [
"10:fe:ed:37:3a:38",
"24:a4:3c:6d:fd:ce",
"a6:86:18:b1:00:7b",
"a6:86:18:b1:00:7b"
]
}
]
}
89 changes: 89 additions & 0 deletions tests/batman/batman.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"source_version" : "2014.3.0",
"algorithm" : 4,
"vis" : [
{ "primary" : "a0:f3:c1:96:94:06",
"neighbors" : [
{ "router" : "a0:f3:c1:96:94:06",
"neighbor" : "90:f6:52:f2:8c:2d",
"metric" : "1.000" }
],
"clients" : [
"86:a6:e8:ff:fd:6c",
"64:76:ba:7e:06:44",
"68:72:51:05:79:10",
"86:a6:e8:ff:fd:6c",
"a0:f3:c1:96:94:05"
]
},
{ "primary" : "a0:f3:c1:ac:6c:44",
"neighbors" : [
{ "router" : "a0:f3:c1:ac:6c:44",
"neighbor" : "10:fe:ed:37:3a:39",
"metric" : "1.000" }
],
"clients" : [
"a0:f3:c1:ac:6c:4c",
"dc:9f:db:f1:d7:a9",
"46:1f:b2:8b:c2:a1",
"46:1f:b2:8b:c2:a1"
]
},
{ "primary" : "90:f6:52:f2:8c:2c",
"secondary" : [ "90:f6:52:f2:8c:2b","90:f6:52:f2:8c:2d"
],
"neighbors" : [
{ "router" : "90:f6:52:f2:8c:2c",
"neighbor" : "00:05:1c:06:35:8e",
"metric" : "1.000" },
{ "router" : "90:f6:52:f2:8c:2b",
"neighbor" : "10:fe:ed:37:3a:39",
"metric" : "1.000" },
{ "router" : "90:f6:52:f2:8c:2d",
"neighbor" : "a0:f3:c1:96:94:06",
"metric" : "1.000" }
],
"clients" : [
"ee:74:50:85:fd:67",
"dc:9f:db:f1:d8:aa",
"68:72:51:05:7c:86",
"90:f6:52:f2:8c:2a",
"ee:74:50:85:fd:67",
"24:a4:3c:6d:fd:81"
]
},
{ "primary" : "00:05:1c:06:35:8e",
"neighbors" : [
{ "router" : "00:05:1c:06:35:8e",
"neighbor" : "90:f6:52:f2:8c:2c",
"metric" : "1.000" }
],
"clients" : [
"00:ff:aa:00:00:01",
"00:18:7d:0b:b3:31",
"52:fe:31:1d:aa:4e",
"24:a4:3c:47:53:9a",
"dc:9f:db:0b:af:b9",
"52:fe:31:1d:aa:4e",
"dc:9f:db:f1:d8:a7"
]
},
{ "primary" : "10:fe:ed:37:3a:39",
"neighbors" : [
{ "router" : "10:fe:ed:37:3a:39",
"neighbor" : "90:f6:52:f2:8c:2b",
"metric" : "1.000" },
{ "router" : "10:fe:ed:37:3a:39",
"neighbor" : "a0:f3:c1:ac:6c:44",
"metric" : "1.016" }
],
"clients" : [
"10:fe:ed:37:3a:38",
"24:a4:3c:6d:fd:ce",
"a6:86:18:b1:00:7b",
"a6:86:18:b1:00:7b"
]
}
]
}

37 changes: 37 additions & 0 deletions tests/batman/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
import unittest
import json
from netdiff.batman import BatmanParser


__all__ = ['TestBatmanParser']


CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
iulinet = open('{0}/batman.json'.format(CURRENT_DIR)).read()
iulinet2 = open('{0}/batman-1+1.json'.format(CURRENT_DIR)).read()


class TestBatmanParser(unittest.TestCase):

def test_added_removed_1_node(self):
parser = BatmanParser(old=iulinet, new=iulinet2)
result = parser.diff()
self.assertTrue(type(result) is dict)
self.assertTrue(type(result['added']) is list)
self.assertTrue(type(result['removed']) is list)
# ensure there are no differences
self.assertEqual(len(result['added']), 1)
self.assertEqual(len(result['removed']), 1)
self.assertEqual(result['added'][0], ('a0:f3:c1:96:94:10', '90:f6:52:f2:8c:2c'))
self.assertEqual(result['removed'][0], ('a0:f3:c1:96:94:06', '90:f6:52:f2:8c:2c'))

def test_no_changes(self):
parser = BatmanParser(old=iulinet, new=iulinet)
result = parser.diff()
self.assertTrue(type(result) is dict)
self.assertTrue(type(result['added']) is list)
self.assertTrue(type(result['removed']) is list)
# ensure there are no differences
self.assertEqual(len(result['added']), 0)
self.assertEqual(len(result['removed']), 0)