diff options
Diffstat (limited to 'ryu/services/protocols/bgp/operator/commands')
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 + }) |