def handle_srv6_behavior_request(self, operation, request, context):
        # pylint: disable=unused-argument
        """Handler for SRv6 behaviors"""

        LOGGER.debug('config received:\n%s', request)
        # Let's process the request
        try:
            for behavior in request.behaviors:
                if operation == 'del':
                    res = self.handle_srv6_behavior_del_request(behavior)
                    return srv6_manager_pb2.SRv6ManagerReply(status=res)
                if operation == 'get':
                    res = self.handle_srv6_behavior_get_request(behavior)
                    return srv6_manager_pb2.SRv6ManagerReply(status=res)
                # Pass the request to the right handler
                res = self.dispatch_srv6_behavior(operation, behavior)
                if res != commons_pb2.STATUS_SUCCESS:
                    return srv6_manager_pb2.SRv6ManagerReply(status=res)
            # and create the response
            LOGGER.debug('Send response: OK')
            return srv6_manager_pb2.SRv6ManagerReply(
                status=commons_pb2.STATUS_SUCCESS)
        except NetlinkError as err:
            return srv6_manager_pb2.SRv6ManagerReply(
                status=parse_netlink_error(err))
Beispiel #2
0
    def handle_srv6_src_addr_request(self, operation, request, context):
        '''
        This function is used to setup the source address used for the SRv6
        encapsulation, equivalent to:

        > set vppctl set sr encaps source addr $VPP_SR_Policy_src_addr
        '''
        # pylint: disable=unused-argument
        #
        LOGGER.debug('Entering handle_srv6_src_addr_request')
        if operation in ['add', 'get', 'del']:
            LOGGER.error('Operation %s not supported', operation)
            return srv6_manager_pb2.SRv6ManagerReply(
                status=STATUS_CODE['STATUS_OPERATION_NOT_SUPPORTED'])
        if operation in ['change']:
            # String representing the command to be sent to VPP
            cmd = 'set sr encaps source addr %s' % str(request.src_addr)
            # Send the command to VPP
            # If success, an empty string will be returned
            # In case of error, the error message is returned
            LOGGER.debug('Sending command to VPP: %s', cmd)
            res = self.exec_vpp_cmd(cmd).decode()
            if res != '':
                # The operation failed
                logging.error('VPP returned an error: %s', res)
                return srv6_manager_pb2.SRv6ManagerReply(
                    status=STATUS_CODE['STATUS_INTERNAL_ERROR'])
            # Return the result
            LOGGER.debug('Operation completed successfully')
            return srv6_manager_pb2.SRv6ManagerReply(
                status=STATUS_CODE['STATUS_SUCCESS'])
        # Unknown operation: this is a bug
        LOGGER.error('Unrecognized operation: %s', operation)
        sys.exit(-1)
    def handle_srv6_policy_request(self, operation, request, context):
        '''
        This function is used to create, delete or change a SRv6 policy,
        equivalent to:

        > vppctl sr policy add bsid $VPP_SR_Policy_BSID next $srv6_1st_sid
          next $srv6_2nd_sid
        '''
        # Perform the operation
        if operation in ['change', 'get']:
            LOGGER.error('Operation not yet supported: %s' % operation)
            return srv6_manager_pb2.SRv6ManagerReply(
                status=commons_pb2.STATUS_OPERATION_NOT_SUPPORTED)
        if operation in ['add', 'del']:
            # Let's push the routes
            for policy in request.policies:
                # Extract BSID
                bsid_addr = policy.bsid_addr
                # Extract SID list
                segments = []
                for srv6_segment in policy.sr_path:
                    segments.append(srv6_segment.segment)
                # Extract the table
                table = policy.table
                if policy.table == -1:
                    table = None
                # Extract the metric
                metric = policy.metric
                if policy.metric == -1:
                    metric = None
                # Create a SR policy
                # This command returns a empty string in case of success
                cmd = ('sr policy %s bsid %s' % (operation, bsid_addr))
                # Add segments
                for segment in segments:
                    cmd += ' next %s' % segment
                # Add metric
                if metric is not None:
                    cmd += ' weight %s' % metric
                # Add the table
                if table is not None:
                    cmd += ' fib-table %s' % table
                # Execute the command
                LOGGER.debug('Sending command to VPP: %s' % cmd)
                res = exec_vpp_cmd(cmd).decode()
                if res != '':
                    # Failure
                    logging.error('VPP returned an error: %s' % res)
                    return srv6_manager_pb2.SRv6ManagerReply(
                        status=commons_pb2.STATUS_INTERNAL_ERROR)
        else:
            # Operation unknown: this is a bug
            LOGGER.error('Unrecognized operation: %s', operation)
            sys.exit(-1)
        # and create the response
        LOGGER.debug('Send response: OK')
        return srv6_manager_pb2.SRv6ManagerReply(
            status=commons_pb2.STATUS_SUCCESS)
    def handle_srv6_path_request(self, operation, request, context):
        # pylint: disable=unused-argument
        """Handler for SRv6 paths"""

        LOGGER.debug('config received:\n%s', request)
        # Perform operation
        try:
            if operation in ['add', 'change', 'del']:
                # Let's push the routes
                for path in request.paths:
                    # Rebuild segments
                    segments = []
                    for srv6_segment in path.sr_path:
                        segments.append(srv6_segment.segment)
                    segments.reverse()
                    table = path.table
                    if path.table == -1:
                        table = None
                    metric = path.metric
                    if path.metric == -1:
                        metric = None
                    if segments == []:
                        segments = ['::']
                    oif = None
                    if path.device != '':
                        oif = self.interface_to_idx[path.device]
                    elif operation == 'add':
                        oif = self.interface_to_idx[
                            self.non_loopback_interfaces[0]]
                    self.ip_route.route(operation,
                                        dst=path.destination,
                                        oif=oif,
                                        table=table,
                                        priority=metric,
                                        encap={
                                            'type': 'seg6',
                                            'mode': path.encapmode,
                                            'segs': segments
                                        })
            elif operation == 'get':
                return srv6_manager_pb2.SRv6ManagerReply(
                    status=commons_pb2.STATUS_OPERATION_NOT_SUPPORTED)
            else:
                # Operation unknown: this is a bug
                LOGGER.error('Unrecognized operation: %s', operation)
                sys.exit(-1)
            # and create the response
            LOGGER.debug('Send response: OK')
            return srv6_manager_pb2.SRv6ManagerReply(
                status=commons_pb2.STATUS_SUCCESS)
        except NetlinkError as err:
            return srv6_manager_pb2.SRv6ManagerReply(
                status=parse_netlink_error(err))
