[ovs-dev] [PATCH 08/10] ofp-actions/set-field: introduce set_field related functions
Isaku Yamahata
yamahata at valinux.co.jp
Wed Jun 27 04:27:03 UTC 2012
This patch implements set field action.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
---
lib/automake.mk | 2 +
lib/set-field.c | 447 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/set-field.h | 57 +++++++
3 files changed, 506 insertions(+), 0 deletions(-)
create mode 100644 lib/set-field.c
create mode 100644 lib/set-field.h
diff --git a/lib/automake.mk b/lib/automake.mk
index 244c76a..a6d8dbd 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -135,6 +135,8 @@ lib_libopenvswitch_a_SOURCES = \
lib/reconnect.c \
lib/reconnect.h \
lib/sat-math.h \
+ lib/set-field.c \
+ lib/set-field.h \
lib/sha1.c \
lib/sha1.h \
lib/shash.c \
diff --git a/lib/set-field.c b/lib/set-field.c
new file mode 100644
index 0000000..039e12b
--- /dev/null
+++ b/lib/set-field.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2012 Isaku Yamahata <yamahata at private email ne jp>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include "dynamic-string.h"
+#include "meta-flow.h"
+#include "odp-util.h"
+#include "ofp-actions.h"
+#include "openflow/openflow.h"
+#include "openvswitch/types.h"
+#include "set-field.h"
+
+enum ofperr
+set_field_put(struct ofpbuf *out, enum mf_field_id id, const void *valuep)
+{
+ struct ofpact_set_field *osf;
+ osf = ofpact_put_SET_FIELD(out);
+ osf->mf = mf_from_id(id);
+ memcpy(&osf->value, valuep, osf->mf->n_bytes);
+
+ if (!mf_is_value_valid(osf->mf, &osf->value)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ return 0;
+}
+
+enum ofperr
+set_field_check(const struct ofpact_set_field *osf,
+ const struct flow *flow)
+{
+ if (!mf_are_prereqs_ok(osf->mf, flow)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ // TODO:XXX?
+ return 0;
+}
+
+static bool
+set_field_mf_allowed(const struct mf_field *mf)
+{
+ if (!mf->writable || mf->oxm_header == 0 /* TODO: check meta data */) {
+ return false;
+ }
+ return true;
+}
+
+enum ofperr
+set_field_from_openflow(const struct ofp12_action_set_field* oasf,
+ struct ofpbuf *ofpacts)
+{
+ ovs_be32 *p = (ovs_be32*)oasf->field;
+ uint32_t oxm_header = ntohl(*p);
+ uint8_t oxm_length = NXM_LENGTH(oxm_header);
+ struct ofpact_set_field *set_field = ofpact_put_SET_FIELD(ofpacts);
+ const struct mf_field *mf;
+
+ if (NXM_HASMASK(oxm_header)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ if (oasf->len != ROUND_UP(sizeof(*oasf) + oxm_length,
+ OFP12_ACTION_SET_FIELD_ALIGN)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ mf = mf_from_nxm_header(oxm_header);
+ if (!set_field_mf_allowed(mf)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ memcpy(&set_field->value, oasf + 1, mf->n_bytes);
+ if (!mf_is_value_valid(mf, &set_field->value)) {
+ return OFPERR_OFPBMC_BAD_VALUE;
+ }
+
+ set_field->mf = mf;
+ return 0;
+}
+
+static void
+set_field_put_value(void *valuep, const struct ofpact_set_field *set_field)
+{
+ memcpy(valuep, &set_field->value, set_field->mf->n_bytes);
+}
+
+void
+set_field_to_nxact(const struct ofpact_set_field *set_field,
+ struct ofpbuf *out)
+{
+ switch (set_field->mf->id) {
+ case MFF_TUN_ID:
+ case MFF_IN_PORT:
+ case MFF_REG0 ... MFF_REG_END:
+ case MFF_ETH_SRC:
+ case MFF_ETH_DST:
+ case MFF_ETH_TYPE:
+ case MFF_VLAN_TCI:
+ case MFF_VLAN_VID:
+ case MFF_VLAN_PCP:
+ case MFF_IPV4_SRC:
+ case MFF_IPV4_DST:
+ case MFF_IPV6_SRC:
+ case MFF_IPV6_DST:
+ case MFF_IPV6_LABEL:
+ case MFF_IP_PROTO:
+ case MFF_IP_DSCP:
+ case MFF_IP_ECN:
+ case MFF_IP_TTL:
+ case MFF_IP_FRAG:
+ case MFF_ARP_OP:
+ case MFF_ARP_SPA:
+ case MFF_ARP_TPA:
+ case MFF_ARP_SHA:
+ case MFF_ARP_THA:
+ case MFF_TCP_SRC:
+ case MFF_TCP_DST:
+ case MFF_UDP_SRC:
+ case MFF_UDP_DST:
+ case MFF_ICMPV4_TYPE:
+ case MFF_ICMPV4_CODE:
+ case MFF_ICMPV6_TYPE:
+ case MFF_ICMPV6_CODE:
+ case MFF_ND_TARGET:
+ case MFF_ND_SLL:
+ case MFF_ND_TLL:
+ case MFF_N_IDS:
+ default:
+ NOT_REACHED();
+ break;
+ }
+}
+
+bool
+set_field_to_openflow10(const struct ofpact_set_field *set_field,
+ struct ofpbuf *out)
+{
+ switch (set_field->mf->id) {
+ case MFF_VLAN_VID:
+ set_field_put_value(&ofputil_put_OFPAT10_SET_VLAN_VID(out)->vlan_vid,
+ set_field);
+ break;
+ case MFF_VLAN_PCP:
+ set_field_put_value(&ofputil_put_OFPAT10_SET_VLAN_PCP(out)->vlan_pcp,
+ set_field);
+ break;
+ case MFF_ETH_SRC:
+ set_field_put_value(ofputil_put_OFPAT10_SET_DL_SRC(out)->dl_addr,
+ set_field);
+ break;
+ case MFF_ETH_DST:
+ set_field_put_value(ofputil_put_OFPAT10_SET_DL_DST(out)->dl_addr,
+ set_field);
+ break;
+ case MFF_IPV4_SRC:
+ set_field_put_value(&ofputil_put_OFPAT10_SET_NW_SRC(out)->nw_addr,
+ set_field);
+ break;
+ case MFF_IPV4_DST:
+ set_field_put_value(&ofputil_put_OFPAT10_SET_NW_DST(out)->nw_addr,
+ set_field);
+ break;
+
+ case MFF_TUN_ID:
+ case MFF_IN_PORT:
+ case MFF_REG0 ... MFF_REG_END:
+ case MFF_ETH_TYPE:
+ case MFF_VLAN_TCI:
+ case MFF_IPV6_SRC:
+ case MFF_IPV6_DST:
+ case MFF_IPV6_LABEL:
+ case MFF_IP_PROTO:
+ case MFF_IP_DSCP:
+ case MFF_IP_ECN:
+ case MFF_IP_TTL:
+ case MFF_IP_FRAG:
+ case MFF_ARP_OP:
+ case MFF_ARP_SPA:
+ case MFF_ARP_TPA:
+ case MFF_ARP_SHA:
+ case MFF_ARP_THA:
+ case MFF_TCP_SRC:
+ case MFF_TCP_DST:
+ case MFF_UDP_SRC:
+ case MFF_UDP_DST:
+ case MFF_ICMPV4_TYPE:
+ case MFF_ICMPV4_CODE:
+ case MFF_ICMPV6_TYPE:
+ case MFF_ICMPV6_CODE:
+ case MFF_ND_TARGET:
+ case MFF_ND_SLL:
+ case MFF_ND_TLL:
+ case MFF_N_IDS:
+ default:
+ NOT_REACHED();
+ }
+
+ return true;
+}
+
+bool
+set_field_to_openflow11(const struct ofpact_set_field *set_field,
+ struct ofpbuf *out)
+{
+ switch (set_field->mf->id) {
+ case MFF_VLAN_VID:
+ set_field_put_value(&ofputil_put_OFPAT11_SET_VLAN_VID(out)->vlan_vid,
+ set_field);
+ break;
+ case MFF_VLAN_PCP:
+ set_field_put_value(&ofputil_put_OFPAT11_SET_VLAN_PCP(out)->vlan_pcp,
+ set_field);
+ break;
+ case MFF_ETH_SRC:
+ set_field_put_value(ofputil_put_OFPAT11_SET_DL_SRC(out)->dl_addr,
+ set_field);
+ break;
+ case MFF_ETH_DST:
+ set_field_put_value(ofputil_put_OFPAT11_SET_DL_DST(out)->dl_addr,
+ set_field);
+ break;
+ case MFF_IPV4_SRC:
+ set_field_put_value(&ofputil_put_OFPAT11_SET_NW_SRC(out)->nw_addr,
+ set_field);
+ break;
+ case MFF_IPV4_DST:
+ set_field_put_value(&ofputil_put_OFPAT11_SET_NW_DST(out)->nw_addr,
+ set_field);
+ break;
+
+ case MFF_TUN_ID:
+ case MFF_IN_PORT:
+ case MFF_REG0 ... MFF_REG_END:
+ case MFF_ETH_TYPE:
+ case MFF_VLAN_TCI:
+ case MFF_IPV6_SRC:
+ case MFF_IPV6_DST:
+ case MFF_IPV6_LABEL:
+ case MFF_IP_PROTO:
+ case MFF_IP_DSCP:
+ case MFF_IP_ECN:
+ case MFF_IP_TTL:
+ case MFF_IP_FRAG:
+ case MFF_ARP_OP:
+ case MFF_ARP_SPA:
+ case MFF_ARP_TPA:
+ case MFF_ARP_SHA:
+ case MFF_ARP_THA:
+ case MFF_TCP_SRC:
+ case MFF_TCP_DST:
+ case MFF_UDP_SRC:
+ case MFF_UDP_DST:
+ case MFF_ICMPV4_TYPE:
+ case MFF_ICMPV4_CODE:
+ case MFF_ICMPV6_TYPE:
+ case MFF_ICMPV6_CODE:
+ case MFF_ND_TARGET:
+ case MFF_ND_SLL:
+ case MFF_ND_TLL:
+ case MFF_N_IDS:
+ default:
+ NOT_REACHED();
+ }
+
+ return true;
+}
+
+void
+set_field_parse_with_id(enum mf_field_id id,
+ const char *arg, struct ofpbuf *ofpacts)
+{
+ const struct mf_field *mf = mf_from_id(id);
+ struct ofpact_set_field *set_field = ofpact_put_SET_FIELD(ofpacts);
+ const char *ret;
+ set_field->mf = mf;
+
+ if (!set_field_mf_allowed(mf)){
+ ovs_fatal(0, "%s: field can't be written", mf->name);
+ }
+ ret = mf_parse_value(mf, arg, &set_field->value);
+ if (ret) {
+ ovs_fatal(0, "%s", ret);
+ }
+ if (!mf_is_value_valid(mf, &set_field->value)) {
+ ovs_fatal(0, "%s: invalid field value for field %s", arg, mf->name);
+ }
+}
+
+void
+set_field_parse(const char *s, struct ofpbuf *ofpacts)
+{
+ char *pos;
+ char *copy;
+ char *key;
+ char *value_s;
+ const struct mf_field *mf;
+ union mf_value value;
+ struct ofpact_set_field *set_field;
+
+ pos = copy = xstrdup(s);
+ if (!ofputil_parse_key_value(&pos, &key, &value_s)) {
+ goto out;
+ }
+ mf = mf_from_name(key);
+ if (!mf) {
+ goto out;
+ }
+ if (!set_field_mf_allowed(mf)){
+ goto out;
+ }
+ if (mf_parse_value(mf, value_s, &value)) {
+ goto out;
+ }
+ if (!mf_is_value_valid(mf, &value)) {
+ goto out;
+ }
+ set_field = ofpact_put_SET_FIELD(ofpacts);
+ set_field->mf = mf;
+ set_field->value = value;
+
+out:
+ free(copy);
+
+ /* TODO:XXX error */
+}
+
+struct format_prefix {
+ enum mf_field_id id;
+ const char* prefix;
+};
+struct format_prefix format_prefix[] = {
+ {
+ .id = MFF_VLAN_VID,
+ .prefix = "mod_vlan_vid",
+ }, {
+ .id = MFF_VLAN_PCP,
+ .prefix = "mod_vlan_pcp",
+ }, {
+ .id = MFF_ETH_SRC,
+ .prefix = "mod_dl_src",
+ }, {
+ .id = MFF_ETH_DST,
+ .prefix = "mod_dl_dst",
+ }, {
+ .id = MFF_IPV4_SRC,
+ .prefix = "mod_nw_src",
+ }, {
+ .id = MFF_IPV4_DST,
+ .prefix = "mod_nw_dst",
+ }, {
+ .id = MFF_IP_DSCP,
+ .prefix = "mod_nw_tos",
+ },
+};
+
+
+void
+set_field_format(const struct ofpact_set_field *set_field, struct ds *s)
+{
+ struct format_prefix *fp;
+
+ for (fp = format_prefix; fp < &format_prefix[ARRAY_SIZE(format_prefix)];
+ fp++) {
+ if (fp->id == set_field->mf->id) {
+ ds_put_cstr(s, fp->prefix);
+ ds_put_cstr(s, ":");
+ mf_format(set_field->mf, &set_field->value, NULL, s);
+ return;
+ }
+ }
+
+ NOT_REACHED();
+}
+
+void
+set_field_execute(const struct ofpact_set_field *set_field,
+ struct flow *flow, struct flow *base_flow,
+ struct ofpbuf *odp_actions)
+{
+ switch (set_field->mf->id) {
+ case MFF_IP_DSCP:
+ /* OpenFlow 1.0 only supports IPv4. */
+ /* TODO:XXX 1.1+ */
+ if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ mf_set_flow_value(set_field->mf, &set_field->value, flow);
+ }
+ break;
+
+ case MFF_ETH_SRC:
+ case MFF_ETH_DST:
+ case MFF_VLAN_VID:
+ case MFF_VLAN_PCP:
+ case MFF_IPV4_SRC:
+ case MFF_IPV4_DST:
+ mf_set_flow_value(set_field->mf, &set_field->value, flow);
+ break;
+
+ case MFF_ETH_TYPE:
+ case MFF_VLAN_TCI:
+ case MFF_IP_PROTO:
+ case MFF_IP_ECN:
+ case MFF_TCP_SRC:
+ case MFF_TCP_DST:
+ case MFF_UDP_SRC:
+ case MFF_UDP_DST:
+ case MFF_ARP_OP:
+ case MFF_ARP_SPA:
+ case MFF_ARP_TPA:
+ case MFF_ARP_SHA:
+ case MFF_ARP_THA:
+ case MFF_IPV6_SRC:
+ case MFF_IPV6_DST:
+ case MFF_ICMPV4_TYPE:
+ case MFF_ICMPV4_CODE:
+ case MFF_ICMPV6_TYPE:
+ case MFF_ICMPV6_CODE:
+ case MFF_ND_TARGET:
+ case MFF_ND_SLL:
+ case MFF_ND_TLL:
+ /* TODO:XXX */
+ mf_set_flow_value(set_field->mf, &set_field->value, flow);
+ break;
+
+ case MFF_TUN_ID:
+ case MFF_IN_PORT:
+ case MFF_REG0 ... MFF_REG_END:
+ case MFF_IP_TTL:
+ case MFF_IP_FRAG:
+ case MFF_IPV6_LABEL:
+ case MFF_N_IDS:
+ default:
+ NOT_REACHED();
+ break;
+ }
+}
+
+/* TODO:XXX udatapath case */
diff --git a/lib/set-field.h b/lib/set-field.h
new file mode 100644
index 0000000..44375ce
--- /dev/null
+++ b/lib/set-field.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012 Isaku Yamahata <yamahata at private email ne jp>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SET_FIELD_H
+#define SET_FIELD_H 1
+
+struct ds;
+struct ofp12_action_set_field;
+struct ofpbuf;
+struct ofpact_set_field;
+enum mf_field_id;
+
+enum ofperr
+set_field_put(struct ofpbuf *out, enum mf_field_id id, const void *valuep);
+enum ofperr
+set_field_check(const struct ofpact_set_field *set_field,
+ const struct flow *flow);
+
+enum ofperr
+set_field_from_openflow(const struct ofp12_action_set_field* oasf,
+ struct ofpbuf *ofpacts);
+void
+set_field_to_nxact(const struct ofpact_set_field *set_field,
+ struct ofpbuf *out);
+bool
+set_field_to_openflow10(const struct ofpact_set_field *set_field,
+ struct ofpbuf *out);
+bool
+set_field_to_openflow11(const struct ofpact_set_field *set_field,
+ struct ofpbuf *out);
+
+void
+set_field_parse_with_id(enum mf_field_id id,
+ const char *arg, struct ofpbuf *ofpacts);
+void set_field_parse(const char *s, struct ofpbuf *ofpacts);
+void
+set_field_format(const struct ofpact_set_field *set_field, struct ds *s);
+void
+set_field_execute(const struct ofpact_set_field *set_field,
+ struct flow *flow, struct flow *base_flow,
+ struct ofpbuf *odp_actions);
+
+
+#endif /* SET_FIELD_H */
--
1.7.1.1
More information about the dev
mailing list