Example #1
0
def main(params):
    os.makedirs(params['dest_dir'], exist_ok=True)

    nodes_fn = os.path.join(params['dest_dir'], 'nodes.json')
    graph_fn = os.path.join(params['dest_dir'], 'graph.json')
    nodelist_fn = os.path.join(params['dest_dir'], 'nodelist.json')

    now = datetime.utcnow().replace(microsecond=0)

    # parse mesh param and instantiate Alfred/Batman instances
    alfred_instances = []
    batman_instances = []
    for value in params['mesh']:
        # (1) only batman-adv if, no alfred sock
        if ':' not in value:
            if len(params['mesh']) > 1:
                raise ValueError(
                    'Multiple mesh interfaces require the use of '
                    'alfred socket paths.')
            alfred_instances.append(Alfred(unix_sockpath=None))
            batman_instances.append(Batman(mesh_interface=value))
        else:
            # (2) batman-adv if + alfred socket
            try:
                batif, alfredsock = value.split(':')
                alfred_instances.append(Alfred(unix_sockpath=alfredsock))
                batman_instances.append(Batman(mesh_interface=batif,
                                               alfred_sockpath=alfredsock))
            except ValueError:
                raise ValueError(
                    'Unparseable value "{0}" in --mesh parameter.'.
                    format(value))

    # read nodedb state from node.json
    try:
        with open(nodes_fn, 'r') as nodedb_handle:
            nodedb = json.load(nodedb_handle)
    except IOError:
        nodedb = {'nodes': dict()}

    # flush nodedb if it uses the old format
    if 'links' in nodedb:
        nodedb = {'nodes': dict()}

    # set version we're going to output
    nodedb['version'] = NODES_VERSION

    # update timestamp and assume all nodes are offline
    nodedb['timestamp'] = now.isoformat()
    for node_id, node in nodedb['nodes'].items():
        node['flags']['online'] = False

    # integrate alfred nodeinfo
    for alfred in alfred_instances:
        nodeinfo = validate_nodeinfos(alfred.nodeinfo())
        nodes.import_nodeinfo(nodedb['nodes'], nodeinfo,
                              now, assume_online=True)

    # integrate static aliases data
    for aliases in params['aliases']:
        with open(aliases, 'r') as f:
            nodeinfo = validate_nodeinfos(json.load(f))
            nodes.import_nodeinfo(nodedb['nodes'], nodeinfo,
                                  now, assume_online=False)

    nodes.reset_statistics(nodedb['nodes'])
    for alfred in alfred_instances:
        nodes.import_statistics(nodedb['nodes'], alfred.statistics())

    # acquire gwl and visdata for each batman instance
    mesh_info = []
    for batman in batman_instances:
        vd = batman.vis_data()
        gwl = batman.gateway_list()

        mesh_info.append((vd, gwl))

    # update nodedb from batman-adv data
    for vd, gwl in mesh_info:
        nodes.import_mesh_ifs_vis_data(nodedb['nodes'], vd)
        nodes.import_vis_clientcount(nodedb['nodes'], vd)
        nodes.mark_vis_data_online(nodedb['nodes'], vd, now)
        nodes.mark_gateways(nodedb['nodes'], gwl)

    # clear the nodedb from nodes that have not been online in $prune days
    if params['prune']:
        nodes.prune_nodes(nodedb['nodes'], now, params['prune'])

    # build nxnetworks graph from nodedb and visdata
    batadv_graph = nx.DiGraph()
    for vd, gwl in mesh_info:
        graph.import_vis_data(batadv_graph, nodedb['nodes'], vd)

    # force mac addresses to be vpn-link only (like gateways for example)
    if params['vpn']:
        graph.mark_vpn(batadv_graph, frozenset(params['vpn']))

    def extract_tunnel(nodes):
        macs = set()
        for id, node in nodes.items():
            try:
                for mac in node["nodeinfo"]["network"]["mesh"]["bat0"]["interfaces"]["tunnel"]:
                    macs.add(mac)
            except KeyError:
                pass

        return macs

    graph.mark_vpn(batadv_graph, extract_tunnel(nodedb['nodes']))

    batadv_graph = graph.merge_nodes(batadv_graph)
    batadv_graph = graph.to_undirected(batadv_graph)

    # write processed data to dest dir
    with open(nodes_fn + '.tmp', 'w') as f:
        json.dump(nodedb, f)
        # prevent glitch if files is reading while the new content is writing
        f.flush() # From Python-Docs: first do f.flush()
        os.fsync(f.fileno()) # and then do os.fsync(f.fileno())
        # to ensure that all internal buffers associated with f are written to disk.
    os.rename(nodes_fn + '.tmp', nodes_fn) # move new file to real position

    graph_out = {'batadv': json_graph.node_link_data(batadv_graph),
                 'version': GRAPH_VERSION}

    with open(graph_fn + '.tmp', 'w') as f:
        json.dump(graph_out, f)
        # prevent glitch if files is reading while the new content is writing
        f.flush() # From Python-Docs: first do f.flush()
        os.fsync(f.fileno()) # and then do os.fsync(f.fileno())
        # to ensure that all internal buffers associated with f are written to disk.
    os.rename(graph_fn + '.tmp', graph_fn) # move new file to real position

    with open(nodelist_fn + '.tmp', 'w') as f:
        json.dump(export_nodelist(now, nodedb), f)
        # prevent glitch if files is reading while the new content is writing
        f.flush() # From Python-Docs: first do f.flush()
        os.fsync(f.fileno()) # and then do os.fsync(f.fileno())
        # to ensure that all internal buffers associated with f are written to disk.
    os.rename(nodelist_fn + '.tmp', nodelist_fn) # move new file to real position


    # optional rrd graphs (trigger with --rrd)
    if params['rrd']:
        script_directory = os.path.dirname(os.path.realpath(__file__))
        rrd = RRD(os.path.join(script_directory, 'nodedb'),
                  os.path.join(params['dest_dir'], 'nodes'))
        rrd.update_database(nodedb['nodes'])
        rrd.update_images()