Beispiel #5
0
 def handle_end_x_behavior_request(self, operation, behavior):
     '''
     Handle seg6local End.X behavior
     '''
     # Extract params from request
     segment = behavior.segment
     interface = behavior.interface
     nexthop = behavior.nexthop
     table = behavior.table
     metric = behavior.metric
     # Check optional params
     #
     # Table is a optional parameter
     # -1 is the default value that means that no table has
     # been provided
     table = table if table != -1 else None
     # Metric is a optional parameter
     # -1 is the default value that means that no metric has
     # been provided
     metric = metric if metric != -1 else None
     # Perform the operation
     if operation == 'change':
         LOGGER.info('Operation %s is not yet implemented\n', operation)
         return STATUS_CODE['STATUS_OPERATION_NOT_SUPPORTED']
     if operation == 'del':
         # The operation is a "delete"
         return self.handle_srv6_behavior_del_request(behavior)
     if operation == 'get':
         # The operation is a "get"
         return self.handle_srv6_behavior_get_request(behavior)
     if operation in ['add']:
         # The operation is a "add"
         #
         # Build the command to add the behavior
         cmd = ('sr localsid address %s behavior end.x %s %s' %
                (segment, interface, nexthop))
         # Append the table to the command
         if table is not None:
             cmd += ' fib-table %s' % table
         # Send the command to VPP
         # This command returns a empty string in case of success
         # The decode() function is used to convert the response to a
         # string
         LOGGER.debug('Sending command to VPP: %s', cmd)
         res = self.exec_vpp_cmd(cmd).decode()
         if res != '':
             # The operation failed
             logging.error('VPP returned an error: %s', res)
             return STATUS_CODE['STATUS_INTERNAL_ERROR']
         # The behavior has been processed, create the response
         LOGGER.debug('Send response: OK')
         return srv6_manager_pb2.SRv6ManagerReply(
             status=STATUS_CODE['STATUS_SUCCESS'])
     # Unknown operation: this is a bug
     LOGGER.error('BUG - Unrecognized operation: %s', operation)
     sys.exit(-1)
