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({})
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({})
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({})
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({})
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({})
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))
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({})
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))
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)
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({})
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))