Example #2
0
def main(params):
    os.makedirs(params['dest_dir'], exist_ok=True)

    nodes_fn = os.path.join(params['dest_dir'], 'nodes.json')
    graph_fn = os.path.join(params['dest_dir'], 'graph.json')
    nodelist_fn = os.path.join(params['dest_dir'], 'nodelist.json')

    now = datetime.utcnow().replace(microsecond=0)

    # parse mesh param and instantiate Alfred/Batman instances
    alfred_instances = []
    batman_instances = []
    for value in params['mesh']:
        # (1) only batman-adv if, no alfred sock
        if ':' not in value:
            if len(params['mesh']) > 1:
                raise ValueError('Multiple mesh interfaces require the use of '
                                 'alfred socket paths.')
            alfred_instances.append(Alfred(unix_sockpath=None))
            batman_instances.append(Batman(mesh_interface=value))
        else:
            # (2) batman-adv if + alfred socket
            try:
                batif, alfredsock = value.split(':')
                alfred_instances.append(Alfred(unix_sockpath=alfredsock))
                batman_instances.append(
                    Batman(mesh_interface=batif, alfred_sockpath=alfredsock))
            except ValueError:
                raise ValueError(
                    'Unparseable value "{0}" in --mesh parameter.'.format(
                        value))

    # read nodedb state from node.json
    try:
        with open(nodes_fn, 'r') as nodedb_handle:
            nodedb = json.load(nodedb_handle)
    except IOError:
        nodedb = {'nodes': dict()}

    # flush nodedb if it uses the old format
    if 'links' in nodedb:
        nodedb = {'nodes': dict()}

    # set version we're going to output
    nodedb['version'] = NODES_VERSION

    # update timestamp and assume all nodes are offline
    nodedb['timestamp'] = now.isoformat()
    for node_id, node in nodedb['nodes'].items():
        node['flags']['online'] = False

    # integrate alfred nodeinfo
    for alfred in alfred_instances:
        nodes.import_nodeinfo(nodedb['nodes'],
                              alfred.nodeinfo(),
                              now,
                              assume_online=True)

    # integrate static aliases data
    for aliases in params['aliases']:
        with open(aliases, 'r') as f:
            nodes.import_nodeinfo(nodedb['nodes'],
                                  json.load(f),
                                  now,
                                  assume_online=False)

    nodes.reset_statistics(nodedb['nodes'])
    for alfred in alfred_instances:
        nodes.import_statistics(nodedb['nodes'], alfred.statistics())

    # acquire gwl and visdata for each batman instance
    mesh_info = []
    for batman in batman_instances:
        vd = batman.vis_data()
        gwl = batman.gateway_list()

        mesh_info.append((vd, gwl))

    # update nodedb from batman-adv data
    for vd, gwl in mesh_info:
        nodes.import_mesh_ifs_vis_data(nodedb['nodes'], vd)
        nodes.import_vis_clientcount(nodedb['nodes'], vd)
        nodes.mark_vis_data_online(nodedb['nodes'], vd, now)
        nodes.mark_gateways(nodedb['nodes'], gwl)

    # clear the nodedb from nodes that have not been online in $prune days
    if params['prune']:
        nodes.prune_nodes(nodedb['nodes'], now, params['prune'])

    # build nxnetworks graph from nodedb and visdata
    batadv_graph = nx.DiGraph()
    for vd, gwl in mesh_info:
        graph.import_vis_data(batadv_graph, nodedb['nodes'], vd)

    # force mac addresses to be vpn-link only (like gateways for example)
    if params['vpn']:
        graph.mark_vpn(batadv_graph, frozenset(params['vpn']))

    batadv_graph = graph.merge_nodes(batadv_graph)
    batadv_graph = graph.to_undirected(batadv_graph)

    # write processed data to dest dir
    with open(nodes_fn, 'w') as f:
        json.dump(nodedb, f)

    graph_out = {
        'batadv': json_graph.node_link_data(batadv_graph),
        'version': GRAPH_VERSION
    }

    with open(graph_fn, 'w') as f:
        json.dump(graph_out, f)

    with open(nodelist_fn, 'w') as f:
        json.dump(export_nodelist(now, nodedb), f)

    # optional rrd graphs (trigger with --rrd)
    if params['rrd']:
        script_directory = os.path.dirname(os.path.realpath(__file__))
        rrd = RRD(os.path.join(script_directory, 'nodedb'),
                  os.path.join(params['dest_dir'], 'nodes'))
        rrd.update_database(nodedb['nodes'])
        rrd.update_images()