Beispiel #6
0
    def handle_srv6_policy_request(self, operation, request, context):
        # pylint: disable=unused-argument
        """Handler for SRv6 policies"""

        LOGGER.debug('config received:\n%s', request)
        # Extract forwarding engine
        fwd_engine = request.fwd_engine
        # Perform operation
        if fwd_engine == FWD_ENGINE['linux']:
            # Linux forwarding engine does not support SRv6 policy
            return srv6_manager_pb2.SRv6ManagerReply(
                status=commons_pb2.STATUS_OPERATION_NOT_SUPPORTED)
        if fwd_engine == FWD_ENGINE['linux']:
            # VPP forwarding engine
            # TODO gestire caso VPP non abilitato o non disponibile
            return self.srv6_mgr_vpp.handle_srv6_policy_request(
                operation, request, context)
        # Unknown forwarding engine
        return srv6_manager_pb2.SRv6ManagerReply(status=commons_pb2.StatusCode.Value(
            'STATUS_INTERNAL_ERROR'))  # TODO creare un errore specifico
Beispiel #7
0
    def handle_srv6_path_request(self, operation, request, context):
        # pylint: disable=unused-argument
        """Handler for SRv6 paths"""

        LOGGER.debug('config received:\n%s', request)
        # Extract forwarding engine
        fwd_engine = request.fwd_engine
        # Perform operation
        if fwd_engine == srv6_manager_pb2.FwdEngine.Value('Linux'):
            # Linux forwarding engine
            return self.srv6_mgr_linux.handle_srv6_path_request(operation,
                                                                request,
                                                                context)
        if fwd_engine == srv6_manager_pb2.FwdEngine.Value('VPP'):
            # VPP forwarding engine
            return self.srv6_mgr_vpp.handle_srv6_path_request(operation,
                                                              request,
                                                              context)     # TODO gestire caso VPP non abilitato o non disponibile
        # Unknown forwarding engine
        return srv6_manager_pb2.SRv6ManagerReply(
            status=commons_pb2.StatusCode.Value('STATUS_INTERNAL_ERROR'))       # TODO creare un errore specifico
    def handle_srv6_src_addr_request(self, operation, request,
                                     context):  # TODO
        '''
        This function is used to setup the source address used for the SRv6
        encapsulation, equivalent to:

        > set vppctl set sr encaps source addr $VPP_SR_Policy_src_addr
        '''
        # Return value
        res = commons_pb2.STATUS_SUCCESS
        # String representing the command to be sent to VPP
        cmd = 'set sr encaps source addr %s' % str(request.src_addr)
        # Send the command to VPP
        # If success, an empty string will be returned
        LOGGER.debug('Sending command to VPP: %s' % cmd)
        res = exec_vpp_cmd(cmd).decode()
        if res != '':
            # Failure
            logging.error('VPP returned an error: %s' % res)
            res = commons_pb2.STATUS_INTERNAL_ERROR
        return srv6_manager_pb2.SRv6ManagerReply(status=res)
