mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 20:28:43 +00:00
201 lines
7.4 KiB
Python
201 lines
7.4 KiB
Python
|
import cbor
|
||
|
import json
|
||
|
import sys
|
||
|
import os
|
||
|
import socket, struct
|
||
|
import datetime
|
||
|
|
||
|
|
||
|
class Command:
|
||
|
num = -1
|
||
|
def addr_to_str(self, addr):
|
||
|
return socket.inet_ntoa(struct.pack('!L', addr))
|
||
|
|
||
|
def print_answer(self, answer):
|
||
|
print(answer)
|
||
|
|
||
|
class Memory(Command):
|
||
|
num = 1
|
||
|
def nums_to_str(self, answer, key):
|
||
|
|
||
|
e = answer["show_memory:message"]["body"][key]["effective"]
|
||
|
o = answer["show_memory:message"]["body"][key]["overhead"]
|
||
|
j_e = " B"
|
||
|
j_o = " B"
|
||
|
if e > 9999:
|
||
|
e = e/1000
|
||
|
j_e = "kB"
|
||
|
if o > 9999:
|
||
|
o = o/1000
|
||
|
j_o = "kB"
|
||
|
return f"{e:>7} {j_e} {o:>7} {j_o}"
|
||
|
|
||
|
def print_answer(self, answer):
|
||
|
print()
|
||
|
print("BIRD memory usage")
|
||
|
keys = answer["show_memory:message"]["body"].keys()
|
||
|
first_column_width = len("route attributes ")
|
||
|
print(" " * (first_column_width+4), "Effective ", "Overhead")
|
||
|
for key in keys:
|
||
|
name = key.replace("_", " ")
|
||
|
print(name,":", " "*(first_column_width - len(name)), self.nums_to_str(answer, key))
|
||
|
|
||
|
|
||
|
class Status(Command):
|
||
|
num = 0
|
||
|
|
||
|
def print_answer(self, answer):
|
||
|
print(answer)
|
||
|
print()
|
||
|
print("BIRD", answer["show_status:message"]["version"])
|
||
|
for key in answer["show_status:message"]["body"].keys():
|
||
|
name = key.replace("_", " ")
|
||
|
if key == "router_id":
|
||
|
print(name, self.addr_to_str( answer["show_status:message"]["body"][key]))
|
||
|
elif key in "server_time last_reboot last_reconfiguration":
|
||
|
print(name, datetime.datetime.fromtimestamp(answer["show_status:message"]["body"][key]))
|
||
|
else:
|
||
|
print(name, answer["show_status:message"]["body"][key])
|
||
|
print(answer["show_status:message"]["state"])
|
||
|
|
||
|
|
||
|
class Symbols(Command):
|
||
|
num = 2
|
||
|
|
||
|
def print_answer(self, answer):
|
||
|
print()
|
||
|
for item in answer["show_symbols:message"]["table"]:
|
||
|
print(f"{item['name']:<15} {item['type']}")
|
||
|
|
||
|
|
||
|
class Ospf(Command):
|
||
|
num = 3
|
||
|
|
||
|
def print_lsa_router(self, area):
|
||
|
print ("\trouter", self.addr_to_str(area['router']))
|
||
|
print("\t\tdistance", area['distance'])
|
||
|
if ('vlink' in area.keys()):
|
||
|
for vlink in area['vlink']:
|
||
|
print(f"\t\tvlink {self.addr_to_str( vlink['vlink'])} metric {vlink['metric']}")
|
||
|
if ('router_metric' in area.keys()):
|
||
|
for router in area['router_metric']:
|
||
|
print(f"\t\trouter {self.addr_to_str( router['router'])} metric {router['metric']}")
|
||
|
for network in area['network']:
|
||
|
addr = self.addr_to_str(network['network'])
|
||
|
if('nif' in network):
|
||
|
print(f"\t\tnetwork [{addr}-{network['nif']}] metric {network['metric']}")
|
||
|
elif('len' in area.keys()):
|
||
|
print(f"\t\tnetwork {addr}/{network['len']} metric {network['metric']}")
|
||
|
else:
|
||
|
print(f"\t\tnetwork [{addr}] metric {network['metric']}")
|
||
|
if ('stubnet' in area.keys()):
|
||
|
for stubnet in area['stubnet']:
|
||
|
print(f"\t\tstubnet {self.addr_to_str(stubnet['stubnet'])}/{stubnet['len']} metric {stubnet['metric']}")
|
||
|
|
||
|
def print_lsa_network(self, area):
|
||
|
if ('ospf2' in area.keys()):
|
||
|
print(f"\tnetwork {self.addr_to_str(area['ospf2']['network'])}/{area['ospf2']['optx']}")
|
||
|
print(f"\t\tdr {self.addr_to_str(area['ospf2']['dr'])}")
|
||
|
elif ('ospf' in area.keys()):
|
||
|
print(f"\tnetwork [{self.addr_to_str(area['ospf']['network'])}-{area['ospf']['lsa_id']}]")
|
||
|
print("\t\tdistance", area['distance'])
|
||
|
for router in area['routers']:
|
||
|
print(f"\t\trouter {self.addr_to_str(router['router'])}")
|
||
|
|
||
|
def print_lsa_sum_net(self, area):
|
||
|
print(f"\t\txnetwork {area['net']} metric {area['metric']}")
|
||
|
|
||
|
def print_lsa_sum_rt(self, area):
|
||
|
print(f"\t\txrouter {self.addr_to_str(area['router'])} metric {area['metric']}")
|
||
|
|
||
|
def print_lsa_external(self, area):
|
||
|
if('lsa_type_num' in area.keys()):
|
||
|
print(f"\t\t{area['lsa_type']} {self.addr_to_str(area['rt_net'])} metric{area[lsa_type_num]} {area['metric']}%s%s")
|
||
|
else:
|
||
|
print(f"\t\t{area['lsa_type']} {self.addr_to_str(area['rt_net'])} metric {area['metric']}{area['via']}{area['tag']}")
|
||
|
|
||
|
def print_lsa_prefix(self, area):
|
||
|
for prefix in area['prefixes']:
|
||
|
if 'metric' in prefix.keys():
|
||
|
print(f"\t\tstubnet {self.addr_to_str(prefix['stubnet'])} metric {prefix['metric']}")
|
||
|
|
||
|
def print_answer(self, answer):
|
||
|
print()
|
||
|
if ("error" in answer["show_ospf:message"].keys()):
|
||
|
print("error: ", answer["show_ospf:message"]["error"])
|
||
|
return
|
||
|
if ("not implemented" in answer["show_ospf:message"].keys()):
|
||
|
print("not implemented: ", answer["show_ospf:message"]["not implemented"])
|
||
|
return
|
||
|
for area in answer["show_ospf:message"]["areas"]:
|
||
|
if 'area' in area.keys():
|
||
|
print ("area", self.addr_to_str(area['area']))
|
||
|
print()
|
||
|
if 'lsa_router' in area.keys():
|
||
|
self.print_lsa_router(area['lsa_router'])
|
||
|
elif 'lsa_network' in area.keys():
|
||
|
self.print_lsa_network(area['lsa_network'])
|
||
|
elif 'lsa_sum_net' in area.keys():
|
||
|
self.print_lsa_sum_net(area['lsa_sum_net'])
|
||
|
elif 'lsa_sum_rt' in area.keys():
|
||
|
self.print_lsa_sum_rt(area['lsa_sum_rt'])
|
||
|
elif 'lsa_external' in area.keys():
|
||
|
self.print_lsa_external(area['lsa_external'])
|
||
|
elif 'lsa_prefix' in area.keys():
|
||
|
self.print_lsa_prefix(area['lsa_prefix'])
|
||
|
if('asbrs' in area.keys()):
|
||
|
for asbr in area['asbrs']:
|
||
|
if('other_ABSRs' in asbr.keys()):
|
||
|
print("other ASBRs")
|
||
|
print("other ASBRs")
|
||
|
print(f"\trouter {self.addr_to_str(asbr['router'])}")
|
||
|
|
||
|
command_dictionary = {"status":0, "memory":1, "symbols":2, "ospf":3}
|
||
|
|
||
|
def get_command_class(string):
|
||
|
if string == "status":
|
||
|
return Status()
|
||
|
if string == "memory":
|
||
|
return Memory()
|
||
|
if string == "symbols":
|
||
|
return Symbols()
|
||
|
if string == "ospf":
|
||
|
return Ospf()
|
||
|
raise Exception(f"Command {string} not known. Expected status, memory, symbols or ospf")
|
||
|
|
||
|
def run_on_machine(dev, cmd):
|
||
|
ws = os.system(f"ip netns exec {dev} {cmd}")
|
||
|
if os.WIFEXITED(ws):
|
||
|
ec = os.WEXITSTATUS(ws)
|
||
|
else:
|
||
|
ec = False
|
||
|
|
||
|
if ec != 0:
|
||
|
raise Exception(f"Command {cmd} exited with exit code {ws}")
|
||
|
|
||
|
|
||
|
arguments = sys.argv
|
||
|
if (len(sys.argv) <= 2):
|
||
|
raise Exception("Expected command, no argunents given.")
|
||
|
if (len(sys.argv) == 3):
|
||
|
raise Exception(f"only one ({sys.argv[2]}) command given, that is not implemented")
|
||
|
if(sys.argv[2] != "show"):
|
||
|
raise Exception(f"Expected 'dev show status/memory/symbols/ospf', unknown {sys.argv[2]}.")
|
||
|
comm = get_command_class(sys.argv[3])
|
||
|
|
||
|
command = {"command:do":{"command":comm.num, "args":[]}}
|
||
|
for i in range (4, len(sys.argv)):
|
||
|
command["command:do"]["args"].append({"arg": sys.argv[i]})
|
||
|
print(command)
|
||
|
|
||
|
with open(os.getcwd()+"/command.cbor", "wb") as of:
|
||
|
cbor.dump(command, of)
|
||
|
|
||
|
run_on_machine(sys.argv[1], f"cat command.cbor | sudo socat UNIX-CONNECT:{os.getcwd()}/bird-yang.ctl STDIO > answer.cbor")
|
||
|
|
||
|
|
||
|
with open("answer.cbor", "br") as cbor_file:
|
||
|
answer = cbor.load(cbor_file)
|
||
|
|
||
|
comm.print_answer(answer)
|