def parseGrpcErrorBinaryDetails(grpc_error): if grpc_error.code() != grpc.StatusCode.UNKNOWN: return None error = None # The gRPC Python package does not have a convenient way to access the # binary details for the error: they are treated as trailing metadata. for meta in grpc_error.trailing_metadata(): if meta[0] == "grpc-status-details-bin": error = status_pb2.Status() error.ParseFromString(meta[1]) break if error is None: # no binary details field return None if len(error.details) == 0: # binary details field has empty Any details repeated field return None indexed_p4_errors = [] for idx, one_error_any in enumerate(error.details): p4_error = p4runtime_pb2.Error() if not one_error_any.Unpack(p4_error): raise P4RuntimeErrorFormatException( "Cannot convert Any message to p4.Error") if p4_error.canonical_code == code_pb2.OK: continue indexed_p4_errors += [(idx, p4_error)] return indexed_p4_errors
def next(self): while self.idx < len(self.errors): p4_error = p4runtime_pb2.Error() one_error_any = self.errors[self.idx] if not one_error_any.Unpack(p4_error): raise P4RuntimeErrorFormatException( "Cannot convert Any message to p4.Error") if p4_error.canonical_code == code_pb2.OK: continue v = self.idx, p4_error self.idx += 1 return v raise StopIteration
def process_write_request_pvs(request): switch = SwitchConf.getSwitchById(request.device_id) for request_update in request.updates: if request_update.entity.HasField("table_entry"): switch_id = switch.switch_id table_id = request_update.entity.table_entry.table_id switch_table = SwitchConf.getSwitchTableById( switch.switch_id, table_id) if switch_table == False: ontext.set_code(grpc.StatusCode.NOT_FOUND) context.set_details( "Table with id {} from switch {} not found".format( table_id, switch.switch_name)) return response action_id = request_update.entity.table_entry.action.action.action_id try: table_action = SwitchConf.table_action_dict[switch_id, table_id, action_id] except KeyError: context.set_code(grpc.StatusCode.NOT_FOUND) context.set_details( "Action with id {} from table {}, switch {} not found". format(action_id, switch_table.table_name, switch.switch_name)) return response # Necessary match manipulations. match = request_update.entity.table_entry.match[0] match_key = request_update.entity.table_entry.match[ 0].exact.value match_key = match_key.split() # Necessary action manipulations action_params = request_update.entity.table_entry.action.action.params action_key = action_params[0].value action_key = action_key.split() check_bytestr = re.match("[\\x00-\\x1F\\x80-\\xFF]", match_key[0]) if check_bytestr: # Match value contains a byte string # Need to decode it match_hexvalue = hexlify(match_key[0]) action_hexvalue = hexlify(action_key[0]) if convert.matchesMac(match_hexvalue) == True: decoded_key = convert.decodeMac(match_key[0]) match_key = [] match_key.insert(0, decoded_key) if convert.matchesPort(action_hexvalue) == True: decoded_port = convert.decodePort(action_hexvalue) action_key = [] action_key.insert(0, decoded_port) if convert.matchesIPv4(match_key) == True: decoded_key = convert.decodeIpv4(match_key[0]) match_key = [] match_key.insert(0, decoded_key) else: #match contains a normal string match_key = ast.literal_eval(json.dumps(match_key)) action_key = ast.literal_eval(json.dumps(action_key)) # Insert an entry. if request_update.type == p4runtime_pb2.Update.INSERT: if match.HasField("exact"): p4_tables_api.table_cam_add_entry( switch, switch_table, table_action, match_key, action_key) # Update an entry. elif request_update.type == p4runtime_pb2.Update.MODIFY: # First: Read the entry provided by the client to see its existance in the switch. # TODO: hardcoded yet, need to remove dependence on switch specific p4_tables_api. if match.HasField("exact"): # key = map(p4_px_tables.convert_to_int, match_key) (found, val) = p4_tables_api.table_cam_read_entry( switch_table.switch_id, switch_table.table_name, match_key) if found != "False": # p4_tables_api.table_cam_delete_entry(switch_table.switch_id, switch_table.table_name, match_key) # Second: Modify the existing entry with the values stored in the variables. ServerConfig.print_debug( "Match key: {} exists in table {} of switch {}: found {}, val {}. Updating..." .format(match_key, switch_table.table_name, switch.switch_name, found, val)) p4_tables_api.table_cam_add_entry( switch_table.switch_id, switch_table.table_name, match_key, action_name, action_key) else: ServerConfig.print_debug( "Error: Match key {} not found in table {} of switch {}" .format(match_key, switch_table.table_name, switch.switch_name)) response = p4runtime_pb2.Error() response.canonical_code = code_pb2.NOT_FOUND return response # Delete an entry. elif request_update.type == p4runtime_pb2.Update.DELETE: # First: Use read entry which will check the existence, then delete it. if match.HasField("exact"): # key = map(p4_px_tables.convert_to_int, match_key) (found, val) = p4_tables_api.table_cam_read_entry( switch_table.switch_id, switch_table.table_name, match_key) if found != "False": ServerConfig.print_debug( "Match key: {} exists in table {} of switch {}: found {}, val {}. Deleting..." .format(match_key, switch_table.table_name, switch.switch_name, found, val)) p4_tables_api.table_cam_delete_entry( switch_table.switch_id, switch_table.table_name, match_key) else: ServerConfig.print_debug( "Error: Match key {} not found in table {} of switch {}" .format(match_key, switch_table.table_name, switch.switch_name)) else: context.set_code(grpc.StatusCode.INVALID_ARGUMENT) context.set_details( "Update code {} is invalid. Please inform a valid one (INSERT, MODIFY OR DELETE" .format(update[0].type)) return response # TODO: refactor. elif request_update.entity.HasField("register_entry"): # Verify if the user has permission to write into registers from the requested switch. if ConnectionArray.verifyPermission( context, switch, PermEnum.DEVICE_WRITE | PermEnum.RESOURCE_WRITE) is False: ServerConfig.print_debug( "Error: user does not have permission to write into registers from switch '{}'" .format(switch.switch_name)) context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details( "User does not have permission to write into registers from switch '{}'" .format(switch.switch_name)) return response register_id = request_update.entity.register_entry.register_id register = SwitchConf.getRegisterById(switch_id, register_id) result = p4_regs_api.reg_write( register.switch_id, register.reg_name, request_update.entity.register_entry.index.index, int(request_update.entity.register_entry.data.enum_value)) return response return response