Beispiel #9
0
    def execute(self, operation, request, context):
        """This function dispatch the gRPC requests based
        on the entity carried in them"""

        # Handle operation
        # The operation to be executed depends on
        # the entity carried by the request message
        res = srv6_manager_pb2.SRv6ManagerReply(
            status=commons_pb2.STATUS_SUCCESS)
        if request.HasField('srv6_path_request'):
            res = self.handle_srv6_path_request(
                operation, request.srv6_path_request, context)
            if res.status != commons_pb2.STATUS_SUCCESS:
                return res
        if request.HasField('srv6_policy_request'):
            res = self.handle_srv6_policy_request(
                operation, request.srv6_policy_request, context)
            if res.status != commons_pb2.STATUS_SUCCESS:
                return res
        if request.HasField('srv6_behavior_request'):
            res = self.handle_srv6_behavior_request(
                operation, request.srv6_behavior_request, context)
        return res
Beispiel #10
0
 def handle_srv6_path_request(self, operation, request, context):
     '''
     Handler for SRv6 paths
     '''
     # pylint: disable=unused-argument
     #
     LOGGER.debug('config received:\n%s', request)
     # Perform operation
     if operation in ['change', 'get']:
         # Currently only "add" and "del" operations are supported
         LOGGER.error('Operation not yet supported: %s', operation)
         return srv6_manager_pb2.SRv6ManagerReply(
             status=STATUS_CODE['STATUS_OPERATION_NOT_SUPPORTED'])
     if operation in ['add', 'del']:
         # Let's push the routes
         for path in request.paths:
             # Extract BSID
             bsid_addr = path.bsid_addr
             # Extract SID list
             segments = []
             for srv6_segment in path.sr_path:
                 segments.append(srv6_segment.segment)
             # Extract the table
             # Table is a optional parameter
             # -1 is the default value that means that no table has
             # been provided
             table = path.table
             if path.table == -1:
                 table = None
             # Extract the metric
             # Metric is a optional parameter
             # -1 is the default value that means that no metric has
             # been provided
             metric = path.metric
             if path.metric == -1:
                 metric = None
             # Extract the encap mode
             encapmode = path.encapmode
             # Extract the destination
             destination = str(path.destination)
             # Append "/128" if no prefix len is provided
             if len(destination.split('/')) == 1:
                 destination += '/128'
             # Is a delete operation?
             del_cmd = 'del' if operation == 'del' else ''
             # Build the command to steer packets into a SR policy
             cmd = ('sr steer %s l3 %s via bsid %s' %
                    (del_cmd, destination, bsid_addr))
             # Append metric to the command
             if metric is not None:
                 cmd += ' weight %s' % metric
             # Append table to the command
             if table is not None:
                 cmd += ' fib-table %s' % table
             # Send the command to VPP
             # This command returns a empty string in case of success
             # The decode() function is used to convert the response to a
             # string
             LOGGER.debug('Sending command to VPP: %s', cmd)
             res = self.exec_vpp_cmd(cmd).decode()
             if res != '':
                 # The operation failed
                 logging.error('VPP returned an error: %s', res)
                 return srv6_manager_pb2.SRv6ManagerReply(
                     status=STATUS_CODE['STATUS_INTERNAL_ERROR'])
         # All the paths have been processed, create the response
         LOGGER.debug('Send response: OK')
         return srv6_manager_pb2.SRv6ManagerReply(
             status=STATUS_CODE['STATUS_SUCCESS'])
     # Unknown operation: this is a bug
     LOGGER.error('Unrecognized operation: %s', operation)
     sys.exit(-1)
