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