예제 #1
0
def ping_from_ns(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    dest = request.args.get("destination")

    if app.simulate:
        if dest == "1.1.1.1":
            return jsonify(
                {
                    "destination": "1.1.1.1",
                    "packet_duplicate_count": 0,
                    "packet_duplicate_rate": 0,
                    "packet_loss_count": 0,
                    "packet_loss_rate": 0,
                    "packet_receive": 4,
                    "packet_transmit": 4,
                    "rtt_avg": 5.472,
                    "rtt_max": 10.635,
                    "rtt_mdev": 3.171,
                    "rtt_min": 2.533,
                }
            )
        else:
            return jsonify({})
    else:
        ping_parser = pingparsing.PingParsing()
        try:
            result = util.run_in_ns(namespace, ["ping", "-c", "4", "-i", "0.2", dest])
            return jsonify(ping_parser.parse(result).as_dict())
        except subprocess.CalledProcessError as e:
            LOGGER.exception("status: %s, out: %s, err: %s", e.returncode, e.stdout, e.stderr)
            return jsonify({})
예제 #2
0
def add_namespace(namespace):
    namespace = util.process_namespace(namespace)

    if app.simulate:
        cfg = get_config()

        if namespace in cfg.namespaces:
            return abort(409)
        cfg.namespaces[namespace] = Namespace(namespace, interfaces=[{
            "ifindex": 1,
            "ifname": "lo",
            "flags": ["LOOPBACK"],
            "mtu": 65536,
            "qdisc": "noop",
            "operstate": "DOWN",
            "linkmode": "DEFAULT",
            "group": "default",
            "txqlen": 1000,
            "link_type": "loopback",
            "address": "00:00:00:00:00:00",
            "broadcast": "00:00:00:00:00:00"
        }])
        return jsonify({})
    create_namespace(namespace)

    return jsonify({})
예제 #3
0
def traceroute_from_ns(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    dest = request.args.get("destination")
    if app.simulate:
        if dest == "1.1.1.1":
            return jsonify(
                {
                    "destination_ip": "1.1.1.1",
                    "destination_name": "host",
                    "hops": [
                        {
                            "index": 1,
                            "probes": ["host (1.1.1.1) 0.013 ms", "host (1.1.1.1) 0.003 ms", "host (1.1.1.1) 0.003 ms"],
                        }
                    ],
                }
            )
        else:
            return jsonify({})
    else:
        try:
            result = util.run_in_ns(namespace, ["traceroute", dest])
            parsed = trparse.loads(result)
            hops = []
            for hop in parsed.hops:
                probes = []
                for probe in hop.probes:
                    probes.append(str(probe).strip())
                hops.append({"index": hop.idx, "probes": probes})
            traceroute = {"destination_name": parsed.dest_name, "destination_ip": parsed.dest_ip, "hops": hops}
            return jsonify(traceroute)
        except subprocess.CalledProcessError as e:
            LOGGER.exception("status: %s, out: %s, err: %s", e.returncode, e.stdout, e.stderr)
            return jsonify({})
예제 #4
0
def move_interface(namespace, interface):
    namespace = util.process_namespace(namespace)

    parts = interface.split(".")
    if len(parts) not in range(1, 4):
        raise exceptions.ServerError(f"Only untagged, single and double tagged interfaces are supported")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        all_interfaces = [intf.name for intf in cfg.namespaces[namespace].interfaces]
    else:
        all_interfaces = util.list_interfaces(namespace)

    if interface not in all_interfaces:
        raise exceptions.ServerError(f"Interface {interface} does not exist in {namespace}")

    new_namespace_key: str = "destination_namespace"
    if new_namespace_key not in request.json:
        raise exceptions.ServerError(f"Invalid request: request should contain \"destination_namespace\"")

    new_namespace = request.json[new_namespace_key]

    if app.simulate:
        old_ns: Namespace = cfg.namespaces[namespace]
        new_ns: Namespace = cfg.namespaces[new_namespace]
        iface: Interface = old_ns.get_interface(interface)
        old_ns.interfaces.remove(iface)
        new_ns.interfaces.append(iface)
    else:
        util.move_interface(new_namespace, interface, interface, old_namespace=namespace)

    return jsonify({})
예제 #5
0
def delete_namespace(namespace):
    namespace = util.process_namespace(namespace)

    if namespace not in list_namespaces().get_json():
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    interfaces: List = list_interfaces(namespace).get_json()
    untagged: List = [
        interface
        for interface in interfaces
        if "." not in interface and interface != "lo"
    ]
    if untagged:
        raise exceptions.ServerError(
            "Unable to delete namespace with untagged interfaces %s in it."
            " Move them to another interface first."
            % ", ".join(untagged)
        )

    if app.simulate:
        cfg = get_config()

        if namespace not in cfg.namespaces:
            return abort(404)

        del cfg.namespaces[namespace]
        return jsonify({})

    util.delete_namespace(namespace)
    return jsonify({})
예제 #6
0
def list_interfaces(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            return abort(404)

        return jsonify([intf.name for intf in cfg.namespaces[namespace].interfaces])

    return jsonify(util.list_interfaces(namespace))
예제 #7
0
def get_routing_table_from_ns(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)
        ns = cfg.namespaces[namespace]
        return jsonify([route.to_json() for route in ns.routes])
    else:
        try:
            routes = util.list_routes(namespace)
            return jsonify(routes)
        except subprocess.CalledProcessError as e:
            LOGGER.exception("status: %s, out: %s, err: %s", e.returncode, e.stdout, e.stderr)
            return jsonify({})
예제 #8
0
def set_interface_state(namespace, interface):
    namespace = util.process_namespace(namespace)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        if intf is None:
            abort(404)

        intf.set_state(request.json)
        return jsonify({"interface": intf.get_state()})
    else:
        util.set_interface_state(namespace, interface, request.json)
        return jsonify(util.get_interface_state(namespace, interface))
예제 #9
0
def get_interface_state(namespace, interface):
    namespace = util.process_namespace(namespace, allow_none=True)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        if intf is None:
            abort(404)

        return jsonify({"interface": intf.get_state()})
    else:
        try:
            return jsonify(util.get_interface_state(namespace, interface))
        except Exception:
            LOGGER.exception("Failed to get the interface state")
            abort(404)
예제 #10
0
def add_route_from_ns(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    subnet = request.get_json(force=True).get("subnet")
    gateway = request.get_json(force=True).get("gateway", None)
    interface = request.get_json(force=True).get("interface", None)
    if gateway is None and interface is None:
        raise exceptions.ServerError("gateway or interface should be set.")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        route = Route(subnet, gateway, interface)
        if route in ns.routes:
            abort(409)
        else:
            ns.routes.append(route)
        return jsonify([route.to_json() for route in ns.routes])
    else:
        try:
            util.run_in_ns(
                namespace,
                [
                    "ip",
                    "route",
                    "add",
                    subnet,
                    *(["via", gateway] if gateway is not None else []),
                    *(["dev", interface] if interface is not None else []),
                ],
            )
            routes = util.list_routes(namespace)
            return jsonify(routes)
        except subprocess.CalledProcessError as e:
            LOGGER.exception("status: %s, out: %s, err: %s", e.returncode, e.stdout, e.stderr)
            return jsonify({})
예제 #11
0
def create_sub_interface(namespace, interface):
    namespace = util.process_namespace(namespace)

    parts = interface.split(".")
    if len(parts) not in [2, 3]:
        raise exceptions.ServerError(f"Only single and double tagged interfaces are supported")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        all_interfaces = [intf.name for intf in cfg.namespaces[namespace].interfaces]
    else:
        all_interfaces = util.list_interfaces(namespace)

    if interface in all_interfaces:
        raise exceptions.ServerError(f"Interface {interface} already exists in {namespace}")

    base_interface = parts.pop(0)

    if base_interface not in all_interfaces:
        raise exceptions.ServerError(f"Base interface {base_interface} does not exist")

    outer = int(parts.pop(0))
    inner = 0
    if len(parts):
        inner = int(parts[0])

    if app.simulate:
        ns = cfg.namespaces[namespace]
        base_intf = ns.get_interface(base_interface)
        intf = config.Interface(name=interface, mac=base_intf.mac)
        ns.interfaces.append(intf)
        return jsonify({"interface": intf.get_state()})
    else:
        util.create_sub_interface(namespace, base_interface, outer, inner)
        return jsonify(util.get_interface_state(namespace, interface))