Beispiel #11
0
    def handle_srv6_policy_request(self, operation, request, context):
        '''
        This function is used to create, delete or change a SRv6 policy,
        equivalent to:

        > vppctl sr policy add bsid $VPP_SR_Policy_BSID next $srv6_1st_sid
          next $srv6_2nd_sid
        '''
        # pylint: disable=unused-argument
        #
        LOGGER.debug('Entering handle_srv6_policy_request')
        # Perform the operation
        if operation in ['change', 'get']:
            # Currently only "add" and "del" operations are supported
            LOGGER.error('Operation not yet supported: %s', operation)
            return srv6_manager_pb2.SRv6ManagerReply(
                status=STATUS_CODE['STATUS_OPERATION_NOT_SUPPORTED'])
        if operation in ['add', 'del']:
            # Let's push the routes
            for policy in request.policies:
                # Extract BSID
                bsid_addr = policy.bsid_addr
                # Extract SID list
                segments = []
                for srv6_segment in policy.sr_path:
                    segments.append(srv6_segment.segment)
                # Extract the table
                # Table is a optional parameter
                # -1 is the default value that means that no table has
                # been provided
                table = policy.table
                if policy.table == -1:
                    table = None
                # Extract the metric
                # Metric is a optional parameter
                # -1 is the default value that means that no metric has
                # been provided
                metric = policy.metric
                if policy.metric == -1:
                    metric = None
                # Build the command to create or remove the SR policy
                cmd = ('sr policy %s bsid %s' % (operation, bsid_addr))
                # Append segments to the command
                for segment in segments:
                    cmd += ' next %s' % segment
                # Append metric to the command
                if metric is not None:
                    cmd += ' weight %s' % metric
                # Append table to the command
                if table is not None:
                    cmd += ' fib-table %s' % table
                # Send the command to VPP
                # This command returns a empty string in case of success
                # The decode() function is used to convert the response to a
                # string
                LOGGER.debug('Sending command to VPP: %s', cmd)
                res = self.exec_vpp_cmd(cmd).decode()
                if res != '':
                    # The operation failed
                    logging.error('VPP returned an error: %s', res)
                    return srv6_manager_pb2.SRv6ManagerReply(
                        status=STATUS_CODE['STATUS_INTERNAL_ERROR'])
            # All the policies have been processed, create the response
            LOGGER.debug('Send response: OK')
            return srv6_manager_pb2.SRv6ManagerReply(
                status=STATUS_CODE['STATUS_SUCCESS'])
        # Unknown operation: this is a bug
        LOGGER.error('Unrecognized operation: %s', operation)
        sys.exit(-1)
 def handle_srv6_path_request(self, operation, request, context):
     # pylint: disable=unused-argument
     '''
     Handler for SRv6 paths
     '''
     LOGGER.debug('config received:\n%s', request)
     # Perform operation
     if operation in ['change', 'get']:
         LOGGER.error('Operation not yet supported: %s' % operation)
         return srv6_manager_pb2.SRv6ManagerReply(
             status=commons_pb2.STATUS_OPERATION_NOT_SUPPORTED)
     if operation in ['add', 'del']:
         # Let's push the routes
         for path in request.paths:
             # Extract BSID
             bsid_addr = path.bsid_addr
             # Extract SID list
             segments = []
             for srv6_segment in path.sr_path:
                 segments.append(srv6_segment.segment)
             # Extract the table
             table = path.table
             if path.table == -1:
                 table = None
             # Extract the metric
             metric = path.metric
             if path.metric == -1:
                 metric = None
             # Perform operation
             encapmode = path.encapmode
             # Steer packets into a SR policy
             # This command returns a empty string in case of success
             destination = str(path.destination)
             if len(destination.split('/')) == 1:
                 destination += '/128'
             # Is a delete operation?
             del_cmd = 'del' if operation == 'del' else ''
             # Build the command
             cmd = ('sr steer %s l3 %s via bsid %s' %
                    (del_cmd, destination, bsid_addr))
             # Add the metric
             if metric is not None:
                 cmd += ' weight %s' % metric
             # Add the table
             if table is not None:
                 cmd += ' fib-table %s' % table
             # Execute the command
             LOGGER.debug('Sending command to VPP: %s' % cmd)
             res = exec_vpp_cmd(cmd).decode()
             if res != '':
                 # Failure
                 logging.error('VPP returned an error: %s' % res)
                 return srv6_manager_pb2.SRv6ManagerReply(
                     status=commons_pb2.STATUS_INTERNAL_ERROR)
     else:
         # Operation unknown: this is a bug
         LOGGER.error('Unrecognized operation: %s', operation)
         sys.exit(-1)
     # and create the response
     LOGGER.debug('Send response: OK')
     return srv6_manager_pb2.SRv6ManagerReply(
         status=commons_pb2.STATUS_SUCCESS)