Example #3
0
def main(params):
    os.makedirs(params['dest_dir'], exist_ok=True)

    nodes_fn = os.path.join(params['dest_dir'], 'nodes.json')
    graph_fn = os.path.join(params['dest_dir'], 'graph.json')
    nodelist_fn = os.path.join(params['dest_dir'], 'nodelist.json')

    now = datetime.utcnow().replace(microsecond=0)

    # parse mesh param and instantiate Alfred/Batman instances
    alfred_instances = []
    batman_instances = []
    for value in params['mesh']:
        # (1) only batman-adv if, no alfred sock
        if ':' not in value:
            if len(params['mesh']) > 1:
                raise ValueError(
                    'Multiple mesh interfaces require the use of '
                    'alfred socket paths.')
            alfred_instances.append(Alfred(unix_sockpath=None))
            batman_instances.append(Batman(mesh_interface=value))
        else:
            # (2) batman-adv if + alfred socket
            try:
                batif, alfredsock = value.split(':')
                alfred_instances.append(Alfred(unix_sockpath=alfredsock))
                batman_instances.append(Batman(mesh_interface=batif,
                                               alfred_sockpath=alfredsock))
            except ValueError:
                raise ValueError(
                    'Unparseable value "{0}" in --mesh parameter.'.
                    format(value))

    # read nodedb state from node.json
    try:
        with open(nodes_fn, 'r', encoding=('UTF-8')) as nodedb_handle:
            nodedb = json.load(nodedb_handle)
    except IOError:
        nodedb = {'nodes': []}

    # set version we're going to output
    nodedb['version'] = NODES_VERSION

    # update timestamp and assume all nodes are offline
    nodedb['timestamp'] = now.isoformat()
    for node in nodedb['nodes']:
        node['flags']['online'] = False

    nodesdict = {}

    for node in nodedb['nodes']:
        nodesdict[node['nodeinfo']['node_id']] = node

    # integrate alfred nodeinfo
    for alfred in alfred_instances:
        nodeinfo = validate_nodeinfos(alfred.nodeinfo())
        nodes.import_nodeinfo(nodesdict, nodeinfo,
                              now, assume_online=True)

    # integrate static aliases data
    for aliases in params['aliases']:
        with open(aliases, 'r') as f:
            nodeinfo = validate_nodeinfos(json.load(f))
            nodes.import_nodeinfo(nodesdict, nodeinfo,
                                  now, assume_online=False)

    nodes.reset_statistics(nodesdict)
    for alfred in alfred_instances:
        nodes.import_statistics(nodesdict, alfred.statistics())

    # acquire visdata for each batman instance
    mesh_info = []
    for batman in batman_instances:
        vd = batman.vis_data()

        mesh_info.append(vd)

    # update nodedb from batman-adv data
    for vd in mesh_info:
        nodes.import_mesh_ifs_vis_data(nodesdict, vd)
        nodes.import_vis_clientcount(nodesdict, vd)
        nodes.mark_vis_data_online(nodesdict, vd, now)

    # clear the nodedb from nodes that have not been online in $prune days
    if params['prune']:
        nodes.prune_nodes(nodesdict, now, params['prune'])

    # build nxnetworks graph from nodedb and visdata
    batadv_graph = nx.DiGraph()
    for vd in mesh_info:
        graph.import_vis_data(batadv_graph, nodesdict, vd)

    # force mac addresses to be vpn-link only (like gateways for example)
    if params['vpn']:
        graph.mark_vpn(batadv_graph, frozenset(params['vpn']))

    nodedb['nodes'] = list(nodesdict.values())

    def extract_tunnel(nodes):
        macs = set()
        for node in nodes:
            try:
                for mac in node["nodeinfo"]["network"]["mesh"]["bat0"]["interfaces"]["tunnel"]:
                    macs.add(mac)
            except KeyError:
                pass

        return macs

    graph.mark_vpn(batadv_graph, extract_tunnel(nodedb['nodes']))

    batadv_graph = graph.merge_nodes(batadv_graph)
    batadv_graph = graph.to_undirected(batadv_graph)

    # write processed data to dest dir
    with open(nodes_fn, 'w') as f:
        json.dump(nodedb, f)

    graph_out = {'batadv': json_graph.node_link_data(batadv_graph),
                 'version': GRAPH_VERSION}

    with open(graph_fn, 'w') as f:
        json.dump(graph_out, f)

    with open(nodelist_fn, 'w') as f:
        json.dump(export_nodelist(now, nodedb), f)

    # optional rrd graphs (trigger with --rrd)
    if params['rrd']:
        rrd = RRD(params['rrd_path'], os.path.join(params['dest_dir'], 'nodes'))
        rrd.update_database(nodedb['nodes'])
        rrd.update_images()
