Commit ea9bd892 authored by Simon Redman's avatar Simon Redman

Add helper for generating and setting routable ipv6 addresses

parent 3265d84a
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Redman <>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ssh_helper
import argparse
import getpass
import ipaddress
from netdiff import NetJsonParser
import re
INTERFACE_ID_COMMAND = "ip -6 address list"
def parse_local_interface_addresses(netgraph):
For each ssh session, query the remote for its interfaces, then parse that for its IPv6 interface ID on each interface
:param netgraph: topology map, annotated with logged-in ssh sessions
:return: mapping of hosts to map of interfaces to that interface's IPv6 interface address
hosts = []
sessions = []
commands = []
interface_map = {}
for host in netgraph.graph.nodes:
interface_map[host] = {}
# Build an ordered list of hosts, sessions, and commands
outputs = ssh_helper.run_commands_on_many_hosts(sessions, commands)
for host_idx in range(len(hostnames)):
# Split the output of the `ip` command per-interface. It comes in as a numbered list, so split on the numbers
interface_lines = re.split(r'\s[0-9]+:\s', outputs[host_idx])
# Dump the first line since it is the echo of the command we sent
interface_lines = interface_lines[1:]
for line in interface_lines:
# The first token, ending with a colon, is the name of the interface
interface_name, *remainder = re.split(r':', line, 1)
assert len(remainder) == 1, "Error when splitting for interface name. More than one regex match found!"
if interface_name == 'lo':
# Don't mess with the loopback interface
# Parse out the link-local ipv6 address. There should be only one.
ipaddr = re.findall(r'\sinet6\s+(.*?)\s+scope link', remainder[0])
assert len(ipaddr) == 1, "Should only have found one link-local address!"
ipaddr = ipaddress.ip_interface(ipaddr[0])
interface_map[hostnames[host_idx]][interface_name] = ipaddr
return interface_map
if __name__ == "__main__":
parser = argparse.ArgumentParser("Generate IPv6 Unique Local Addresses for all nodes in the network")
parser.add_argument("--in-file", action='store', type=str, required=True,
help="Path to the NetJSON file to parse")
parser.add_argument("--out-file", action='store', type=str, required=False,
help="Path to write the annotated NetJSON. Default to overwriting in-file.")
parser.add_argument("--username", action='store', type=str, default=getpass.getuser(),
help="Username to use on all hosts. Defaults to current user's username")
args = parser.parse_args()
args.out_file = args.out_file or args.in_file
netgraph = NetJsonParser(file=args.in_file)
hostnames = [node for node in netgraph.graph.nodes]
usernames = [args.username for i in range(len(hostnames))]
sessions, passwords = ssh_helper.log_in_many_sessions(hostnames, usernames)
for host_idx in range(len(hostnames)):
netgraph.graph._node[hostnames[host_idx]]['session'] = sessions[host_idx]
interface_map = parse_local_interface_addresses(netgraph)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment