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