/** * Set match in an object of type of_flow_modify. * @param obj Pointer to an object of type of_flow_modify. * @param match Pointer to the child of type of_match_t. * * If the child's wire buffer is the same as the parent's, then * nothing is done as the changes have already been registered in the * parent. Otherwise, the data in the child's wire buffer is inserted * into the parent's and the appropriate lengths are updated. */ int WARN_UNUSED_RESULT of_flow_modify_match_set( of_flow_modify_t *obj, of_match_t *match) { of_wire_buffer_t *wbuf; int offset = 0; /* Offset of value relative to the start obj */ int abs_offset; /* Offset of value relative to start of wbuf */ of_version_t ver; int cur_len = 0; /* Current length of object data */ int new_len, delta; /* For set, need new length and delta */ of_octets_t match_octets; /* Serialized string for match */ ASSERT(IS_FLOW_MOD_SUBTYPE(obj->object_id)); ver = obj->version; wbuf = OF_OBJECT_TO_WBUF(obj); ASSERT(wbuf != NULL); /* By version, determine offset and current length (where needed) */ switch (ver) { case OF_VERSION_1_0: offset = 8; cur_len = _WIRE_MATCH_PADDED_LEN(obj, offset); break; case OF_VERSION_1_1: offset = 48; cur_len = _WIRE_MATCH_PADDED_LEN(obj, offset); break; case OF_VERSION_1_2: case OF_VERSION_1_3: offset = 48; cur_len = _WIRE_MATCH_PADDED_LEN(obj, offset); break; default: ASSERT(0); } abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset); ASSERT(abs_offset >= 0); ASSERT(cur_len >= 0 && cur_len < 64 * 1024); /* Match object */ OF_TRY(of_match_serialize(ver, match, &match_octets)); new_len = match_octets.bytes; of_wire_buffer_replace_data(wbuf, abs_offset, cur_len, match_octets.data, new_len); /* Free match serialized octets */ FREE(match_octets.data); /* Not scalar, update lengths if needed */ delta = new_len - cur_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } OF_LENGTH_CHECK_ASSERT(obj); return OF_ERROR_NONE; }
int of_list_append_bind(of_object_t *parent, of_object_t *child) { if (parent == NULL || child == NULL || parent->wbuf == NULL) { return OF_ERROR_PARAM; } if (!of_object_can_grow(parent, parent->length + child->length)) { return OF_ERROR_RESOURCE; } object_child_attach(parent, child, parent->length, child->length); /* Update the wire length and type if needed */ of_object_wire_length_set(child, child->length); of_object_wire_type_set(child); /* Update the parent's length */ of_object_parent_length_update(parent, child->length); OF_LENGTH_CHECK_ASSERT(parent); return OF_ERROR_NONE; }
/** * Set data in an object of type of_packet_in. * @param obj Pointer to an object of type of_packet_in. * @param data The value to write into the object */ int WARN_UNUSED_RESULT of_packet_in_data_set( of_packet_in_t *obj, of_octets_t *data) { of_wire_buffer_t *wbuf; int offset = 0; /* Offset of value relative to the start obj */ int abs_offset; /* Offset of value relative to start of wbuf */ of_version_t ver; int cur_len = 0; /* Current length of object data */ int new_len, delta; /* For set, need new length and delta */ ASSERT(obj->object_id == OF_PACKET_IN); ver = obj->version; wbuf = OF_OBJECT_TO_WBUF(obj); ASSERT(wbuf != NULL); /* By version, determine offset and current length (where needed) */ switch (ver) { case OF_VERSION_1_0: offset = 18; cur_len = _END_LEN(obj, offset); break; case OF_VERSION_1_1: offset = 24; cur_len = _END_LEN(obj, offset); break; case OF_VERSION_1_2: case OF_VERSION_1_3: offset = _PACKET_IN_DATA_OFFSET(obj); cur_len = _END_LEN(obj, offset); break; default: ASSERT(0); } abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset); ASSERT(abs_offset >= 0); ASSERT(cur_len >= 0 && cur_len < 64 * 1024); new_len = data->bytes; of_wire_buffer_grow(wbuf, abs_offset + (new_len - cur_len)); of_wire_buffer_octets_data_set(wbuf, abs_offset, data, cur_len); /* Not scalar, update lengths if needed */ delta = new_len - cur_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } OF_LENGTH_CHECK_ASSERT(obj); return OF_ERROR_NONE; }
static int flow_removed_setup_from_flow_add_common(of_flow_removed_t *obj, of_flow_add_t *flow_add, int removed_match_offset, int add_match_offset) { int add_len, removed_len; of_wire_buffer_t *wbuf; int abs_offset; int delta; uint16_t val16; uint64_t cookie; of_octets_t match_octets; /* Transfer the match underlying object from add to removed obj */ wbuf = OF_OBJECT_TO_WBUF(obj); removed_len = _WIRE_MATCH_PADDED_LEN(obj, removed_match_offset); add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset); match_octets.bytes = add_len; match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset); /* Copy data into flow removed */ abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, removed_match_offset); of_wire_buffer_replace_data(wbuf, abs_offset, removed_len, match_octets.data, add_len); /* Not scalar, update lengths if needed */ delta = add_len - removed_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } of_flow_add_cookie_get(flow_add, &cookie); of_flow_removed_cookie_set(obj, cookie); of_flow_add_priority_get(flow_add, &val16); of_flow_removed_priority_set(obj, val16); of_flow_add_idle_timeout_get(flow_add, &val16); of_flow_removed_idle_timeout_set(obj, val16); if (obj->version >= OF_VERSION_1_2) { of_flow_add_hard_timeout_get(flow_add, &val16); of_flow_removed_hard_timeout_set(obj, val16); } return OF_ERROR_NONE; }
int of_packet_in_setup_from_flow_add(of_packet_in_t *obj, of_flow_add_t *flow_add) { int add_len, pkt_in_len; of_wire_buffer_t *wbuf; int abs_offset; int delta; const int pkt_in_match_offset = 16; const int add_match_offset = 48; of_octets_t match_octets; if (obj->version < OF_VERSION_1_2) { /* Nothing to be done before OF 1.2 */ return OF_ERROR_NONE; } /* Transfer match struct from flow add to packet in object */ wbuf = OF_OBJECT_TO_WBUF(obj); pkt_in_len = _WIRE_MATCH_PADDED_LEN(obj, pkt_in_match_offset); add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset); match_octets.bytes = add_len; match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset); /* Copy data into pkt_in msg */ abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, pkt_in_match_offset); of_wire_buffer_replace_data(wbuf, abs_offset, pkt_in_len, match_octets.data, add_len); /* Not scalar, update lengths if needed */ delta = add_len - pkt_in_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } return OF_ERROR_NONE; }
/** * Generic atomic list append operation * @param list The list to which an item is being appended * @param item THe item to append to the list * * The contents of the item are copied to the end of the list. * Currently assumes the list is at the end of its parent. */ int of_list_append(of_object_t *list, of_object_t *item) { int new_len; new_len = list->length + item->length; if (!of_object_can_grow(list, new_len)) { return OF_ERROR_RESOURCE; } of_wire_buffer_grow(list->wbuf, OF_OBJECT_ABSOLUTE_OFFSET(list, new_len)); MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length), OF_OBJECT_BUFFER_INDEX(item, 0), item->length); /* Update the list's length */ of_object_parent_length_update(list, item->length); OF_LENGTH_CHECK_ASSERT(list); return OF_ERROR_NONE; }
/** * Set elements in an object of type of_hello. * @param obj Pointer to an object of type of_hello. * @param elements Pointer to the child of type of_list_hello_elem_t. * * If the child's wire buffer is the same as the parent's, then * nothing is done as the changes have already been registered in the * parent. Otherwise, the data in the child's wire buffer is inserted * into the parent's and the appropriate lengths are updated. */ int WARN_UNUSED_RESULT of_hello_elements_set( of_hello_t *obj, of_list_hello_elem_t *elements) { of_wire_buffer_t *wbuf; int offset = 0; /* Offset of value relative to the start obj */ int abs_offset; /* Offset of value relative to start of wbuf */ of_version_t ver; int cur_len = 0; /* Current length of object data */ int new_len, delta; /* For set, need new length and delta */ ASSERT(obj->object_id == OF_HELLO); ver = obj->version; wbuf = OF_OBJECT_TO_WBUF(obj); ASSERT(wbuf != NULL); /* By version, determine offset and current length (where needed) */ switch (ver) { case OF_VERSION_1_3: offset = 8; cur_len = _END_LEN(obj, offset); break; default: ASSERT(0); } abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset); ASSERT(abs_offset >= 0); ASSERT(cur_len >= 0 && cur_len < 64 * 1024); /* LOCI object type */ new_len = elements->length; /* If underlying buffer already shared; nothing to do */ if (obj->wire_object.wbuf == elements->wire_object.wbuf) { of_wire_buffer_grow(wbuf, abs_offset + new_len); /* Verify that the offsets are correct */ ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(elements, 0)); /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */ return OF_ERROR_NONE; } /* Otherwise, replace existing object in data buffer */ of_wire_buffer_replace_data(wbuf, abs_offset, cur_len, OF_OBJECT_BUFFER_INDEX(elements, 0), new_len); /* @fixme Shouldn't this precede copying value's data to buffer? */ if (elements->wire_length_set != NULL) { elements->wire_length_set((of_object_t *)elements, elements->length); } /* Not scalar, update lengths if needed */ delta = new_len - cur_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } OF_LENGTH_CHECK_ASSERT(obj); return OF_ERROR_NONE; }
static int flow_stats_entry_setup_from_flow_add_common(of_flow_stats_entry_t *obj, of_flow_add_t *flow_add, of_object_t *effects, int entry_match_offset, int add_match_offset) { int entry_len, add_len; of_wire_buffer_t *wbuf; int abs_offset; int delta; uint16_t val16; uint64_t cookie; of_octets_t match_octets; /* Transfer the match underlying object from add to stats entry */ wbuf = OF_OBJECT_TO_WBUF(obj); entry_len = _WIRE_MATCH_PADDED_LEN(obj, entry_match_offset); add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset); match_octets.bytes = add_len; match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset); /* Copy data into flow entry */ abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, entry_match_offset); of_wire_buffer_replace_data(wbuf, abs_offset, entry_len, match_octets.data, add_len); /* Not scalar, update lengths if needed */ delta = add_len - entry_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } of_flow_add_cookie_get(flow_add, &cookie); of_flow_stats_entry_cookie_set(obj, cookie); of_flow_add_priority_get(flow_add, &val16); of_flow_stats_entry_priority_set(obj, val16); of_flow_add_idle_timeout_get(flow_add, &val16); of_flow_stats_entry_idle_timeout_set(obj, val16); of_flow_add_hard_timeout_get(flow_add, &val16); of_flow_stats_entry_hard_timeout_set(obj, val16); /* Effects may come from different places */ if (effects != NULL) { if (obj->version == OF_VERSION_1_0) { OF_TRY(of_flow_stats_entry_actions_set(obj, (of_list_action_t *)effects)); } else { OF_TRY(of_flow_stats_entry_instructions_set(obj, (of_list_instruction_t *)effects)); } } else { if (obj->version == OF_VERSION_1_0) { of_list_action_t actions; of_flow_add_actions_bind(flow_add, &actions); OF_TRY(of_flow_stats_entry_actions_set(obj, &actions)); } else { of_list_instruction_t instructions; of_flow_add_instructions_bind(flow_add, &instructions); OF_TRY(of_flow_stats_entry_instructions_set(obj, &instructions)); } } return OF_ERROR_NONE; }
/** * Set actions in an object of type of_packet_out. * @param obj Pointer to an object of type of_packet_out. * @param actions Pointer to the child of type of_list_action_t. * * If the child's wire buffer is the same as the parent's, then * nothing is done as the changes have already been registered in the * parent. Otherwise, the data in the child's wire buffer is inserted * into the parent's and the appropriate lengths are updated. */ int WARN_UNUSED_RESULT of_packet_out_actions_set( of_packet_out_t *obj, of_list_action_t *actions) { of_wire_buffer_t *wbuf; int offset = 0; /* Offset of value relative to the start obj */ int abs_offset; /* Offset of value relative to start of wbuf */ of_version_t ver; int cur_len = 0; /* Current length of object data */ int new_len, delta; /* For set, need new length and delta */ ASSERT(obj->object_id == OF_PACKET_OUT); ver = obj->version; wbuf = OF_OBJECT_TO_WBUF(obj); ASSERT(wbuf != NULL); /* By version, determine offset and current length (where needed) */ switch (ver) { case OF_VERSION_1_0: offset = 16; cur_len = _PACKET_OUT_ACTION_LEN(obj); break; case OF_VERSION_1_1: case OF_VERSION_1_2: case OF_VERSION_1_3: offset = 24; cur_len = _PACKET_OUT_ACTION_LEN(obj); break; default: ASSERT(0); } abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset); ASSERT(abs_offset >= 0); ASSERT(cur_len >= 0 && cur_len < 64 * 1024); /* LOCI object type */ new_len = actions->length; /* If underlying buffer already shared; nothing to do */ if (obj->wire_object.wbuf == actions->wire_object.wbuf) { of_wire_buffer_grow(wbuf, abs_offset + new_len); /* Verify that the offsets are correct */ ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(actions, 0)); /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */ return OF_ERROR_NONE; } /* Otherwise, replace existing object in data buffer */ of_wire_buffer_replace_data(wbuf, abs_offset, cur_len, OF_OBJECT_BUFFER_INDEX(actions, 0), new_len); /* Special case for setting action lengths */ _PACKET_OUT_ACTION_LEN_SET(obj, actions->length); /* Not scalar, update lengths if needed */ delta = new_len - cur_len; if (delta != 0) { /* Update parent(s) */ of_object_parent_length_update((of_object_t *)obj, delta); } OF_LENGTH_CHECK_ASSERT(obj); return OF_ERROR_NONE; }