github.com/osrg/gobgp@v2.0.0+incompatible/test/lib/yabgp_helper.py (about) 1 #!/usr/bin/env python 2 3 from __future__ import absolute_import 4 from __future__ import print_function 5 6 import json 7 import logging 8 import sys 9 10 from flask import Blueprint 11 import flask 12 13 from yabgp.agent import prepare_service 14 from yabgp.common import constants 15 from yabgp.handler import BaseHandler 16 from yabgp.api import app 17 from yabgp.api import utils as api_utils 18 from yabgp.api.v1 import auth 19 20 LOG = logging.getLogger(__name__) 21 blueprint = Blueprint('v1-ext', __name__) 22 _send_update = api_utils.send_update 23 24 25 def _extract_afi_safi(attr): 26 # MP_REACH_NLRI(14) or MP_UNREACH_NLRI(15) 27 nlri = attr.get(14, None) or attr.get(15, None) 28 if nlri and 'afi_safi' in nlri: 29 afi_safi = nlri.get('afi_safi', None) 30 return constants.AFI_SAFI_DICT.get(tuple(afi_safi), None) 31 return 'ipv4' 32 33 34 def _construct_msg(attr, nlri, withdraw): 35 return { 36 'afi_safi': _extract_afi_safi(attr), 37 'attr': attr, 38 'nlir': nlri or [], 39 'withdraw': withdraw or [], 40 } 41 42 43 def _extract_nlri_list(msg): 44 try: 45 if msg['afi_safi'] == 'ipv4': 46 return msg['nlri'] 47 return msg['attr'][14]['nlri'] # MP_REACH_NLRI(14) 48 except KeyError: 49 # Ignore case when no nlri 50 pass 51 return [] 52 53 54 def _extract_withdraw_list(msg): 55 try: 56 if msg['afi_safi'] == 'ipv4': 57 return msg['withdraw'] 58 return msg['attr'][15]['withdraw'] # MP_UNREACH_NLRI(15) 59 except KeyError: 60 # Ignore case when no withdraw 61 pass 62 return [] 63 64 65 def _nlri_key(nlri): 66 if isinstance(nlri, (dict, list)): 67 return json.dumps(nlri) 68 return str(nlri) 69 70 71 # ADJ_RIB_IN = { 72 # <peer.factory.peer_addr>: { 73 # <afi_safi>: { 74 # <nlri>: <msg>, 75 # ... 76 # }, 77 # ... 78 # }, 79 # ... 80 # } 81 ADJ_RIB_IN = {} 82 83 84 @blueprint.route('/peer/<peer_ip>/adj-rib-in') 85 @auth.login_required 86 @api_utils.log_request 87 def peer_adj_rib_in(peer_ip): 88 """ 89 Dumps one peer's adj-RIB-in. 90 """ 91 return flask.jsonify(ADJ_RIB_IN.get(peer_ip, {})) 92 93 94 # ADJ_RIB_OUT = { 95 # <peer_ip>: { 96 # <afi_safi>: { 97 # <nlri>: <msg>, 98 # ... 99 # }, 100 # ... 101 # }, 102 # ... 103 # } 104 ADJ_RIB_OUT = {} 105 106 107 @blueprint.route('/peer/<peer_ip>/adj-rib-out') 108 @auth.login_required 109 @api_utils.log_request 110 def peer_adj_rib_out(peer_ip): 111 """ 112 Dumps one peer's adj-RIB-out. 113 """ 114 return flask.jsonify(ADJ_RIB_OUT.get(peer_ip, {})) 115 116 117 app.app.register_blueprint(blueprint, url_prefix='/v1-ext') 118 119 120 def send_update(peer_ip, attr, nlri, withdraw): 121 """ 122 Wrapper of "yabgp.api.send_update" in order to hook sending UPDATE 123 messages via REST API. 124 """ 125 msg = _construct_msg(attr, nlri, withdraw) 126 afi_safi = msg['afi_safi'] 127 ADJ_RIB_OUT.setdefault(peer_ip, {}) 128 ADJ_RIB_OUT[peer_ip].setdefault(afi_safi, {}) 129 rib = ADJ_RIB_OUT[peer_ip][afi_safi] 130 for _nlri in _extract_nlri_list(msg): 131 rib[_nlri_key(_nlri)] = msg 132 for _withdraw in _extract_withdraw_list(msg): 133 rib.pop(_nlri_key(_withdraw), None) 134 return _send_update(peer_ip, attr, nlri, withdraw) 135 136 137 setattr(api_utils, 'send_update', send_update) 138 139 140 class CliHandler(BaseHandler): 141 142 def __init__(self): 143 super(CliHandler, self).__init__() 144 145 def init(self): 146 pass 147 148 def on_update_error(self, peer, timestamp, msg): 149 LOG.info('[-] UPDATE ERROR: %s', msg) 150 151 def route_refresh_received(self, peer, msg, msg_type): 152 LOG.info('[+] ROUTE_REFRESH received: %s', msg) 153 154 def keepalive_received(self, peer, timestamp): 155 LOG.debug('[+] KEEPALIVE received: %s', peer.factory.peer_addr) 156 157 def open_received(self, peer, timestamp, result): 158 LOG.info('[+] OPEN received: %s', result) 159 160 def update_received(self, peer, timestamp, msg): 161 LOG.info('[+] UPDATE received: %s', msg) 162 peer_addr = peer.factory.peer_addr 163 afi_safi = msg['afi_safi'] 164 ADJ_RIB_IN.setdefault(peer.factory.peer_addr, {}) 165 ADJ_RIB_IN[peer_addr].setdefault(afi_safi, {}) 166 rib = ADJ_RIB_IN[peer_addr][afi_safi] 167 for nlri in _extract_nlri_list(msg): 168 rib[_nlri_key(nlri)] = msg 169 for withdraw in _extract_withdraw_list(msg): 170 rib.pop(_nlri_key(withdraw), None) 171 172 def notification_received(self, peer, msg): 173 LOG.info('[-] NOTIFICATION received: %s', msg) 174 175 def on_connection_lost(self, peer): 176 LOG.info('[-] CONNECTION lost: %s', peer.factory.peer_addr) 177 178 def on_connection_failed(self, peer, msg): 179 LOG.info('[-] CONNECTION failed: %s', msg) 180 181 182 def main(): 183 try: 184 cli_handler = CliHandler() 185 prepare_service(handler=cli_handler) 186 except Exception as e: 187 print(e) 188 189 190 if __name__ == '__main__': 191 sys.exit(main())