Example #4
0
def main(params):
    os.makedirs(params["dest_dir"], exist_ok=True)

    nodes_fn = os.path.join(params["dest_dir"], "nodes.json")
    graph_fn = os.path.join(params["dest_dir"], "graph.json")
    nodelist_fn = os.path.join(params["dest_dir"], "nodelist.json")

    now = datetime.utcnow().replace(microsecond=0)

    # parse mesh param and instantiate Alfred/Batman instances
    alfred_instances = []
    batman_instances = []
    for value in params["mesh"]:
        # (1) only batman-adv if, no alfred sock
        if ":" not in value:
            if len(params["mesh"]) > 1:
                raise ValueError("Multiple mesh interfaces require the use of " "alfred socket paths.")
            alfred_instances.append(Alfred(unix_sockpath=None))
            batman_instances.append(Batman(mesh_interface=value))
        else:
            # (2) batman-adv if + alfred socket
            try:
                batif, alfredsock = value.split(":")
                alfred_instances.append(Alfred(unix_sockpath=alfredsock))
                batman_instances.append(Batman(mesh_interface=batif, alfred_sockpath=alfredsock))
            except ValueError:
                raise ValueError('Unparseable value "{0}" in --mesh parameter.'.format(value))

    # read nodedb state from node.json
    try:
        with open(nodes_fn, "r") as nodedb_handle:
            nodedb = json.load(nodedb_handle)
    except IOError:
        nodedb = {"nodes": dict()}

    # flush nodedb if it uses the old format
    if "links" in nodedb:
        nodedb = {"nodes": dict()}

    # set version we're going to output
    nodedb["version"] = NODES_VERSION

    # update timestamp and assume all nodes are offline
    nodedb["timestamp"] = now.isoformat()
    for node_id, node in nodedb["nodes"].items():
        node["flags"]["online"] = False

    # integrate alfred nodeinfo
    for alfred in alfred_instances:
        nodeinfo = validate_nodeinfos(alfred.nodeinfo())
        nodes.import_nodeinfo(nodedb["nodes"], nodeinfo, now, assume_online=True)

    # integrate static aliases data
    for aliases in params["aliases"]:
        with open(aliases, "r") as f:
            nodeinfo = validate_nodeinfos(json.load(f))
            nodes.import_nodeinfo(nodedb["nodes"], nodeinfo, now, assume_online=False)

    nodes.reset_statistics(nodedb["nodes"])
    for alfred in alfred_instances:
        nodes.import_statistics(nodedb["nodes"], alfred.statistics())

    # acquire gwl and visdata for each batman instance
    mesh_info = []
    for batman in batman_instances:
        vd = batman.vis_data()
        gwl = batman.gateway_list()

        mesh_info.append((vd, gwl))

    # update nodedb from batman-adv data
    for vd, gwl in mesh_info:
        nodes.import_mesh_ifs_vis_data(nodedb["nodes"], vd)
        nodes.import_vis_clientcount(nodedb["nodes"], vd)
        nodes.mark_vis_data_online(nodedb["nodes"], vd, now)
        nodes.mark_gateways(nodedb["nodes"], gwl)

    # clear the nodedb from nodes that have not been online in $prune days
    if params["prune"]:
        nodes.prune_nodes(nodedb["nodes"], now, params["prune"])

    # clear the nodedb from a specific node by MAC address
    if params["prunemac"]:
        nodes.prune_mac_node(nodedb["nodes"], params["prunemac"])

    # build nxnetworks graph from nodedb and visdata
    batadv_graph = nx.DiGraph()
    for vd, gwl in mesh_info:
        graph.import_vis_data(batadv_graph, nodedb["nodes"], vd)

    # force mac addresses to be vpn-link only (like gateways for example)
    if params["vpn"]:
        graph.mark_vpn(batadv_graph, frozenset(params["vpn"]))

    def extract_tunnel(nodes):
        macs = set()
        for id, node in nodes.items():
            try:
                for mac in node["nodeinfo"]["network"]["mesh"]["bat0"]["interfaces"]["tunnel"]:
                    macs.add(mac)
            except KeyError:
                pass

        return macs

    graph.mark_vpn(batadv_graph, extract_tunnel(nodedb["nodes"]))

    batadv_graph = graph.merge_nodes(batadv_graph)
    batadv_graph = graph.to_undirected(batadv_graph)

    # write processed data to dest dir
    with open(nodes_fn, "w") as f:
        json.dump(nodedb, f)

    graph_out = {"batadv": json_graph.node_link_data(batadv_graph), "version": GRAPH_VERSION}

    with open(graph_fn, "w") as f:
        json.dump(graph_out, f)

    with open(nodelist_fn, "w") as f:
        json.dump(export_nodelist(now, nodedb), f)

    # optional rrd graphs (trigger with --rrd)
    if params["rrd"]:
        script_directory = os.path.dirname(os.path.realpath(__file__))
        rrd = RRD(os.path.join(script_directory, "nodedb"), os.path.join(params["dest_dir"], "nodes"))
        rrd.update_database(nodedb["nodes"])
        rrd.update_images()
