1import logging 2from time import strftime 3 4from ryu.services.protocols.bgp.operator.command import Command 5from ryu.services.protocols.bgp.operator.command import CommandsResponse 6from ryu.services.protocols.bgp.operator.command import STATUS_ERROR 7from ryu.services.protocols.bgp.operator.command import STATUS_OK 8from ryu.services.protocols.bgp.operator.commands.responses import \ 9 WrongParamResp 10from ryu.services.protocols.bgp.operator.views.bgp import CoreServiceDetailView 11from ryu.lib.packet.bgp import RF_IPv4_UC 12from ryu.lib.packet.bgp import RF_IPv6_UC 13from ryu.lib.packet.bgp import RF_IPv4_VPN 14from ryu.lib.packet.bgp import RF_IPv6_VPN 15from ryu.lib.packet.bgp import BGP_ATTR_ORIGIN_IGP 16from ryu.lib.packet.bgp import BGP_ATTR_ORIGIN_EGP 17from ryu.lib.packet.bgp import BGP_ATTR_ORIGIN_INCOMPLETE 18 19LOG = logging.getLogger('bgpspeaker.operator.commands.show.neighbor') 20 21 22class NeighborSummary(Command): 23 help_msg = 'show summarized neighbor information' 24 command = 'summary' 25 26 def action(self, params): 27 requested_peers = [] 28 if len(params) > 0: 29 requested_peers = [str(p) for p in params] 30 31 core_service = self.api.get_core_service() 32 core_service_view = CoreServiceDetailView(core_service) 33 peers_view = core_service_view.rel('peer_manager').rel('peers_summary') 34 35 def filter_requested(peer_id, peer_obj): 36 return not requested_peers or peer_id in requested_peers 37 38 peers_view.apply_filter(filter_requested) 39 ret = peers_view.encode() 40 return CommandsResponse(STATUS_OK, ret) 41 42 43class SentRoutes(Command): 44 help_msg = 'paths sent and not withdrawn to given peer' 45 command = 'sent-routes' 46 param_help_msg = '<ip_addr> <addr_family>{vpnv4, vpnv6, ipv4, ipv6, all}' 47 fmtstr = ' {0:<2s} {1:<19s} {2:<32s} {3:<8s} {4:<20s} '\ 48 '{5:<6s} {6:<6s} {7:<}\n' 49 50 def action(self, params): 51 if len(params) != 2: 52 return WrongParamResp() 53 ip_addr, addr_family = params 54 55 if addr_family == 'ipv4': 56 rf = RF_IPv4_UC 57 elif addr_family == 'ipv6': 58 rf = RF_IPv6_UC 59 elif addr_family == 'vpnv4': 60 rf = RF_IPv4_VPN 61 elif addr_family == 'vpnv6': 62 rf = RF_IPv6_VPN 63 elif addr_family == 'all': 64 rf = None 65 else: 66 return WrongParamResp('wrong addr_family name') 67 68 ret = self._retrieve_paths(addr_family, rf, ip_addr).encode() 69 return CommandsResponse(STATUS_OK, ret) 70 71 def _retrieve_paths(self, addr_family, route_family, ip_addr): 72 peer_view = self._retrieve_peer_view(ip_addr) 73 adj_rib_out = peer_view.c_rel('adj_rib_out') 74 adj_rib_out.apply_filter(lambda k, v: addr_family == 'all' or 75 v.path.route_family == route_family) 76 return adj_rib_out 77 78 def _retrieve_peer_view(self, ip_addr): 79 core_service = self.api.get_core_service() 80 core_sv = CoreServiceDetailView(core_service) 81 peers_view = core_sv.rel('peer_manager').rel('peers') 82 peers_view.apply_filter(lambda k, v: v.ip_address == ip_addr) 83 return peers_view 84 85 @classmethod 86 def cli_resp_formatter(cls, resp): 87 if resp.status == STATUS_ERROR: 88 return Command.cli_resp_formatter(resp) 89 return cls._format_header() + cls._format_value(resp.value) 90 91 @classmethod 92 def _format_header(cls): 93 ret = '' 94 ret += ('Status codes: x filtered\n') 95 ret += ('Origin codes: i - IGP, e - EGP, ? - incomplete\n') 96 ret += cls.fmtstr.format('', 'Timestamp', 'Network', 'Labels', 97 'Next Hop', 'Metric', 'LocPrf', 'Path') 98 return ret 99 100 @classmethod 101 def _format_value(cls, value): 102 ret = '' 103 for v in value: 104 path = v.get('path') 105 aspath = path.get('as_path') 106 origin = path.get('origin') 107 108 if origin == BGP_ATTR_ORIGIN_IGP: 109 origin = 'i' 110 elif origin == BGP_ATTR_ORIGIN_EGP: 111 origin = 'e' 112 elif origin == BGP_ATTR_ORIGIN_INCOMPLETE: 113 origin = '?' 114 115 if origin: 116 aspath = aspath + [origin] 117 118 next_hop = path.get('nexthop') 119 med = path.get('metric') 120 labels = path.get('labels') 121 localpref = path.get('local_pref') 122 prefix = path.get('nlri').get('prefix') 123 124 path_status = '' 125 if v.get('filtered'): 126 path_status = 'x' 127 time = 'N/A' 128 if v.get('timestamp'): 129 time = strftime("%Y/%m/%d %H:%M:%S", v.get('timestamp')) 130 ret += cls.fmtstr.format(path_status, time, prefix, labels, 131 str(next_hop), str(med), str(localpref), 132 ' '.join(map(str, aspath))) 133 return ret 134 135 136class ReceivedRoutes(SentRoutes): 137 help_msg = 'paths received and not withdrawn by given peer' 138 command = 'received-routes' 139 140 def _retrieve_paths(self, addr_family, route_family, ip_addr): 141 peer_view = self._retrieve_peer_view(ip_addr) 142 adj_rib_in = peer_view.c_rel('adj_rib_in') 143 adj_rib_in.apply_filter(lambda k, v: addr_family == 'all' or 144 v.path.route_family == route_family) 145 return adj_rib_in 146 147 148class Neighbor(Command): 149 help_msg = 'show neighbor information' 150 command = 'neighbor' 151 subcommands = { 152 'summary': NeighborSummary, 153 'sent-routes': SentRoutes, 154 'received-routes': ReceivedRoutes 155 } 156 157 fmtstr = ' {0:<12s} {1:<12s} {2:<}\n' 158 159 def action(self, params): 160 core_service = self.api.get_core_service() 161 core_service_view = CoreServiceDetailView(core_service) 162 peers_view = core_service_view.rel('peer_manager').rel('peers') 163 164 ret = peers_view.encode() 165 return CommandsResponse(STATUS_OK, 166 [{'ip_addr': k, 167 'as_num': str(v['remote_as']), 168 'bgp_state': v['stats']['bgp_state']} 169 for k, v in ret.items()]) 170 171 @classmethod 172 def cli_resp_formatter(cls, resp): 173 if resp.status == STATUS_ERROR: 174 return Command.cli_resp_formatter(resp) 175 return cls._format_header() + cls._format_value(resp.value) 176 177 @classmethod 178 def _format_header(cls): 179 return cls.fmtstr.format('IP Address', 'AS Number', 'BGP State') 180 181 @classmethod 182 def _format_value(cls, value): 183 ret = '' 184 for v in value: 185 ret += cls.fmtstr.format(v['ip_addr'], v['as_num'], v['bgp_state']) 186 return ret 187