orchestrator.py 6.03 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#!/usr/bin/env python3

# Copyright (C) 2018 Simon Redman <sredman@cs.utah.edu>
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# For future reference, here is the OSPFv6 RFC: https://tools.ietf.org/html/rfc2740.html

import add_routable_ipv6_addrs
import frr_configurator
22
import ipt_NETFLOW_configurator
23
import ospf_sniffer_configurator
24
import silk_configurator
25
import ssh_helper
26
import sysctl_configurator
27 28 29 30
import topomap_parser

import argparse
import getpass
31
import json
32
from netdiff import NetJsonParser
33
import re
34 35 36 37 38 39 40

if __name__ == "__main__":
    parser = argparse.ArgumentParser("Setup an Emulab experiment for Segment Routing")
    parser.add_argument("--topomap-file", action='store', default='/var/emulab/boot/topomap', type=str,
                        help="Path to the emulab topomap file to parse")
    parser.add_argument("--netgraph-file", action='store', type=str, required=False,
                        help="Path to the NetJSON file to parse. Skips parsing the netgrap from the topomap-file")
41 42
    parser.add_argument("--netgraph-write", action='store', type=str, required=False,
                        help="(Optional) Path to write the final NetJSON file")
43 44
    parser.add_argument("--username", action='store', type=str, default=getpass.getuser(),
                        help="Username to use on all hosts. Defaults to current user's username")
45 46 47 48
    parser.add_argument("--no-frr", action='store_true',
                        help="Do not start the FRR daemons")
    parser.add_argument("--no-sniffer", action='store_true',
                        help="Do not start the OSPF sniffer daemons")
49
    parser.add_argument("--controller-name", action='store', type=str, default=ospf_sniffer_configurator.DEFAULT_CONTROLLER,
50
                        help="Hostname or IP of the node which is acting as the controller for all collectors (Default: {default})".format(default=ospf_sniffer_configurator.DEFAULT_CONTROLLER))
51 52
    parser.add_argument("--controller-port", action='store', type=int, default=ospf_sniffer_configurator.DEFAULT_CONTROLLER_PORT,
                        help="Port number on the server listening for OSPF reports (Default: {default})".format(default=ospf_sniffer_configurator.DEFAULT_CONTROLLER_PORT))
53 54
    parser.add_argument("--border-regex", action='store', type=str, default='^ovs.*',
                        help="Regex to distinguish border switch nodes by label (Default \"^ovs.*\")")
55 56
    parser.add_argument("--host-regex", action='store', type=str, default='^host.*',
                        help="Regex to distinguish host nodes by label (Default \"^host.*\")")
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

    args = parser.parse_args()

    if not args.netgraph_file:
        netgraph = NetJsonParser(data=topomap_parser.parse_topomap_to_netjson(args.topomap_file))
    else:
        netgraph = NetJsonParser(file=args.netgraph_file)

    ssh_helper.network_graph_login(netgraph.graph, args.username)

    # Skip adding ipv6 addresses to the management interfaces
    management_ips = [node["management-ip"] for node in netgraph.graph._node.values()]

    ULA_map = add_routable_ipv6_addrs.construct_ULAs(netgraph.graph, ignore_addrs=management_ips)

    add_routable_ipv6_addrs.add_ULAs_to_hosts(netgraph.graph, ULA_map)
    add_routable_ipv6_addrs.add_interfaces_to_netgraph(netgraph.graph, ULA_map)

75 76
    # Prepare a list of nodes which act as an edge switch and should thus be ignore for router-related activites
    border_nodes = []
77 78
    for node in netgraph.graph.nodes:
        node_name = netgraph.graph._node[node]['label']
79 80 81 82
        if re.match(args.border_regex, node_name):
            border_nodes.append(node)

    controller_node = [node for node in netgraph.graph._node if netgraph.graph._node[node]['label'] == args.controller_name].pop()
83

84
    # Prepare a list of nodes which are "customer host nodes" and should thus be ignored for core network-related activities
85 86 87 88 89 90
    host_nodes = []
    for node in netgraph.graph.nodes:
        node_name = netgraph.graph._node[node]['label']
        if re.match(args.host_regex, node_name):
            host_nodes.append(node)

91 92
    frr_configurator.configure_nodes(netgraph.graph, ignore_nodes=border_nodes)
    sysctl_configurator.configure_nodes(netgraph.graph, ignore_nodes=border_nodes)
93

94 95
    ospf_sniffer_configurator.clone_repo_on_network(netgraph.graph, ignore_nodes=border_nodes + host_nodes)
    ospf_sniffer_configurator.stop_sniffer_on_network(netgraph.graph, ignore_nodes=border_nodes + host_nodes)  # Stopping with the app not running is not great, but better than starting twice
Simon Redman's avatar
Simon Redman committed
96

97
    if not args.no_frr:
98
        frr_configurator.start_frr_on_network(netgraph.graph, ignore_nodes=border_nodes)
99
    if not args.no_sniffer:
Simon Redman's avatar
Simon Redman committed
100 101 102
        ospf_sniffer_configurator.start_sniffer_on_network(netgraph.graph,
                                                           controller=args.controller_name,
                                                           port=args.controller_port,
103
                                                           ignore_nodes=border_nodes + host_nodes)
104

105 106 107 108
    silk_configurator.configure(netgraph.graph,
                                controller_node=controller_node,
                                border_routers=border_nodes,
                                )
109 110 111 112 113
    ipt_NETFLOW_configurator.configure(netgraph.graph,
                                       collector_node=controller_node,
                                       border_routers=border_nodes,
                                       )

114
    ssh_helper.network_graph_logout(netgraph.graph)
115 116

    if args.netgraph_write:
117 118
        with open(args.netgraph_write, 'w') as outfile:
            json.dump(netgraph.json(dict=True), outfile)