def main(params):
    os.makedirs(params['dest_dir'], exist_ok=True)

    nodes_fn = os.path.join(params['dest_dir'], 'nodes.json')
    graph_fn = os.path.join(params['dest_dir'], 'graph.json')
    nodelist_fn = os.path.join(params['dest_dir'], 'nodelist.json')

    now = datetime.utcnow().replace(microsecond=0)

    # parse mesh param and instantiate Alfred/Batman instances
    alfred_instances = []
    batman_instances = []
    for value in params['mesh']:
        # (1) only batman-adv if, no alfred sock
        if ':' not in value:
            if len(params['mesh']) > 1:
                raise ValueError(
                    'Multiple mesh interfaces require the use of '
                    'alfred socket paths.')
            alfred_instances.append(Alfred(unix_sockpath=None))
            batman_instances.append(Batman(mesh_interface=value))
        else:
            # (2) batman-adv if + alfred socket
            try:
                batif, alfredsock = value.split(':')
                alfred_instances.append(Alfred(unix_sockpath=alfredsock))
                batman_instances.append(Batman(mesh_interface=batif,
                                               alfred_sockpath=alfredsock))
            except ValueError:
                raise ValueError(
                    'Unparseable value "{0}" in --mesh parameter.'.
                    format(value))

    # read nodedb state from node.json
    try:
        with open(nodes_fn, 'r') as nodedb_handle:
            nodedb = json.load(nodedb_handle)
    except (IOError, ValueError):
        nodedb = {'nodes': dict()}

    # flush nodedb if it uses the old format
    if 'links' in nodedb:
        nodedb = {'nodes': dict()}

    # set version we're going to output
    nodedb['version'] = NODES_VERSION

    # update timestamp and assume all nodes are offline
    nodedb['timestamp'] = now.isoformat()
    for node_id, node in nodedb['nodes'].items():
        node['flags']['online'] = False

    # integrate alfred nodeinfo
    for alfred in alfred_instances:
        nodeinfo = validate_nodeinfos(alfred.nodeinfo())
        nodes.import_nodeinfo(nodedb['nodes'], nodeinfo,
                              now, assume_online=True)

    # integrate static aliases data
    for aliases in params['aliases']:
        with open(aliases, 'r') as f:
            nodeinfo = validate_nodeinfos(json.load(f))
            nodes.import_nodeinfo(nodedb['nodes'], nodeinfo,
                                  now, assume_online=False)

    nodes.reset_statistics(nodedb['nodes'])
    for alfred in alfred_instances:
        nodes.import_statistics(nodedb['nodes'], alfred.statistics())

    # acquire gwl and visdata for each batman instance
    mesh_info = []
    for batman in batman_instances:
        vd = batman.vis_data()
        gwl = batman.gateway_list()

        mesh_info.append((vd, gwl))

    # integrate static online aliases data

    gwc = {}

    # parse aliases for gateways
    for aliases in params['aliases_online']:
        with open(aliases, 'r') as f:
            nodeinfo = validate_nodeinfos(json.load(f))
            for node in nodeinfo:
                try:
                    system = nodedb['nodes'][node.get('node_id')]['nodeinfo'].get('system', None)
                    if system:
                        # if role is gatway add mac to gateway list (gwl)
                        if nodedb['nodes'][node.get('node_id')]['nodeinfo']['system'].get('role') == 'gateway':
                            mac = nodedb['nodes'][node.get('node_id')]['nodeinfo']['network'].get('mac', None)
                            if mac:
                                # extend gwl
                                gwl.append(mac)
                                # fake visdata
                                vd.append({"primary": mac})
                                gwc[mac] = 0
                except KeyError:
                    pass

    # parse data from aliases
    for aliases in params['aliases_online']:
        with open(aliases, 'r') as f:
            nodeinfo = validate_nodeinfos(json.load(f))
            nodes.import_nodeinfo(nodedb['nodes'], nodeinfo,
                                  now, assume_online=True)
            for node in nodeinfo:
                gateways = nodedb['nodes'][node.get('node_id')]['nodeinfo']['network'].get('gateway', None)
                # if gateway in gwl fake visdata
                if gateways:
                    if isinstance(gateways, str):
                        gateways = [ gateways ]
                    for gateway in gateways:
                        gateway = ':'.join(gateway[i:i+2] for i in range(0,12,2))
                        if gateway in gwl:
                            mac = nodedb['nodes'][node.get('node_id')]['nodeinfo']['network'].get('mac', None)
                            if mac:
                                # fake visdata
                                vd.append({"primary": mac})
                                vd.append({"router": mac, "label": "TT", "gateway": gateway})
                                vd.append({"router": mac, "label": "1.000", "neighbor": gateway})
                                # count node to gateway clients
                                try:
                                    gwc[gateway] += 1
                                except KeyError:
                                    pass
                # add Statistics from aliases
                try:
                    statistics = node.get('statistics', None)
                except KeyError:
                    pass
                if statistics:
                    if nodedb['nodes'][node.get('node_id')].get('statistics'):
                        nodedb['nodes'][node.get('node_id')]['statistics'].update(statistics)
                        nodedb['nodes'][node.get('node_id')]['nodeinfo'].pop('statistics')

    if params['aliases_online']:
        # update gateway clients
        for gw in gwc:
            node = gw.replace(':', '')
            try:
                clients = nodedb['nodes'][node]['statistics'].get('clients')
                nodedb['nodes'][node]['statistics']['clients'] = clients + gwc[gw]
                clients = nodedb['nodes'][node]['statistics'].get('clients')
            except KeyError:
                pass
        # rebuild mesh_info
        mesh_info = []
        mesh_info.append((vd, gwl))

    # update nodedb from batman-adv data
    for vd, gwl in mesh_info:
        nodes.import_mesh_ifs_vis_data(nodedb['nodes'], vd)
        nodes.import_vis_clientcount(nodedb['nodes'], vd)
        nodes.mark_vis_data_online(nodedb['nodes'], vd, now)
        nodes.mark_gateways(nodedb['nodes'], gwl)

    # clear the nodedb from nodes that have not been online in $prune days
    if params['prune']:
        nodes.prune_nodes(nodedb['nodes'], now, params['prune'])

    # build nxnetworks graph from nodedb and visdata
    batadv_graph = nx.DiGraph()
    for vd, gwl in mesh_info:
        graph.import_vis_data(batadv_graph, nodedb['nodes'], vd)

    # force mac addresses to be vpn-link only (like gateways for example)
    if params['vpn']:
        graph.mark_vpn(batadv_graph, frozenset(params['vpn']))

    def extract_tunnel(nodes):
        macs = set()
        for id, node in nodes.items():
            try:
                for mac in node["nodeinfo"]["network"]["mesh"]["bat0"]["interfaces"]["tunnel"]:
                    macs.add(mac)
            except KeyError:
                pass

        return macs

    graph.mark_vpn(batadv_graph, extract_tunnel(nodedb['nodes']))

    batadv_graph = graph.merge_nodes(batadv_graph)
    batadv_graph = graph.to_undirected(batadv_graph)

    # optional anonymize data (trigger with --anonymize)
    if params['anonymize']:
        for node in nodedb['nodes']:
            if nodedb['nodes'][node]['nodeinfo'].get('owner'):
                nodedb['nodes'][node]['nodeinfo'].pop('owner')

    # write processed data to dest dir
    with open(nodes_fn, 'w') as f:
        json.dump(nodedb, f)

    graph_out = {'batadv': json_graph.node_link_data(batadv_graph),
                 'version': GRAPH_VERSION}

    with open(graph_fn, 'w') as f:
        json.dump(graph_out, f)

    with open(nodelist_fn, 'w') as f:
        json.dump(export_nodelist(now, nodedb), f)

    # optional rrd graphs (trigger with --rrd)
    if params['rrd']:
        script_directory = os.path.dirname(os.path.realpath(__file__))
        rrd = RRD(os.path.join(script_directory, 'nodedb'),
                  os.path.join(params['dest_dir'], 'nodes'),
                  params['display_time_global'],
                  params['display_time_node'])
        rrd.update_database(nodedb['nodes'])
        rrd.update_images()