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