summaryrefslogtreecommitdiffhomepage
path: root/ryu/services/protocols/bgp/operator/commands
diff options
context:
space:
mode:
Diffstat (limited to 'ryu/services/protocols/bgp/operator/commands')
-rw-r--r--ryu/services/protocols/bgp/operator/commands/clear.py54
-rw-r--r--ryu/services/protocols/bgp/operator/commands/responses.py34
-rw-r--r--ryu/services/protocols/bgp/operator/commands/root.py11
-rw-r--r--ryu/services/protocols/bgp/operator/commands/set.py65
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/__init__.py56
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/count.py53
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/importmap.py42
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/memory.py89
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/neighbor.py135
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/rib.py65
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/route_formatter_mixin.py43
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/vrf.py162
12 files changed, 809 insertions, 0 deletions
diff --git a/ryu/services/protocols/bgp/operator/commands/clear.py b/ryu/services/protocols/bgp/operator/commands/clear.py
new file mode 100644
index 00000000..be4a9e9d
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/clear.py
@@ -0,0 +1,54 @@
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+
+
+class BGPCmd(Command):
+ help_msg = ('reset bgp connections, no afi/safi is '
+ 'treated as - all supported address-families')
+ param_help_msg = '<peer_ip> [<afi> <safi>]'
+ command = 'bgp'
+
+ def __init__(self, *args, **kwargs):
+ super(BGPCmd, self).__init__(*args, **kwargs)
+
+ self.subcommands = {'all': self.All}
+
+ def action(self, params):
+ if len(params) == 0:
+ return WrongParamResp()
+ peer = afi = safi = None
+ try:
+ peer = params[0]
+ afi = params[1]
+ safi = params[2]
+ except IndexError:
+ pass
+
+ self.api.route_refresh(peer, afi, safi)
+ return CommandsResponse(STATUS_OK, '')
+
+ class All(Command):
+ help_msg = 'reset all connections'
+ param_help_msg = '[<afi=> <safi=>]'
+ command = 'all'
+
+ def action(self, params):
+ peer = afi = safi = None
+ try:
+ afi = params[0]
+ safi = params[1]
+ except IndexError:
+ pass
+
+ self.api.route_refresh(peer, afi, safi)
+ return CommandsResponse(STATUS_OK, '')
+
+
+class ClearCmd(Command):
+ help_msg = 'allows to reset BGP connections'
+ command = 'clear'
+
+ subcommands = {'bgp': BGPCmd}
diff --git a/ryu/services/protocols/bgp/operator/commands/responses.py b/ryu/services/protocols/bgp/operator/commands/responses.py
new file mode 100644
index 00000000..f90dd98e
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/responses.py
@@ -0,0 +1,34 @@
+# 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.
+
+"""
+ Defines classes related to incorrect parameters.
+"""
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.internal_api import WrongParamError
+
+
+class WrongParamResp(object):
+ def __new__(cls, e=None):
+ return cls.wrong_param_resp_factory(e)
+
+ @staticmethod
+ def wrong_param_resp_factory(e=None):
+ if not e:
+ e = WrongParamError()
+ desc = 'wrong parameters: %s' % str(e)
+
+ return CommandsResponse(STATUS_ERROR, desc)
diff --git a/ryu/services/protocols/bgp/operator/commands/root.py b/ryu/services/protocols/bgp/operator/commands/root.py
new file mode 100644
index 00000000..cf6d5cd4
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/root.py
@@ -0,0 +1,11 @@
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.commands.clear import ClearCmd
+from ryu.services.protocols.bgp.operator.commands.set import SetCmd
+from ryu.services.protocols.bgp.operator.commands.show import ShowCmd
+
+
+class RootCmd(Command):
+ subcommands = {
+ 'show': ShowCmd,
+ 'set': SetCmd,
+ 'clear': ClearCmd}
diff --git a/ryu/services/protocols/bgp/operator/commands/set.py b/ryu/services/protocols/bgp/operator/commands/set.py
new file mode 100644
index 00000000..b28a80ac
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/set.py
@@ -0,0 +1,65 @@
+import logging
+
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+
+
+class LoggingCmd(Command):
+ command = 'logging'
+ help_msg = 'turn on/off logging at current level'
+
+ def __init__(self, *args, **kwargs):
+ super(LoggingCmd, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'on': self.On,
+ 'off': self.Off,
+ 'level': self.Level
+ }
+
+ class On(Command):
+ command = 'on'
+ help_msg = 'turn-on the logging at the current level'
+
+ def action(self, params):
+ logging.getLogger('bgpspeaker').addHandler(self.api.log_handler)
+ return CommandsResponse(STATUS_OK, True)
+
+ class Off(Command):
+ command = 'off'
+ help_msg = 'turn-off the logging'
+
+ def action(self, params):
+ logging.getLogger('bgpspeaker').removeHandler(self.api.log_handler)
+ return CommandsResponse(STATUS_OK, True)
+
+ class Level(Command):
+ command = 'level'
+ help_msg = 'set logging level'
+ param_help_msg = '[debug/info/error]'
+
+ def action(self, params):
+ lvls = {
+ 'debug': logging.DEBUG,
+ 'error': logging.ERROR,
+ 'info': logging.INFO
+ }
+ if len(params) == 1 and params[0] in lvls:
+ self.api.log_handler.setLevel(
+ lvls.get(params[0], logging.ERROR)
+ )
+ return CommandsResponse(STATUS_OK, True)
+ else:
+ return WrongParamResp()
+
+
+class SetCmd(Command):
+ help_msg = 'allows to set runtime settings'
+ command = 'set'
+
+ subcommands = {'logging': LoggingCmd}
+
+ def action(self, params):
+ return CommandsResponse(STATUS_OK, True)
diff --git a/ryu/services/protocols/bgp/operator/commands/show/__init__.py b/ryu/services/protocols/bgp/operator/commands/show/__init__.py
new file mode 100644
index 00000000..388a1e7a
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/__init__.py
@@ -0,0 +1,56 @@
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.show import count
+from ryu.services.protocols.bgp.operator.commands.show import importmap
+from ryu.services.protocols.bgp.operator.commands.show import memory
+from ryu.services.protocols.bgp.operator.commands.show import neighbor
+from ryu.services.protocols.bgp.operator.commands.show import rib
+from ryu.services.protocols.bgp.operator.commands.show import vrf
+
+
+class ShowCmd(Command):
+ help_msg = 'shows runtime state information'
+ command = 'show'
+
+ def __init__(self, *args, **kwargs):
+ super(ShowCmd, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'count': self.Count,
+ 'logging': self.Logging,
+ 'rib': self.Rib,
+ 'vrf': self.Vrf,
+ 'memory': self.Memory,
+ 'neighbor': self.Neighbor,
+ 'importmap': self.Importmap
+ }
+
+ def action(self, params):
+ return CommandsResponse(STATUS_OK, None)
+
+ class Count(count.Count):
+ pass
+
+ class Rib(rib.Rib):
+ pass
+
+ class Vrf(vrf.Vrf):
+ pass
+
+ class Importmap(importmap.Importmap):
+ pass
+
+ class Memory(memory.Memory):
+ pass
+
+ class Neighbor(neighbor.Neighbor):
+ pass
+
+ class Logging(Command):
+ command = 'logging'
+ help_msg = 'shows if logging is on/off and current logging level.'
+
+ def action(self, params):
+ ret = {'logging': self.api.check_logging(),
+ 'level': self.api.check_logging_level()}
+ return CommandsResponse(STATUS_OK, ret)
diff --git a/ryu/services/protocols/bgp/operator/commands/show/count.py b/ryu/services/protocols/bgp/operator/commands/show/count.py
new file mode 100644
index 00000000..f0cd5b89
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/count.py
@@ -0,0 +1,53 @@
+import logging
+
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+
+LOG = logging.getLogger('bgpspeaker.operator.commands.show.count')
+
+
+class Count(Command):
+ help_msg = 'show counters'
+ param_help_msg = '<vpn-name> <route-family>{ipv4, ipv6}'
+ command = 'count'
+ cli_resp_line_template = 'BGP route count for VPN {0} is {1}\n'
+
+ def __init__(self, *args, **kwargs):
+ super(Count, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'all': self.All
+ }
+
+ def action(self, params):
+ if len(params) < 1:
+ return CommandsResponse(STATUS_ERROR, 'Not enough params')
+ else:
+ vrf_name = params[0]
+ if len(params) == 2:
+ vrf_rf = params[1]
+ else:
+ vrf_rf = 'ipv4'
+
+ from ryu.services.protocols.bgp.operator.internal_api import \
+ WrongParamError
+ try:
+ return CommandsResponse(
+ STATUS_OK,
+ self.api.count_single_vrf_routes(vrf_name, vrf_rf)
+ )
+ except WrongParamError as e:
+ return WrongParamResp(e)
+
+ class All(Command):
+ help_msg = 'shows number of routes for all VRFs'
+ command = 'all'
+ cli_resp_line_template = 'BGP route count for VPN {0} is {1}\n'
+
+ def action(self, params):
+ if len(params) > 0:
+ return WrongParamResp()
+ return CommandsResponse(STATUS_OK, self.api.count_all_vrf_routes())
diff --git a/ryu/services/protocols/bgp/operator/commands/show/importmap.py b/ryu/services/protocols/bgp/operator/commands/show/importmap.py
new file mode 100644
index 00000000..d33c6706
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/importmap.py
@@ -0,0 +1,42 @@
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+
+from ryu.services.protocols.bgp.operator.views.bgp import CoreServiceDetailView
+
+
+class Importmap(Command):
+ help_msg = 'show importmaps'
+ param_help_msg = 'all | <name>'
+ command = 'importmap'
+
+ def __init__(self, *args, **kwargs):
+ super(Importmap, self).__init__(*args, **kwargs)
+
+ def action(self, params):
+ if len(params) != 1:
+ return WrongParamResp()
+
+ core_service = self.api.get_core_service()
+ core_service_view = CoreServiceDetailView(core_service)
+ importmap_manager = core_service_view.rel('importmap_manager')
+ importmaps_view = importmap_manager.rel('importmaps')
+
+ importmap_name = params[0]
+ if importmap_name == 'all':
+ encoded = importmaps_view.encode()
+ else:
+ encoded = importmaps_view.encode().get(importmap_name)
+ if encoded is None:
+ return CommandsResponse(
+ STATUS_ERROR,
+ 'Wrong importmap name.'
+ )
+
+ return CommandsResponse(
+ STATUS_OK,
+ encoded
+ )
diff --git a/ryu/services/protocols/bgp/operator/commands/show/memory.py b/ryu/services/protocols/bgp/operator/commands/show/memory.py
new file mode 100644
index 00000000..c519adff
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/memory.py
@@ -0,0 +1,89 @@
+import gc
+import sys
+
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+
+
+class Memory(Command):
+ help_msg = 'show memory information'
+ command = 'memory'
+
+ def __init__(self, *args, **kwargs):
+ super(Memory, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'summary': self.Summary}
+
+ class Summary(Command):
+ help_msg = 'shows total memory used and how it is getting used'
+ command = 'summary'
+
+ def action(self, params):
+ count = {}
+ size = {}
+ total_size = 0
+ unreachable = gc.collect()
+ for obj in gc.get_objects():
+ inst_name = type(obj).__name__
+ c = count.get(inst_name, None)
+ if not c:
+ count[inst_name] = 0
+ s = size.get(inst_name, None)
+ if not s:
+ size[inst_name] = 0
+
+ count[inst_name] += 1
+ s = sys.getsizeof(obj)
+ size[inst_name] += s
+ total_size += s
+
+ # Total size in MB
+
+ total_size = total_size / 1000000
+ ret = {
+ 'unreachable': unreachable,
+ 'total': total_size,
+ 'summary': []}
+
+ for class_name, s in size.items():
+ # Calculate size in MB
+ size_mb = s / 1000000
+ # We are only interested in class which take-up more than a MB
+ if size_mb > 0:
+ ret['summary'].append(
+ {
+ 'class': class_name,
+ 'instances': count.get(class_name, None),
+ 'size': size_mb
+ }
+ )
+
+ return CommandsResponse(STATUS_OK, ret)
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return Command.cli_resp_formatter(resp)
+ val = resp.value
+ ret = 'Unreachable objects: {0}\n'.format(
+ val.get('unreachable', None)
+ )
+ ret += 'Total memory used (MB): {0}\n'.format(
+ val.get('total', None)
+ )
+ ret += 'Classes with instances that take-up more than one MB:\n'
+ ret += '{0:<20s} {1:>16s} {2:>16s}\n'.format(
+ 'Class',
+ '#Instance',
+ 'Size(MB)'
+ )
+
+ for s in val.get('summary', []):
+ ret += '{0:<20s} {1:>16d} {2:>16d}\n'.format(
+ s.get('class', None), s.get('instances', None),
+ s.get('size', None)
+ )
+
+ return ret
diff --git a/ryu/services/protocols/bgp/operator/commands/show/neighbor.py b/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
new file mode 100644
index 00000000..2e8b8715
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
@@ -0,0 +1,135 @@
+import logging
+import pprint
+
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+from ryu.services.protocols.bgp.operator.views.bgp import CoreServiceDetailView
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_UC
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_VPN
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv6_UC
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv6_VPN
+
+LOG = logging.getLogger('bgpspeaker.operator.commands.show.summary')
+
+
+class NeighborSummary(Command):
+ help_msg = 'show summarized neighbor information'
+ command = 'summary'
+
+ def action(self, params):
+ requested_peers = []
+ if len(params) > 0:
+ requested_peers = [str(p) for p in params]
+
+ core_service = self.api.get_core_service()
+ core_service_view = CoreServiceDetailView(core_service)
+ peers_view = core_service_view.rel('peer_manager').rel('peers_summary')
+
+ def filter_requested(peer_id, peer_obj):
+ return not requested_peers or peer_id in requested_peers
+
+ peers_view.apply_filter(filter_requested)
+ ret = peers_view.encode()
+ return CommandsResponse(STATUS_OK, ret)
+
+
+class SentRoutes(Command):
+ help_msg = 'paths sent and not withdrawn to given peer'
+ command = 'sent-routes'
+ param_help_msg = '<ip_addr> <addr_family>{vpnv4, vpnv6, ipv4, ipv6, all}'
+
+ def action(self, params):
+ if len(params) != 2:
+ return WrongParamResp()
+ ip_addr, addr_family = params
+
+ if addr_family == 'ipv4':
+ rf = RF_IPv4_UC
+ elif addr_family == 'ipv6':
+ rf = RF_IPv6_UC
+ elif addr_family == 'vpnv4':
+ rf = RF_IPv4_VPN
+ elif addr_family == 'vpnv6':
+ rf = RF_IPv6_VPN
+ elif addr_family == 'all':
+ rf = None
+ else:
+ return WrongParamResp('wrong addr_family name')
+
+ ret = self._retrieve_paths(addr_family, rf, ip_addr).encode()
+ ret = {
+ path['nlri']['formatted_nlri']: path
+ for path in ret
+ }
+
+ return CommandsResponse(STATUS_OK, ret)
+
+ def _retrieve_paths(self, addr_family, route_family, ip_addr):
+ global_tables_view = self._retrieve_global_tables_view(
+ addr_family,
+ route_family
+ )
+ sent = global_tables_view.c_rel('destinations').c_rel('sent_routes')
+ sent.apply_filter(
+ lambda route: route.sent_peer.ip_address == ip_addr
+ )
+ paths = sent.c_rel('path')
+ paths.apply_filter(
+ lambda path: not path.is_withdraw
+ )
+ return paths
+
+ def _retrieve_global_tables_view(self, addr_family, route_family):
+ core_service = self.api.get_core_service()
+ core_sv = CoreServiceDetailView(core_service)
+ table_manager_view = core_sv.rel('table_manager')
+ global_tables_view = table_manager_view.rel('global_tables')
+ global_tables_view.apply_filter(
+ lambda k, v: addr_family == 'all' or k == route_family
+ )
+ return global_tables_view
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return Command.cli_resp_formatter(resp)
+
+ return '\n{0}'.format(pprint.pformat(resp.value))
+
+
+class ReceivedRoutes(SentRoutes):
+ help_msg = 'paths received and not withdrawn by given peer'
+ command = 'received-routes'
+
+ def _retrieve_paths(self, addr_family, route_family, ip_addr):
+ global_tables_view = self._retrieve_global_tables_view(
+ addr_family,
+ route_family
+ )
+ paths = global_tables_view.c_rel(
+ 'destinations'
+ ).c_rel('known_path_list')
+
+ def path_filter(path):
+ return path.source is not None and \
+ path.source.ip_address == ip_addr and \
+ not path.is_withdraw
+
+ paths.apply_filter(
+ path_filter
+ )
+ return paths
+
+
+class Neighbor(Command):
+ help_msg = 'show neighbor information'
+ command = 'neighbor'
+ subcommands = {
+ 'summary': NeighborSummary,
+ 'sent-routes': SentRoutes,
+ 'received-routes': ReceivedRoutes
+ }
diff --git a/ryu/services/protocols/bgp/operator/commands/show/rib.py b/ryu/services/protocols/bgp/operator/commands/show/rib.py
new file mode 100644
index 00000000..8469eef5
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/rib.py
@@ -0,0 +1,65 @@
+from route_formatter_mixin import RouteFormatterMixin
+
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+
+
+class RibBase(Command, RouteFormatterMixin):
+ supported_families = ['vpnv4', 'rtfilter', 'vpnv6']
+
+
+class Rib(RibBase):
+ help_msg = 'show all routes for address family (only vpnv4 supported)'
+ param_help_msg = '<address-family>'
+ command = 'rib'
+
+ def __init__(self, *args, **kwargs):
+ super(Rib, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'all': self.All}
+
+ def action(self, params):
+ if len(params) != 1 or params[0] not in self.supported_families:
+ return WrongParamResp()
+ from ryu.services.protocols.bgp.speaker.operator.internal_api \
+ import WrongParamError
+ try:
+ return CommandsResponse(
+ STATUS_OK,
+ self.api.get_single_rib_routes(params[0])
+ )
+ except WrongParamError as e:
+ return WrongParamResp(e)
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return RibBase.cli_resp_formatter(resp)
+ return cls._format_family_header() + cls._format_family(resp.value)
+
+ class All(RibBase):
+ help_msg = 'show routes for all RIBs'
+ command = 'all'
+
+ def action(self, params):
+ if len(params) != 0:
+ return WrongParamResp()
+ ret = {}
+ for family in self.supported_families:
+ ret[family] = self.api.get_single_rib_routes(family)
+ return CommandsResponse(STATUS_OK, ret)
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return RibBase.cli_resp_formatter(resp)
+ ret = cls._format_family_header()
+ for family, data in resp.value.iteritems():
+ ret += 'Family: {0}\n'.format(family)
+ ret += cls._format_family(data)
+ return ret
diff --git a/ryu/services/protocols/bgp/operator/commands/show/route_formatter_mixin.py b/ryu/services/protocols/bgp/operator/commands/show/route_formatter_mixin.py
new file mode 100644
index 00000000..ff69e069
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/route_formatter_mixin.py
@@ -0,0 +1,43 @@
+import StringIO
+
+
+class RouteFormatterMixin(object):
+
+ @classmethod
+ def _format_family_header(cls):
+ ret = ''
+ ret += ('Status codes: * valid, > best\n')
+ ret += ' {0:<3s} {1:<32s} {2:<20s} {3:<10s} {4:<20s} {5:<}\n'.format(
+ '', 'Network', 'Next Hop', 'Reason', 'Metric', 'Path')
+ return ret
+
+ @classmethod
+ def _format_family(cls, dest_list):
+ msg = StringIO.StringIO()
+
+ def _append_path_info(buff, path, is_best, show_prefix):
+ aspath = path.get('aspath')
+ bpr = path.get('bpr')
+ next_hop = path.get('nexthop')
+ med = path.get('metric')
+ # Construct path status string.
+ path_status = '*'
+ if is_best:
+ path_status += '>'
+
+ # Check if we want to show prefix.
+ prefix = ''
+ if show_prefix:
+ prefix = path.get('prefix')
+
+ # Append path info to String buffer.
+ buff.write(' {0:<3s} {1:<32s} {2:<20s} {3:<20s} {4:<10s} {5:<}\n'.
+ format(path_status, prefix, next_hop, bpr, str(med),
+ ', '.join(map(str, aspath))))
+
+ for dist in dest_list:
+ for idx, path in enumerate(dist.get('paths')):
+ _append_path_info(msg, path, path['best'], (idx == 0))
+ ret = msg.getvalue()
+ msg.close()
+ return ret
diff --git a/ryu/services/protocols/bgp/operator/commands/show/vrf.py b/ryu/services/protocols/bgp/operator/commands/show/vrf.py
new file mode 100644
index 00000000..4b34c096
--- /dev/null
+++ b/ryu/services/protocols/bgp/operator/commands/show/vrf.py
@@ -0,0 +1,162 @@
+import logging
+import pprint
+
+from ryu.services.protocols.bgp.operator.command import Command
+from ryu.services.protocols.bgp.operator.command import CommandsResponse
+from ryu.services.protocols.bgp.operator.command import STATUS_ERROR
+from ryu.services.protocols.bgp.operator.command import STATUS_OK
+from ryu.services.protocols.bgp.operator.commands.responses import \
+ WrongParamResp
+from ryu.services.protocols.bgp.operator.views.conf import ConfDetailView
+from ryu.services.protocols.bgp.operator.views.conf import ConfDictView
+from route_formatter_mixin import RouteFormatterMixin
+
+LOG = logging.getLogger('bgpspeaker.operator.commands.show.vrf')
+
+
+class Routes(Command, RouteFormatterMixin):
+ help_msg = 'show routes present for vrf'
+ param_help_msg = '<vpn-name> <route-family>(ipv4, ipv6)'
+ command = 'routes'
+
+ def __init__(self, *args, **kwargs):
+ super(Routes, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'all': self.All,
+ }
+
+ def action(self, params):
+ if len(params) != 2:
+ return WrongParamResp()
+ vrf_name = params[0]
+ vrf_rf = params[1]
+ if vrf_rf not in ('ipv4', 'ipv6'):
+ return WrongParamResp('route-family not one of (ipv4, ipv6)')
+
+ from ryu.services.protocols.bgp.speaker.operator.internal_api import \
+ WrongParamError
+
+ try:
+ return CommandsResponse(
+ STATUS_OK,
+ self.api.get_single_vrf_routes(vrf_name, vrf_rf)
+ )
+ except WrongParamError as e:
+ return CommandsResponse(
+ STATUS_ERROR,
+ 'wrong parameters: %s' % str(e)
+ )
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return super(Routes, cls).cli_resp_formatter(resp)
+ return cls._format_family_header() + cls._format_family(resp.value)
+
+ class All(Command, RouteFormatterMixin):
+ help_msg = 'show routes for all VRFs'
+ command = 'all'
+
+ def action(self, params):
+ if len(params) != 0:
+ return WrongParamResp()
+ return CommandsResponse(
+ STATUS_OK,
+ self.api.get_all_vrf_routes()
+ )
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return Command.cli_resp_formatter(resp)
+ ret = cls._format_family_header()
+ for family, data in resp.value.iteritems():
+ ret += 'VPN: {0}\n'.format(family)
+ ret += cls._format_family(data)
+ return ret
+
+
+class CountRoutesMixin(object):
+ def _count_routes(self, vrf_name, vrf_rf):
+ return len(self.api.get_single_vrf_routes(vrf_name, vrf_rf))
+
+
+class Summary(Command, CountRoutesMixin):
+ help_msg = 'show configuration and summary of vrf'
+ param_help_msg = '<rd> <route_family>| all'
+ command = 'summary'
+
+ def __init__(self, *args, **kwargs):
+ super(Summary, self).__init__(*args, **kwargs)
+ self.subcommands = {
+ 'all': self.All
+ }
+
+ def action(self, params):
+ if len(params) == 0:
+ return WrongParamResp('Not enough params')
+
+ vrf_confs = self.api.get_vrfs_conf()
+ if len(params) < 2:
+ vrf_rf = 'ipv4'
+ else:
+ vrf_rf = params[1]
+
+ vrf_key = params[0], vrf_rf
+
+ if vrf_key in vrf_confs:
+ view = ConfDetailView(vrf_confs[vrf_key])
+ encoded = view.encode()
+ encoded['routes_count'] = self._count_routes(params[0], vrf_rf)
+ else:
+ return WrongParamResp('No vrf matched by %s' % str(vrf_key))
+
+ return CommandsResponse(
+ STATUS_OK,
+ encoded
+ )
+
+ @classmethod
+ def cli_resp_formatter(cls, resp):
+ if resp.status == STATUS_ERROR:
+ return Command.cli_resp_formatter(resp)
+ return pprint.pformat(resp.value)
+
+ class All(Command, CountRoutesMixin):
+ command = 'all'
+ help_msg = 'shows all vrfs configurations and summary'
+
+ def action(self, params):
+ vrf_confs = self.api.get_vrfs_conf()
+ view = ConfDictView(vrf_confs)
+ encoded = view.encode()
+ for vrf_key, conf in encoded.iteritems():
+ vrf_name, vrf_rf = vrf_key
+ conf['routes_count'] = self._count_routes(
+ vrf_name,
+ vrf_rf
+ )
+
+ encoded = {str(k): v for k, v in encoded.iteritems()}
+ return CommandsResponse(
+ STATUS_OK,
+ encoded
+ )
+
+ def _count_routes(self, vrf_name, vrf_rf):
+ return len(self.api.get_single_vrf_routes(vrf_name, vrf_rf))
+
+
+class Vrf(Routes):
+ """Main node for vrf related commands. Acts also as Routes node (that's why
+ it inherits from it) for legacy reasons.
+ """
+ help_msg = 'vrf related commands subtree'
+ command = 'vrf'
+
+ def __init__(self, *args, **kwargs):
+ super(Vrf, self).__init__(*args, **kwargs)
+ self.subcommands.update({
+ 'routes': Routes,
+ 'summary': Summary
+ })