updates to route monitor

This commit is contained in:
Blake Harnden 2020-04-13 16:59:55 -07:00
parent 04bd3a2f8f
commit 971a959a19

View file

@ -4,6 +4,7 @@ import enum
import select import select
import socket import socket
import subprocess import subprocess
import sys
import time import time
from argparse import ArgumentDefaultsHelpFormatter from argparse import ArgumentDefaultsHelpFormatter
from functools import cmp_to_key from functools import cmp_to_key
@ -11,6 +12,8 @@ from queue import Queue
from threading import Thread from threading import Thread
from typing import Dict, Tuple from typing import Dict, Tuple
import grpc
from core import utils from core import utils
from core.api.grpc.client import CoreGrpcClient from core.api.grpc.client import CoreGrpcClient
from core.api.grpc.core_pb2 import NodeType from core.api.grpc.core_pb2 import NodeType
@ -56,14 +59,17 @@ class SdtClient:
class RouterMonitor: class RouterMonitor:
def __init__(self, src_id: str, src: str, dst: str, pkt: str, def __init__(self, session: int, src: str, dst: str, pkt: str, rate: int, dead: int,
sdt_host: str, sdt_port: int) -> None: sdt_host: str, sdt_port: int) -> None:
self.queue = Queue() self.queue = Queue()
self.core = CoreGrpcClient() self.core = CoreGrpcClient()
self.src_id = src_id self.session = session
self.src_id = None
self.src = src self.src = src
self.dst = dst self.dst = dst
self.pkt = pkt self.pkt = pkt
self.rate = rate
self.dead = dead
self.seen = {} self.seen = {}
self.running = False self.running = False
self.route_time = None self.route_time = None
@ -71,23 +77,44 @@ class RouterMonitor:
self.sdt = SdtClient((sdt_host, sdt_port)) self.sdt = SdtClient((sdt_host, sdt_port))
self.nodes = self.get_nodes() self.nodes = self.get_nodes()
def get_nodes(self) -> Dict[str, str]: def get_nodes(self) -> Dict[int, str]:
nodes = {}
with self.core.context_connect(): with self.core.context_connect():
if self.session is None:
self.session = self.get_session()
print("session: ", self.session)
try:
response = self.core.get_session(self.session)
nodes = response.session.nodes
node_map = {}
for node in nodes:
if node.type != NodeType.DEFAULT:
continue
node_map[node.id] = node.channel
if self.src_id is None:
response = self.core.get_node(self.session, node.id)
for netif in response.interfaces:
if self.src == netif.ip4:
self.src_id = node.id
break
except grpc.RpcError:
print(f"invalid session: {self.session}")
sys.exit(1)
if self.src_id is None:
print(f"could not find node with source address: {self.src}")
sys.exit(1)
print(f"monitoring src_id ({self.src_id}) src({self.src}) dst({self.dst}) pkt({self.pkt})")
return node_map
def get_session(self) -> int:
response = self.core.get_sessions() response = self.core.get_sessions()
sessions = response.sessions sessions = response.sessions
session = None session = None
if sessions: if sessions:
session = sessions[0] session = sessions[0]
if not session: if not session:
raise Exception("no current core sessions") print("no current core sessions")
print("session: ", session.dir) sys.exit(1)
response = self.core.get_session(session.id) return session.id
for node in response.session.nodes:
if node.type != NodeType.DEFAULT:
continue
nodes[node.id] = node.channel
return nodes
def start(self) -> None: def start(self) -> None:
self.running = True self.running = True
@ -107,7 +134,7 @@ class RouterMonitor:
elif node in self.seen: elif node in self.seen:
del self.seen[node] del self.seen[node]
if (time.monotonic() - self.route_time) >= ROUTE_TIME: if (time.monotonic() - self.route_time) >= self.rate:
self.manage_routes() self.manage_routes()
self.route_time = time.monotonic() self.route_time = time.monotonic()
@ -148,7 +175,7 @@ class RouterMonitor:
def listen(self, node_id, node) -> None: def listen(self, node_id, node) -> None:
cmd = ( cmd = (
f"tcpdump -lnv src host {self.src} and dst host {self.dst} and {self.pkt}" f"tcpdump -lnvi any src host {self.src} and dst host {self.dst} and {self.pkt}"
) )
node_cmd = f"vcmd -c {node} -- {cmd}" node_cmd = f"vcmd -c {node} -- {cmd}"
p = subprocess.Popen(node_cmd, shell=True, stdout=subprocess.PIPE, p = subprocess.Popen(node_cmd, shell=True, stdout=subprocess.PIPE,
@ -166,7 +193,7 @@ class RouterMonitor:
self.queue.put((RouteEnum.ADD, node_id, ttl)) self.queue.put((RouteEnum.ADD, node_id, ttl))
current = time.monotonic() current = time.monotonic()
else: else:
if (time.monotonic() - current) >= DEAD_TIME: if (time.monotonic() - current) >= self.dead:
self.queue.put((RouteEnum.DEL, node_id, None)) self.queue.put((RouteEnum.DEL, node_id, None))
except Exception as e: except Exception as e:
print(f"listener error: {e}") print(f"listener error: {e}")
@ -177,27 +204,34 @@ def main() -> None:
print("core-route-monitor requires tcpdump to be installed") print("core-route-monitor requires tcpdump to be installed")
return return
desc = "core route monitor leverages tcpdump to monitor traffic and find route using TTL"
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="core route monitor", description=desc,
formatter_class=ArgumentDefaultsHelpFormatter, formatter_class=ArgumentDefaultsHelpFormatter
) )
parser.add_argument("--id", required=True, parser.add_argument("--src", required=True,
help="source node id for determining path")
parser.add_argument("--src", default="10.0.0.20",
help="source address for route monitoring") help="source address for route monitoring")
parser.add_argument("--dst", default="10.0.2.20", parser.add_argument("--dst", required=True,
help="destination address for route monitoring") help="destination address for route monitoring")
parser.add_argument("--session", type=int,
help="session to monitor route")
parser.add_argument("--pkt", default="icmp", choices=PACKET_CHOICES, parser.add_argument("--pkt", default="icmp", choices=PACKET_CHOICES,
help="packet type") help="packet type")
parser.add_argument("--rate", type=int, default=ROUTE_TIME,
help="rate to update route, in seconds")
parser.add_argument("--dead", type=int, default=DEAD_TIME,
help="timeout to declare path dead, in seconds")
parser.add_argument("--sdt-host", default=SDT_HOST, help="sdt host address") parser.add_argument("--sdt-host", default=SDT_HOST, help="sdt host address")
parser.add_argument("--sdt-port", type=int, default=SDT_PORT, help="sdt port") parser.add_argument("--sdt-port", type=int, default=SDT_PORT, help="sdt port")
args = parser.parse_args() args = parser.parse_args()
monitor = RouterMonitor( monitor = RouterMonitor(
args.id, args.session,
args.src, args.src,
args.dst, args.dst,
args.pkt, args.pkt,
args.rate,
args.dead,
args.sdt_host, args.sdt_host,
args.sdt_port, args.sdt_port,
) )