Exemplo n.º 1
0
def handle_srv6_path(
        operation,
        grpc_address,
        grpc_port,
        destination,
        segments="",
        device='',
        encapmode="encap",
        table=-1,
        metric=-1,
        bsid_addr='',
        fwd_engine='Linux'):
    """Handle a SRv6 path"""

    # pylint: disable=too-many-arguments

    with utils.get_grpc_session(grpc_address, grpc_port) as channel:
        res = srv6_utils.handle_srv6_path(
            operation=operation,
            channel=channel,
            destination=destination,
            segments=segments.split(','),
            device=device,
            encapmode=encapmode,
            table=table,
            metric=metric,
            bsid_addr=bsid_addr,
            fwd_engine=fwd_engine
        )
        if res == 0:
            print('OK')
        else:
            print('Error')
Exemplo n.º 2
0
def shift_path():
    # +--------------------------------------------------------------------+
    # |         Switch from r1---r7---r8 path to r1---r4---r8 path         |
    # |                     by exchanging the metrics                      |
    # +--------------------------------------------------------------------+
    logger.info(
        '*** Attempting to change path from r1---r7---r8 to r1---r4---r8')
    # IP addresses
    r1 = 'fcff:1::1'
    r8 = 'fcff:8::1'
    # Open gRPC channels
    with get_grpc_session(r1, GRPC_PORT) as r1_chan, \
            get_grpc_session(r8, GRPC_PORT) as r8_chan:
        # +---------------------------------------------------------------+
        # |              Decreasing the metric value of the               |
        # |               r4 route to an intermediate value               |
        # +---------------------------------------------------------------+
        logger.info('******* Decreasing the metric value of '
                    'the r4 route to an intermediate value')
        #
        # Encap route on r1
        # on r1: ip -6 route add fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:8:100 dev r1-h11 metric 99
        logger.info('*********** Creating encap route on r1')
        res = handle_srv6_path(op='add',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               segments=['fcff:4::1', 'fcff:8::100'],
                               device='r1-h11',
                               metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route add fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 99
        logger.info('*********** Creating decap route on r8')
        res = handle_srv6_behavior(op='add',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   action='End.DT6',
                                   lookup_table=254,
                                   device='r8-h83',
                                   metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route add fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:1:100 dev r8-h83 metric 99
        logger.info('*********** Creating encap route on r8')
        res = handle_srv6_path(op='add',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               segments=['fcff:4::1', 'fcff:1::100'],
                               device='r8-h83',
                               metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route add fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 99
        logger.info('*********** Creating decap route on r1')
        res = handle_srv6_behavior(op='add',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   action='End.DT6',
                                   lookup_table=254,
                                   device='r1-h11',
                                   metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        #
        # +---------------------------------------------------------------+
        # |                   Removing old route via r4                   |
        # +---------------------------------------------------------------+
        logger.info('*** Attempting to remove tunnel r1---r4---r8')
        #
        # Encap route on r1
        # on r1: ip -6 route del fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:8:100 dev r1-h11 metric 200
        logger.info('*********** Removing encap route on r1')
        res = handle_srv6_path(op='del',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               device='r1-h11',
                               metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route del fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 200
        logger.info('*********** Removing decap route on r8')
        res = handle_srv6_behavior(op='del',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   device='r8-h83',
                                   metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route del fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:1:100 dev r8-h83 metric 200
        logger.info('*********** Removing encap route on r8')
        res = handle_srv6_path(op='del',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               device='r8-h83',
                               metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route del fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 200
        logger.info('*********** Removing decap route on r1')
        res = handle_srv6_behavior(op='del',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   device='r1-h11',
                                   metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        #
        # +----------------------------------------------------------------+
        # |           Increasing the metric value of the r7 path           |
        # +----------------------------------------------------------------+
        logger.info(
            '*** Increasing the metric value of the tunnel r1---r7---r8')
        #
        # Encap route on r1
        # on r1: ip -6 route add fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:7::1,fcff:8:100 dev r1-h11 metric 200
        logger.info('*********** Creating encap route on r1')
        res = handle_srv6_path(op='add',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               segments=['fcff:7::1', 'fcff:8::100'],
                               device='r1-h11',
                               metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route add fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 200
        logger.info('*********** Creating decap route on r8')
        res = handle_srv6_behavior(op='add',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   action='End.DT6',
                                   lookup_table=254,
                                   device='r8-h83',
                                   metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route add fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:7::1,fcff:1:100 dev r8-h83 metric 200
        logger.info('*********** Creating encap route on r8')
        res = handle_srv6_path(op='add',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               segments=['fcff:7::1', 'fcff:1::100'],
                               device='r8-h83',
                               metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route add fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 200
        logger.info('*********** Creating decap route on r1')
        res = handle_srv6_behavior(op='add',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   action='End.DT6',
                                   lookup_table=254,
                                   device='r1-h11',
                                   metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        #
        # +---------------------------------------------------------------+
        # |                   Removing old route via r7                   |
        # +---------------------------------------------------------------+
        logger.info('*** Attempting to remove tunnel r1---r7---r8')
        # Encap route on r1
        # on r1: ip -6 route del fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:7::1,fcff:8:100 dev r1-h11 metric 100
        logger.info('*********** Removing encap route on r1')
        res = handle_srv6_path(op='del',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               device='r1-h11',
                               metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route del fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 100
        logger.info('*********** Removing decap route on r8')
        res = handle_srv6_behavior(op='del',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   device='r8-h83',
                                   metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route del fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:7::1,fcff:1:100 dev r8-h83 metric 100
        logger.info('*********** Removing encap route on r8')
        res = handle_srv6_path(op='del',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               device='r8-h83',
                               metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route del fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 100
        logger.info('*********** Removing decap route on r1')
        res = handle_srv6_behavior(op='del',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   device='r1-h11',
                                   metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        #
        # +---------------------------------------------------------------+
        # |      Assign to r4 route a definitive value of the metric      |
        # +---------------------------------------------------------------+
        logger.info('*** Assign to r4 route a definitive value of the metric')
        #
        # Encap route on r1
        # on r1: ip -6 route add fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:8:100 dev r1-h11 metric 100
        logger.info('*********** Creating encap route on r1')
        res = handle_srv6_path(op='add',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               segments=['fcff:4::1', 'fcff:8::100'],
                               device='r1-h11',
                               metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route add fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 100
        logger.info('*********** Creating decap route on r8')
        res = handle_srv6_behavior(op='add',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   action='End.DT6',
                                   lookup_table=254,
                                   device='r8-h83',
                                   metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route add fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:1:100 dev r8-h83 metric 100
        logger.info('*********** Creating encap route on r8')
        res = handle_srv6_path(op='add',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               segments=['fcff:4::1', 'fcff:1::100'],
                               device='r8-h83',
                               metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route add fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 100
        logger.info('*********** Creating decap route on r1')
        res = handle_srv6_behavior(op='add',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   action='End.DT6',
                                   lookup_table=254,
                                   device='r1-h11',
                                   metric=100)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        #
        # +---------------------------------------------------------------+
        # | Delete the r4 route with the intermediate value of the metric |
        # +---------------------------------------------------------------+
        logger.info('*** Delete the r4 route with the intermediate value of '
                    'the metric')
        #
        # Encap route on r1
        # on r1: ip -6 route del fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:8:100 dev r1-h11 metric 99
        logger.info('*********** Removing encap route on r1')
        res = handle_srv6_path(op='del',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               device='r1-h11',
                               metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route del fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 99
        logger.info('*********** Removing decap route on r8')
        res = handle_srv6_behavior(op='del',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   device='r8-h83',
                                   metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route del fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:1:100 dev r8-h83 metric 99
        logger.info('*********** Removing encap route on r8')
        res = handle_srv6_path(op='del',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               device='r8-h83',
                               metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route del fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 99
        logger.info('*********** Removing decap route on r1')
        res = handle_srv6_behavior(op='del',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   device='r1-h11',
                                   metric=99)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        #
        # +---------------------------------------------------------------+
        # |                             Done                              |
        # +---------------------------------------------------------------+
        print()
 def HandleSRv6Path(self, request, context):
     """
     Handle a SRv6 path.
     """
     # Iterate on the SRv6 paths
     srv6_paths = None
     for srv6_path in request.srv6_paths:
         # Perform the operation
         #
         # The "with" block is used to avoid duplicating the error handling
         # code
         with srv6_mgr_error_handling() as response:
             # Extract the encap mode
             encapmode = grpc_to_py_encap_mode[srv6_path.encapmode]
             # Extract the forwarding engine
             fwd_engine = grpc_to_py_fwd_engine[srv6_path.fwd_engine]
             if fwd_engine == 'FWD_ENGINE_UNSPEC':
                 fwd_engine = ''
             # Handle SRv6 path
             srv6_paths = srv6_utils.handle_srv6_path(
                 operation=srv6_path.operation,
                 grpc_address=(srv6_path.grpc_address
                               if srv6_path.grpc_address != '' else None),
                 grpc_port=(srv6_path.grpc_port
                            if srv6_path.grpc_port != -1 else None),
                 destination=(srv6_path.destination
                              if srv6_path.destination != '' else None),
                 segments=(list(srv6_path.segments)
                           if len(srv6_path.segments) > 0 else None),
                 device=(srv6_path.device
                         if srv6_path.device != '' else None),
                 encapmode=encapmode if encapmode != '' else None,
                 table=srv6_path.table if srv6_path.table != -1 else None,
                 metric=(srv6_path.metric
                         if srv6_path.metric != -1 else None),
                 bsid_addr=(srv6_path.bsid_addr
                            if srv6_path.bsid_addr != '' else None),
                 fwd_engine=fwd_engine if fwd_engine != '' else None,
                 key=srv6_path.key if srv6_path.key != '' else None,
                 db_conn=self.db_conn
             )
     # If an error occurred, return immediately
     if response.status != nb_commons_pb2.STATUS_SUCCESS:
         return response
     # Add the SRv6 paths to the response message
     if srv6_paths is not None:
         for path in srv6_paths:
             # Create a new path
             _srv6_path = response.srv6_paths.add()
             # Set gRPC address
             _srv6_path.grpc_address = ''
             if path['grpc_address'] is not None:
                 _srv6_path.grpc_address = path['grpc_address']
             # Set gRPC port
             _srv6_path.grpc_port = ''
             if path['grpc_port'] is not None:
                 _srv6_path.grpc_port = path['grpc_port']
             # Set destination
             _srv6_path.destination = ''
             if path['destination'] is not None:
                 _srv6_path.destination = path['destination']
             # Set segment list
             if path['segments'] is not None:
                 _srv6_path.segments.extend(path['segments'])
             # Set encap mode (e.g. "encap" or "inline")
             _srv6_path.encapmode = EncapMode.UNSPEC.value
             if path['encapmode'] is not None:
                 _srv6_path.encapmode = \
                     py_to_grpc_encap_mode[path['encapmode']]
             # Set device
             _srv6_path.device = ''
             if path['device'] is not None:
                 _srv6_path.device = path['device']
             # Set table ID
             _srv6_path.table = -1
             if path['table'] is not None:
                 _srv6_path.table = path['table']
             # Set the metric
             _srv6_path.metric = -1
             if path['metric'] is not None:
                 _srv6_path.metric = path['metric']
             # Set BSID address (required by VPP)
             _srv6_path.bsid_addr = ''
             if path['bsid_addr'] is not None:
                 _srv6_path.bsid_addr = path['bsid_addr']
             # Set forwarding engine
             _srv6_path.fwd_engine = FwdEngine.UNSPEC.value
             if path['fwd_engine'] is not None:
                 _srv6_path.fwd_engine = \
                     py_to_grpc_fwd_engine[path['fwd_engine']]
             # Set key
             if '_key' in path:
                 _srv6_path.key = path['_key']
     # Done, return the reply
     return response
def remove_tunnel_r1r7r8():
    # +--------------------------------------------------------------------+
    # |          Remove a bidirectional tunnel between h11 and h83         |
    # |              passing through router r7 (r1---r7---r8)              |
    # +--------------------------------------------------------------------+
    logger.info('*** Attempting to remove tunnel r1---r7---r8')
    # IP addresses
    r1 = 'fcff:1::1'
    r8 = 'fcff:8::1'
    # Open gRPC channels
    with get_grpc_session(r1, GRPC_PORT) as r1_chan, \
            get_grpc_session(r8, GRPC_PORT) as r8_chan:
        # +---------------------------------------------------------------+
        # |         Remove tunnel from r1 to r8 for fd00:0:83::/64        |
        # +---------------------------------------------------------------+
        logger.info('******* Removing tunnel from r1 to r8 for fd00:0:83::/64')
        #
        # Decap route on r8
        # on r8: ip -6 route del fcff:8::100 dev r8-h83 metric 100
        logger.info('*********** Removing decap route')
        res = handle_srv6_behavior(op='del',
                                   channel=r8_chan,
                                   segment='fcff:8::100',
                                   device='r8-h83',
                                   metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        # Encap route on r1
        # on r1: ip -6 route del fd00:0:83::/64 dev r1-h11 metric 100
        logger.info('*********** Removing encap route')
        res = handle_srv6_path(op='del',
                               channel=r1_chan,
                               destination='fd00:0:83::/64',
                               device='r1-h11',
                               metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        #
        # +---------------------------------------------------------------+
        # |         Remove tunnel from r8 to r1 for fd00:0:11::/64        |
        # +---------------------------------------------------------------+
        logger.info('******* Removing tunnel from r8 to r1 for fd00:0:11::/64')
        #
        # Decap route on r1
        # on r1: ip -6 route del fcff:1::100 dev r1-h11 metric 100
        logger.info('*********** Removing decap route')
        res = handle_srv6_behavior(op='del',
                                   channel=r1_chan,
                                   segment='fcff:1::100',
                                   device='r1-h11',
                                   metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route removed successfully')
        else:
            logger.error('*********** Error while removing decap route')
        #
        # Encap route on r8
        # on r8: ip -6 route del fd00:0:11::/64 dev r8-h83 metric 200
        logger.info('*********** Removing encap route')
        res = handle_srv6_path(op='del',
                               channel=r8_chan,
                               destination='fd00:0:11::/64',
                               device='r8-h83',
                               metric=200)
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route removed successfully')
        else:
            logger.error('*********** Error while removing encap route')
        #
        #
        # +---------------------------------------------------------------+
        # |                             Done                              |
        # +---------------------------------------------------------------+
        print()
Exemplo n.º 5
0
def handle_srv6_usid_policy(operation,
                            lr_destination=None, rl_destination=None,
                            nodes_lr=None,
                            nodes_rl=None, table=-1, metric=-1,
                            persistency=True, _id=None, l_grpc_ip=None,
                            l_grpc_port=None, l_fwd_engine=None,
                            r_grpc_ip=None, r_grpc_port=None,
                            r_fwd_engine=None, decap_sid=None, locator=None,
                            db_conn=None):
    """
    Handle a SRv6 Policy using uSIDs

    :param operation: The operation to be performed on the uSID policy
                      (i.e. add, get, change, del)
    :type operation: str
    :param destination: Destination of the SRv6 route
    :type destination: str
    :param nodes: Waypoints of the SRv6 route
    :type nodes: list
    :param device: Device of the SRv6 route. If not provided, the device
                   is selected automatically by the node.
    :type device: str, optional
    :param table: Routing table containing the SRv6 route. If not provided,
                  the main table (i.e. table 254) will be used.
    :type table: int, optional
    :param metric: Metric for the SRv6 route. If not provided, the default
                   metric will be used.
    :type metric: int, optional
    :param l_grpc_ip: gRPC IP address of the left node, required if the left
                      node is expressed numerically in the nodes list.
    :type l_grpc_ip: str, optional
    :param l_grpc_port: gRPC port of the left node, required if the left
                        node is expressed numerically in the nodes list.
    :type l_grpc_port: str, optional
    :param l_fwd_engine: forwarding engine of the left node, required if the
                         left node is expressed numerically in the nodes list.
    :type l_fwd_engine: str, optional
    :param r_grpc_ip: gRPC IP address of the right node, required if the right
                      node is expressed numerically in the nodes list.
    :type r_grpc_ip: str, optional
    :param r_grpc_port: gRPC port of the right node, required if the right
                        node is expressed numerically in the nodes list.
    :type r_grpc_port: str, optional
    :param r_fwd_engine: Forwarding engine of the right node, required if the
                         right node is expressed numerically in the nodes
                         list.
    :type r_fwd_engine: str, optional
    :param decap_sid: uSID used for the decap behavior (End.DT6).
    :type decap_sid: str, optional
    :param locator: Locator prefix (e.g. 'fcbb:bbbb::').
    :type locator: str, optional
    :return: Status Code of the operation (e.g. 0 for STATUS_SUCCESS)
    :rtype: int
    :raises NodeNotFoundError: Node name not found in the mapping file
    :raises InvalidConfigurationError: The mapping file is not a valid
                                       YAML file
    :raises TooManySegmentsError: segments arg contains more than 6 segments
    :raises SIDLocatorError: SID Locator is wrong for one or more segments
    :raises InvalidSIDError: SID is wrong for one or more segments
    """
    # pylint: disable=too-many-locals, too-many-arguments
    # pylint: disable=too-many-return-statements, too-many-branches
    # pylint: disable=too-many-statements
    #
    # Validate arguments
    if lr_destination is None:
        if operation in ['add']:
            logger.error('"lr_destination" argument is mandatory for %s '
                         'operation', operation)
            return None
    if rl_destination is None:
        if operation in ['add']:
            logger.error('"rl_destination" argument is mandatory for %s '
                         'operation', operation)
            return None
    if nodes_lr is None:
        if operation in ['add']:
            logger.error('"nodes_lr" argument is mandatory for %s '
                         'operation', operation)
            return None
    if nodes_rl is None:
        pass
    if operation == 'change':
        logger.error('Operation not yet implemented: %s', operation)
        return None
    if operation == 'get':
        if not persistency:
            logger.error('Error in get(): Persistency is disabled')
            return None
        # Get the policy from the db
        policies = arangodb_driver.find_usid_policy(
            database=db_conn,
            key=_id,
            lr_dst=lr_destination,
            rl_dst=rl_destination,
            lr_nodes=nodes_lr,
            rl_nodes=nodes_rl,
            table=table if table != -1 else None,
            metric=metric if metric != -1 else None
        )
        # Print policies
        print('\n\n*** uSID policies:')
        pprint.PrettyPrinter(indent=4).pprint(list(policies))
        print('\n\n')
        return 0
    if operation in ['add', 'del']:
        # Extract the nodes configuration from the db
        nodes_config = topo_utils.get_nodes_config()
        #
        # In order to perform this translation, a file containing the
        # mapping of node names to IPv6 addresses is required
        #
        # Read nodes from YAML file
        nodes_info = {node['name']: node for node in nodes_config['nodes']}
        locator_bits = DEFAULT_LOCATOR_BITS  # TODO configurable locator bits
        usid_id_bits = DEFAULT_USID_ID_BITS  # TODO configurable uSID id bits
        # Add nodes list for the left-to-right path to the 'nodes_info' dict
        if nodes_lr is not None:
            fill_nodes_info(
                nodes_info=nodes_info,
                nodes=nodes_lr,
                l_grpc_ip=l_grpc_ip,
                l_grpc_port=l_grpc_port,
                l_fwd_engine=l_fwd_engine,
                r_grpc_ip=r_grpc_ip,
                r_grpc_port=r_grpc_port,
                r_fwd_engine=r_fwd_engine,
                decap_sid=decap_sid,
                locator=locator
            )
        # Add nodes list for the right-to-left path to the 'nodes_info' dict
        if nodes_rl is not None:
            fill_nodes_info(
                nodes_info=nodes_info,
                nodes=nodes_rl,
                l_grpc_ip=r_grpc_ip,
                l_grpc_port=r_grpc_port,
                l_fwd_engine=r_fwd_engine,
                r_grpc_ip=l_grpc_ip,
                r_grpc_port=l_grpc_port,
                r_fwd_engine=l_fwd_engine,
                decap_sid=decap_sid,
                locator=locator
            )
        # Add
        if operation == 'add':
            policies = [{
                'lr_dst': lr_destination,
                'rl_dst': rl_destination,
                'lr_nodes': nodes_lr,
                'rl_nodes': nodes_rl
            }]
        if operation == 'del':
            # Get the policy from the db
            policies = arangodb_driver.find_usid_policy(
                database=db_conn,
                key=_id,
                lr_dst=lr_destination,
                rl_dst=rl_destination,
                lr_nodes=nodes_lr,
                rl_nodes=nodes_rl,
                table=table if table != -1 else None,
                metric=metric if metric != -1 else None
            )

            policies = list(policies)
            for policy in policies:
                # Add nodes list for the left-to-right path to the
                # 'nodes_info' dict
                if policy.get('lr_nodes') is not None:
                    fill_nodes_info(
                        nodes_info=nodes_info,
                        nodes=policy.get('lr_nodes'),
                        l_grpc_ip=policy.get('l_grpc_ip'),
                        l_grpc_port=policy.get('l_grpc_port'),
                        l_fwd_engine=policy.get('l_fwd_engine'),
                        r_grpc_ip=policy.get('r_grpc_ip'),
                        r_grpc_port=policy.get('r_grpc_port'),
                        r_fwd_engine=policy.get('r_fwd_engine'),
                        decap_sid=policy.get('decap_sid'),
                        locator=policy.get('locator')
                    )
                # Add nodes list for the right-to-left path to the
                # 'nodes_info' dict
                if policy.get('rl_nodes') is not None:
                    fill_nodes_info(
                        nodes_info=nodes_info,
                        nodes=policy.get('rl_nodes'),
                        l_grpc_ip=policy.get('r_grpc_ip'),
                        l_grpc_port=policy.get('r_grpc_port'),
                        l_fwd_engine=policy.get('r_fwd_engine'),
                        r_grpc_ip=policy.get('l_grpc_ip'),
                        r_grpc_port=policy.get('l_grpc_port'),
                        r_fwd_engine=policy.get('l_fwd_engine'),
                        decap_sid=policy.get('decap_sid'),
                        locator=policy.get('locator')
                    )
        if len(policies) == 0:
            logger.error('Policy not found')
            return None
        # Iterate on the policies
        for policy in policies:
            lr_destination = policy.get('lr_dst')
            rl_destination = policy.get('rl_dst')
            nodes_lr = policy.get('lr_nodes')
            nodes_rl = policy.get('rl_nodes')
            _id = policy.get('_key')
            #
            # If right to left nodes list is not provided, we use the reverse
            # left to right SID list (symmetric path)
            if nodes_rl is None:
                nodes_rl = nodes_lr[::-1]
            # The two SID lists must have the same endpoints
            if nodes_lr[0] != nodes_rl[-1] or nodes_rl[0] != nodes_lr[-1]:
                logger.error('Bad tunnel endpoints')
                return None
            # Create the SRv6 Policy
            try:
                # # Prefix length for local segment
                # prefix_len = locator_bits + usid_id_bits
                # Ingress node
                ingress_node = nodes_info[nodes_lr[0]]
                # Intermediate nodes
                intermediate_nodes_lr = list()
                for node in nodes_lr[1:-1]:
                    intermediate_nodes_lr.append(nodes_info[node])
                intermediate_nodes_rl = list()
                for node in nodes_rl[1:-1]:
                    intermediate_nodes_rl.append(nodes_info[node])
                # Egress node
                egress_node = nodes_info[nodes_lr[-1]]
                # Extract the segments
                segments_lr = list()
                for node in nodes_lr:
                    segments_lr.append(nodes_info[node]['uN'])
                segments_rl = list()
                for node in nodes_rl:
                    segments_rl.append(nodes_info[node]['uN'])

                # Ingress node
                with utils.get_grpc_session(ingress_node['grpc_ip'],
                                            ingress_node['grpc_port']
                                            ) as channel:
                    # Currently ony Linux and VPP are suppoted for the encap
                    if ingress_node['fwd_engine'] not in ['linux', 'vpp']:
                        logger.error(
                            'Encap operation is not supported for '
                            '%s with fwd engine %s',
                            ingress_node['name'],
                            ingress_node['fwd_engine'])
                        return commons_pb2.STATUS_INTERNAL_ERROR
                    # VPP requires a BSID address
                    bsid_addr = ''
                    if ingress_node['fwd_engine'] == 'VPP':
                        for char in lr_destination:
                            if char not in ('0', ':'):
                                bsid_addr += char
                        add_colon = False
                        if len(bsid_addr) <= 28:
                            add_colon = True
                        bsid_addr = [(bsid_addr[i:i + 4])
                                     for i in range(0, len(bsid_addr), 4)]
                        bsid_addr = ':'.join(bsid_addr)
                        if add_colon:
                            bsid_addr += '::'

                    udt_sids = list()
                    # Locator mask
                    locator_mask = str(IPv6Address(
                        int('1' * 128, 2) ^
                        int('1' * (128 - locator_bits), 2)))
                    # uDT mask
                    udt_mask_1 = str(
                        IPv6Address(int('1' * usid_id_bits, 2) <<
                                    (128 - locator_bits - usid_id_bits)))
                    udt_mask_2 = str(
                        IPv6Address(int('1' * usid_id_bits, 2) <<
                                    (128 - locator_bits - 2 * usid_id_bits)))
                    # Build uDT sid list
                    locator_int = int(IPv6Address(egress_node['uDT'])) & \
                        int(IPv6Address(locator_mask))
                    udt_mask_1_int = int(IPv6Address(egress_node['uDT'])) & \
                        int(IPv6Address(udt_mask_1))
                    udt_mask_2_int = int(IPv6Address(egress_node['uDT'])) & \
                        int(IPv6Address(udt_mask_2))
                    udt_sids += [str(IPv6Address(locator_int +
                                                 udt_mask_1_int))]
                    udt_sids += [str(IPv6Address(locator_int +
                                                 (udt_mask_2_int <<
                                                  usid_id_bits)))]
                    # We need to convert the SID list into a uSID list
                    #  before creating the SRv6 policy
                    usid_list = sidlist_to_usidlist(
                        sid_list=segments_lr[1:][:-1],
                        udt_sids=[segments_lr[1:][-1]] + udt_sids,
                        locator_bits=locator_bits,
                        usid_id_bits=usid_id_bits
                    )
                    # Handle a SRv6 path
                    response = srv6_utils.handle_srv6_path(
                        operation=operation,
                        channel=channel,
                        destination=lr_destination,
                        segments=usid_list,
                        encapmode='encap.red',
                        table=table,
                        metric=metric,
                        bsid_addr=bsid_addr,
                        fwd_engine=ingress_node['fwd_engine'],
                        update_db=False
                    )
                    if response != commons_pb2.STATUS_SUCCESS:
                        # Error
                        return response
                    # # Create the uN behavior
                    # response = handle_srv6_behavior(
                    #     operation=operation,
                    #     channel=channel,
                    #     segment='%s/%s' % (ingress_node['uN'], prefix_len),
                    #     action='uN',
                    #     fwd_engine=ingress_node['fwd_engine']
                    # )
                    # if response != commons_pb2.STATUS_SUCCESS:
                    #     # Error
                    #     return response
                    # # Create the End behavior
                    # response = handle_srv6_behavior(
                    #     operation=operation,
                    #     channel=channel,
                    #     segment='%s/%s' % (ingress_node['uN'], 64),
                    #     action='End',
                    #     fwd_engine=ingress_node['fwd_engine']
                    # )
                    # if response != commons_pb2.STATUS_SUCCESS:
                    #     # Error
                    #     return response
                    # # Create the decap behavior
                    # response = handle_srv6_behavior(
                    #     operation=operation,
                    #     channel=channel,
                    #     segment='%s/%s' % (ingress_node['uDT'], 64),
                    #     action='End.DT6',
                    #     lookup_table=254,
                    #     fwd_engine=ingress_node['fwd_engine']
                    # )
                    # if response != commons_pb2.STATUS_SUCCESS:
                    #     # Error
                    #     return response
                # # Intermediate nodes
                # for node in intermediate_nodes:
                #     with utils.get_grpc_session(node['grpc_ip'],
                #                                 node['grpc_port']
                #                                 ) as channel:
                #         # Create the uN behavior
                #         response = handle_srv6_behavior(
                #             operation=operation,
                #             channel=channel,
                #             segment='%s/%s' % (node['uN'], prefix_len),
                #             action='uN',
                #             fwd_engine=node['fwd_engine']
                #         )
                #         if response != commons_pb2.STATUS_SUCCESS:
                #             # Error
                #             return response
                # Egress node
                with utils.get_grpc_session(egress_node['grpc_ip'],
                                            egress_node['grpc_port']
                                            ) as channel:
                    # Currently ony Linux and VPP are suppoted for the encap
                    if egress_node['fwd_engine'] not in ['linux', 'vpp']:
                        logger.error(
                            'Encap operation is not supported for '
                            '%s with fwd engine %s',
                            egress_node['name'], egress_node['fwd_engine'])
                        return commons_pb2.STATUS_INTERNAL_ERROR
                    # VPP requires a BSID address
                    bsid_addr = ''
                    if egress_node['fwd_engine'] == 'VPP':
                        for char in lr_destination:
                            if char not in ('0', ':'):
                                bsid_addr += char
                        add_colon = False
                        if len(bsid_addr) <= 28:
                            add_colon = True
                        bsid_addr = [(bsid_addr[i:i + 4])
                                     for i in range(0, len(bsid_addr), 4)]
                        bsid_addr = ':'.join(bsid_addr)
                        if add_colon:
                            bsid_addr += '::'
                    # # Create the uN behavior
                    # response = handle_srv6_behavior(
                    #     operation=operation,
                    #     channel=channel,
                    #     segment='%s/%s' % (egress_node['uN'], prefix_len),
                    #     action='uN',
                    #     fwd_engine=egress_node['fwd_engine']
                    # )
                    # if response != commons_pb2.STATUS_SUCCESS:
                    #     # Error
                    #     return response
                    # # Create the End behavior
                    # response = handle_srv6_behavior(
                    #     operation=operation,
                    #     channel=channel,
                    #     segment='%s/%s' % (egress_node['uN'], 64),
                    #     action='End',
                    #     fwd_engine=egress_node['fwd_engine']
                    # )
                    # if response != commons_pb2.STATUS_SUCCESS:
                    #     # Error
                    #     return response
                    # # Create the decap behavior
                    # response = handle_srv6_behavior(
                    #     operation=operation,
                    #     channel=channel,
                    #     segment='%s/%s' % (egress_node['uDT'], 64),
                    #     action='End.DT6',
                    #     lookup_table=254,
                    #     fwd_engine=egress_node['fwd_engine']
                    # )
                    # if response != commons_pb2.STATUS_SUCCESS:
                    #     # Error
                    #     return response
                    udt_sids = list()
                    # Locator mask
                    locator_mask = str(IPv6Address(
                        int('1' * 128, 2) ^
                        int('1' * (128 - locator_bits), 2)))
                    # uDT mask
                    udt_mask_1 = str(IPv6Address(int('1' * usid_id_bits, 2) <<
                                                 (128 - locator_bits -
                                                  usid_id_bits)))
                    udt_mask_2 = str(IPv6Address(int('1' * usid_id_bits, 2) <<
                                                 (128 - locator_bits -
                                                  2 * usid_id_bits)))
                    # Build uDT sid list
                    locator_int = int(
                        IPv6Address(
                            ingress_node['uDT'])) & int(
                                IPv6Address(locator_mask))
                    udt_mask_1_int = int(
                        IPv6Address(
                            ingress_node['uDT'])) & int(
                                IPv6Address(udt_mask_1))
                    udt_mask_2_int = int(
                        IPv6Address(
                            ingress_node['uDT'])) & int(
                                IPv6Address(udt_mask_2))
                    udt_sids += [str(IPv6Address(locator_int +
                                                 udt_mask_1_int))]
                    udt_sids += [str(IPv6Address(locator_int +
                                                 (udt_mask_2_int <<
                                                  usid_id_bits)))]
                    # We need to convert the SID list into a uSID list
                    #  before creating the SRv6 policy
                    usid_list = sidlist_to_usidlist(
                        sid_list=segments_rl[1:][:-1],
                        udt_sids=[segments_rl[1:][-1]] + udt_sids,
                        locator_bits=locator_bits,
                        usid_id_bits=usid_id_bits
                    )
                    # Handle a SRv6 path
                    response = srv6_utils.handle_srv6_path(
                        operation=operation,
                        channel=channel,
                        destination=rl_destination,
                        segments=usid_list,
                        encapmode='encap.red',
                        table=table,
                        metric=metric,
                        bsid_addr=bsid_addr,
                        fwd_engine=egress_node['fwd_engine'],
                        update_db=False
                    )
                    if response != commons_pb2.STATUS_SUCCESS:
                        # Error
                        return response
                # Persist uSID policy to database
                if persistency:
                    if operation == 'add':
                        # Save the policy to the db
                        arangodb_driver.insert_usid_policy(
                            database=db_conn,
                            lr_dst=lr_destination,
                            rl_dst=rl_destination,
                            lr_nodes=nodes_lr,
                            rl_nodes=nodes_rl,
                            table=table if table != -1 else None,
                            metric=metric if metric != -1 else None,
                            l_grpc_ip=l_grpc_ip,
                            l_grpc_port=l_grpc_port,
                            l_fwd_engine=l_fwd_engine,
                            r_grpc_ip=r_grpc_ip,
                            r_grpc_port=r_grpc_port,
                            r_fwd_engine=r_fwd_engine,
                            decap_sid=decap_sid,
                            locator=locator
                        )
                    elif operation == 'del':
                        # Save the policy to the db
                        arangodb_driver.delete_usid_policy(
                            database=db_conn,
                            key=_id,
                            lr_dst=lr_destination,
                            rl_dst=rl_destination,
                            lr_nodes=nodes_lr,
                            rl_nodes=nodes_rl,
                            table=table if table != -1 else None,
                            metric=metric if metric != -1 else None
                        )
                    else:
                        logger.error('Unsupported operation: %s', operation)
            except (InvalidConfigurationError, NodeNotFoundError,
                    TooManySegmentsError, SIDLocatorError, InvalidSIDError):
                return commons_pb2.STATUS_INTERNAL_ERROR
        # Return the response
        return response
    logger.error('Unsupported operation: %s', operation)
    return None
Exemplo n.º 6
0
def create_tunnel_r1r4r8():
    # +--------------------------------------------------------------------+
    # |          Create a bidirectional tunnel between h11 and h83         |
    # |              passing through router r4 (r1---r4---r8)              |
    # +--------------------------------------------------------------------+
    logger.info('*** Attempting to create tunnel r1---r4---r8')
    # IP addresses
    r1 = 'fcff:1::1'
    r8 = 'fcff:8::1'
    # Open gRPC channels
    with get_grpc_session(r1, GRPC_PORT) as r1_chan, \
            get_grpc_session(r8, GRPC_PORT) as r8_chan:
        # +---------------------------------------------------------------+
        # |          Set tunnel from r1 to r8 for fd00:0:83::/64          |
        # +---------------------------------------------------------------+
        logger.info('******* Set tunnel from r1 to r8 for fd00:0:83::/64')
        #
        # Encap route on r1
        # on r1: ip -6 route add fd00:0:83::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:8::100 dev r1-h11 metric 200
        logger.info('*********** Creating encap route')
        res = handle_srv6_path(
            op='add',
            channel=r1_chan,
            destination='fd00:0:83::/64',
            segments=['fcff:4::1', 'fcff:8::100'],
            device='r1-h11',
            metric=200
        )
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r8
        # on r8: ip -6 route add fcff:8::100 encap seg6local action End.DT6
        #        table 254 dev r8-h83 metric 200
        logger.info('*********** Creating decap route')
        res = handle_srv6_behavior(
            op='add',
            channel=r8_chan,
            segment='fcff:8::100',
            action='End.DT6',
            lookup_table=254,
            device='r8-h83',
            metric=200
        )
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        #
        # +---------------------------------------------------------------+
        # |          Set tunnel from r8 to r1 for fd00:0:11::/64          |
        # +---------------------------------------------------------------+
        logger.info('******* Set tunnel from r8 to r1 for fd00:0:11::/64')
        #
        # Encap route on r8
        # on r8: ip -6 route add fd00:0:11::/64 encap seg6 mode encap segs
        #        fcff:4::1,fcff:1::100 dev r8-h83 metric 200
        logger.info('*********** Creating encap route')
        res = handle_srv6_path(
            op='add',
            channel=r8_chan,
            destination='fd00:0:11::/64',
            segments=['fcff:4::1', 'fcff:1::100'],
            device='r8-h83',
            metric=200
        )
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Encap route created successfully')
        else:
            logger.error('*********** Error while creating encap route')
        #
        # Decap route on r1
        # on r1: ip -6 route add fcff:1::100 encap seg6local action End.DT6
        #        table 254 dev r1-h11 metric 200
        logger.info('*********** Creating decap route')
        res = handle_srv6_behavior(
            op='add',
            channel=r1_chan,
            segment='fcff:1::100',
            action='End.DT6',
            lookup_table=254,
            device='r1-h11',
            metric=200
        )
        if res == srv6_manager_pb2.StatusCode.STATUS_SUCCESS:
            logger.info('*********** Decap route created successfully')
        else:
            logger.error('*********** Error while creating decap route')
        #
        #
        # +---------------------------------------------------------------+
        # |                             Done                              |
        # +---------------------------------------------------------------+
        print()