Files
osrg-gobgp/cli/gobgpcli
T
2015-01-16 09:27:07 +09:00

241 lines
9.3 KiB
Python
Executable File

#!/usr/bin/env python
#
# Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
#
# 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.
#
# Examples
#
# - get the state of neighbors
# $ gobgpcli show neighbors
# - get the state of a neighbor
# $ gobgpcli show neighbor 10.0.0.2
# - get the local rib of a neighbor
# $ gobgpcli show neighbor 10.0.0.2 local
# - reset
# $ gobgpcli reset neighbor 10.0.0.2
# - softresetin
# $ gobgpcli softresetin neighbor 10.0.0.2
# - softresetout
# $ gobgpcli softresetout neighbor 10.0.0.2
# - shutdown
# $ gobgpcli shutdown neighbor 10.0.0.2
from optparse import OptionParser
import requests
import sys
import inspect
import json
from datetime import timedelta
class Action(object):
def __init__(self, command, options, args):
super(Action, self).__init__()
self.command = command
self.options = options
self.args = args
self.base_url = self.options.url + ":" + str(self.options.port) + "/v1/bgp"
def __call__(self):
if len(self.args) != 1:
return 1
r = requests.post(self.base_url + "/neighbor/" + self.args[0] + "/" + self.command)
if r.status_code == requests.codes.ok:
print "Succeed"
else:
print "Failed"
return 0
class Show(object):
def __init__(self, _command, options, args):
super(Show, self).__init__()
self.options = options
self.args = args
self.base_url = self.options.url + ":" + str(self.options.port) + "/v1/bgp"
def __call__(self):
if len(self.args) == 0:
return 1
for f in inspect.getmembers(self, inspect.ismethod):
func_name = f[0]
if func_name == "do_" + self.args[0]:
return f[1]()
return 1
def _neighbors(self, neighbor=None):
capdict = {1: "MULTIPROTOCOL",
2: "ROUTE_REFRESH",
4: "CARRYING_LABEL_INFO",
64: "GRACEFUL_RESTART",
65: "FOUR_OCTET_AS_NUMBER",
70: "ENHANCED_ROUTE_REFRESH",
128: "ROUTE_REFRESH_CISCO"}
r = requests.get(self.base_url + "/neighbors")
neighbors = r.json()
if self.options.debug:
print neighbors
return 0
for n in sorted(neighbors, key=lambda n: n["conf"]["remote_ip"]):
if neighbor is not None and neighbor != n["conf"]["remote_ip"]:
continue
print("BGP neighbor is {:s}, remote AS {:d}".format(n["conf"]["remote_ip"], n["conf"]["remote_as"]))
print(" BGP version 4, remote router ID {:s}".format(n["conf"]["id"]))
print(" BGP state = {:s}, up for {:s}".format(n["info"]["bgp_state"], str(timedelta(seconds=n["info"]["uptime"]))))
print(" Neighbor capabilities:")
allcap = set(n["conf"]["RemoteCap"]) | set(n["conf"]["LocalCap"])
for i in sorted(allcap):
if i in capdict:
k = capdict[i]
else:
k = "UNKNOWN (" + str(i) + ")"
r = ""
if i in n["conf"]["LocalCap"]:
r += "advertised"
if i in n["conf"]["RemoteCap"]:
if len(r) != 0:
r += " and "
r += "received"
print(" {:s}: {:s}".format(k, r))
print(" Message statistics:")
print(" Sent Rcvd")
print(" Opens: {:>10d} {:>10d}".format(n["info"]["open_message_out"], n["info"]["open_message_in"]))
print(" Notifications: {:>10d} {:>10d}".format(n["info"]["notification_out"], n["info"]["notification_in"]))
print(" Updates: {:>10d} {:>10d}".format(n["info"]["update_message_out"], n["info"]["update_message_in"]))
print(" Keepalives: {:>10d} {:>10d}".format(n["info"]["keepalive_message_out"], n["info"]["keepalive_message_in"]))
print(" Route Refesh: {:>10d} {:>10d}".format(n["info"]["refresh_message_out"], n["info"]["refresh_message_in"]))
print(" Total: {:>10d} {:>10d}".format(n["info"]["total_message_out"], n["info"]["total_message_in"]))
print("")
return 0
def do_neighbors(self):
if len(self.args) != 1:
return 1
return self._neighbors()
def _format_attrs(self, attrlist):
attrs = []
for a in attrlist:
if a["Type"] == "BGP_ATTR_TYPE_NEXT_HOP":
pass
elif a["Type"] == "BGP_ATTR_TYPE_AS_PATH":
pass
elif a["Type"] == "BGP_ATTR_TYPE_ORIGIN":
attrs.append({"Origin": a["Value"]})
elif a["Type"] == "BGP_ATTR_TYPE_MULTI_EXIT_DISC":
attrs.append({"Med": a["Metric"]})
elif a["Type"] == "BGP_ATTR_TYPE_LOCAL_PREF":
attrs.append({"LocalPref": a["Pref"]})
elif a["Type"] == "BGP_ATTR_TYPE_ATOMIC_AGGREGATE":
attrs.append("AtomicAggregate")
elif a["Type"] == "BGP_ATTR_TYPE_AGGREGATE":
attrs.append({"Aggregate": {"AS": a["AS"], "Address": a["Address"]}})
elif a["Type"] == "BGP_ATTR_TYPE_COMMUNITIES":
wellknown = {
0xffff0000: "planned-shut",
0xffff0001: "accept-own",
0xffff0002: "ROUTE_FILTER_TRANSLATED_v4",
0xffff0003: "ROUTE_FILTER_v4",
0xffff0004: "ROUTE_FILTER_TRANSLATED_v6",
0xffff0005: "ROUTE_FILTER_v6",
0xffff0006: "LLGR_STALE",
0xffff0007: "NO_LLGR",
0xFFFFFF01: "NO_EXPORT",
0xFFFFFF02: "NO_ADVERTISE",
0xFFFFFF03: "NO_EXPORT_SUBCONFED",
0xFFFFFF04: "NOPEER"}
l = []
for v in a["Value"]:
if v in wellknown:
l.append(wellknown[v])
else:
l.append(str((0xffff0000 & v) >> 16) + ":" + str(0xffff & v))
attrs.append({"Community": l})
elif a["Type"] == "BGP_ATTR_TYPE_ORIGINATOR_ID":
attrs.append({"Originator": a["Address"]})
elif a["Type"] == "BGP_ATTR_TYPE_CLUSTER_LIST":
attrs.append({"Cluster": a["Address"]})
elif a["Type"] == "BGP_ATTR_TYPE_MP_REACH_NLRI":
pass
elif a["Type"] == "BGP_ATTR_TYPE_MP_UNREACH_NLRI":
pass
elif a["Type"] == "BGP_ATTR_TYPE_AS4_PATH":
pass
else:
attrs.append({a["Type"]: a["Value"]})
return attrs
def do_neighbor(self):
if len(self.args) != 2 and len(self.args) != 3:
return 1
if len(self.args) == 2:
return self._neighbors(neighbor=self.args[1])
if self.args[2] == "local":
self.args[2] = "local-rib"
r = requests.get(self.base_url + "/neighbor/" + self.args[1] + "/" + self.args[2])
if self.options.debug:
print r.json()
return 0
print(" Network Next Hop AS_PATH Attrs")
for d in r.json()["Destinations"]:
for p in d["Paths"]:
nexthop = ""
AS = ""
for a in p["Attrs"]:
if a["Type"] == "BGP_ATTR_TYPE_AS_PATH":
AS = a["AsPath"]
if p["Best"] == "true":
header = "*>"
else:
header = "*"
print("{:s} {:s} {:s} {:s} {:s}".format(header, p["Network"],
p["Nexthop"], AS, self._format_attrs(p["Attrs"])))
return 0
def main():
usage = "gobpgcli [options] <command> <args>"
parser = OptionParser(usage)
parser.add_option("-u", "--url", dest="url", default="http://localhost",
help="specifying an url (http://localhost by default)")
parser.add_option("-p", "--port", dest="port", default=8080,
help="specifying a port (8080 by default)")
parser.add_option("-d", "--debug", dest="debug", action="store_true",
help="dump raw json")
(options, args) = parser.parse_args()
commands = {"show": Show, "reset": Action, "shutdown": Action, "softreset": Action, "softresetin": Action, "softresetout": Action}
if len(args) == 0:
parser.print_help()
sys.exit(1)
if args[0] not in commands:
parser.print_help()
sys.exit(1)
ret = commands[args[0]](args[0], options, args[1:])()
if ret != 0:
parser.print_help()
sys.exit(1)
if __name__ == "__main__":
main()