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())