[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