autopath: Create the autopath action.
authorEthan Jackson <ethan@nicira.com>
Tue, 5 Apr 2011 19:37:52 +0000 (12:37 -0700)
committerEthan Jackson <ethan@nicira.com>
Mon, 11 Apr 2011 22:56:20 +0000 (15:56 -0700)
The newly created autopath action will be the way OpenFlow
interacts with the existing bonding infrastructure.

include/openflow/nicira-ext.h
lib/automake.mk
lib/autopath.c [new file with mode: 0644]
lib/autopath.h [new file with mode: 0644]
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
ofproto/ofproto.c
ofproto/ofproto.h
utilities/ovs-ofctl.8.in
vswitchd/bridge.c

index 663059f..292a987 100644 (file)
@@ -223,7 +223,8 @@ enum nx_action_subtype {
     NXAST_REG_LOAD,             /* struct nx_action_reg_load */
     NXAST_NOTE,                 /* struct nx_action_note */
     NXAST_SET_TUNNEL64,         /* struct nx_action_set_tunnel64 */
-    NXAST_MULTIPATH             /* struct nx_action_multipath */
+    NXAST_MULTIPATH,            /* struct nx_action_multipath */
+    NXAST_AUTOPATH              /* struct nx_action_autopath */
 };
 
 /* Header for Nicira-defined actions. */
@@ -610,6 +611,51 @@ enum nx_mp_algorithm {
 #define NXFW_ALL NXFW_TUN_ID
 #define OVSFW_ALL (OFPFW_ALL | NXFW_ALL)
 \f
+/* Action structure for NXAST_AUTOPATH.
+ *
+ * This action performs the following steps in sequence:
+ *
+ *    1. Hashes the flow using an implementation-defined hash function.
+ *
+ *       The hashed fields' values are drawn from the current state of the
+ *       flow, including all modifications that have been made by actions up to
+ *       this point.
+ *
+ *    2. Selects an OpenFlow 'port'.
+ *
+ *       'port' is selected in an implementation-defined manner, taking into
+ *       account 'id' and the hash value calculated in step 1.
+ *
+ *       Generally a switch will have been configured with a set of ports that
+ *       may be chosen given 'id'.  The switch may take into account any number
+ *       of factors when choosing 'port' from its configured set.  Factors may
+ *       include carrier, load, and the results of configuration protocols such
+ *       as LACP.
+ *
+ *    3. Stores 'port' in dst[ofs:ofs+n_bits].
+ *
+ *       The format and semantics of 'dst' and 'ofs_nbits' are similar to those
+ *       for the NXAST_REG_LOAD action, except that 'dst' must be
+ *       NXM_NX_REG(idx) for 'idx' in the switch's supported range.
+ *
+ * The switch will reject actions in which ofs+n_bits is greater than the width
+ * of 'dst', with error type OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT.
+ */
+struct nx_action_autopath {
+    ovs_be16 type;              /* OFPAT_VENDOR. */
+    ovs_be16 len;               /* Length is 20. */
+    ovs_be32 vendor;            /* NX_VENDOR_ID. */
+    ovs_be16 subtype;           /* NXAST_MULTIPATH. */
+
+    /* Where to store the result. */
+    ovs_be16 ofs_nbits;         /* (ofs << 6) | (n_bits - 1). */
+    ovs_be32 dst;               /* Destination register. */
+
+    ovs_be32 id;                /* Autopath ID. */
+    ovs_be32 pad;
+};
+OFP_ASSERT(sizeof(struct nx_action_autopath) == 24);
+\f
 /* Flexible flow specifications (aka NXM = Nicira Extended Match).
  *
  * OpenFlow 1.0 has "struct ofp_match" for specifying flow matches.  This
index ffebefa..802cc99 100644 (file)
@@ -10,6 +10,8 @@ noinst_LIBRARIES += lib/libopenvswitch.a
 lib_libopenvswitch_a_SOURCES = \
        lib/aes128.c \
        lib/aes128.h \
+       lib/autopath.c \
+       lib/autopath.h \
        lib/backtrace.c \
        lib/backtrace.h \
        lib/bitmap.c \
diff --git a/lib/autopath.c b/lib/autopath.c
new file mode 100644 (file)
index 0000000..889b037
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011 Nicira Networks.
+ *
+ * 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 <config.h>
+
+#include "autopath.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "flow.h"
+#include "nx-match.h"
+#include "ofp-util.h"
+#include "openflow/nicira-ext.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(autopath);
+
+static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+/* Loads 'ofp_port' into the appropriate register in accordance with the
+ * autopath action. */
+void
+autopath_execute(const struct nx_action_autopath *ap, struct flow *flow,
+                 uint16_t ofp_port)
+{
+    uint32_t *reg = &flow->regs[NXM_NX_REG_IDX(ntohl(ap->dst))];
+    int ofs = nxm_decode_ofs(ap->ofs_nbits);
+    int n_bits = nxm_decode_n_bits(ap->ofs_nbits);
+    uint32_t mask = n_bits == 32 ? UINT32_MAX : (UINT32_C(1) << n_bits) - 1;
+    *reg = (*reg & ~(mask << ofs)) | ((ofp_port & mask) << ofs);
+}
+
+void
+autopath_parse(struct nx_action_autopath *ap, const char *s_)
+{
+    char *s;
+    uint32_t reg;
+    int id_int, ofs, n_bits;
+    char *id_str, *dst, *save_ptr;
+
+    s = xstrdup(s_);
+    save_ptr = NULL;
+    id_str = strtok_r(s, ", ", &save_ptr);
+    dst = strtok_r(NULL, ", ", &save_ptr);
+
+    if (!dst) {
+        ovs_fatal(0, "%s: not enough arguments to autopath action", s_);
+    }
+
+    id_int = atoi(id_str);
+    if (id_int < 1 || id_int > UINT32_MAX) {
+        ovs_fatal(0, "%s: autopath id %d is not in valid range "
+                  "1 to %"PRIu32, s_, id_int, UINT32_MAX);
+    }
+
+    nxm_parse_field_bits(dst, &reg, &ofs, &n_bits);
+    if (!NXM_IS_NX_REG(reg) || NXM_NX_REG_IDX(reg) >= FLOW_N_REGS) {
+        ovs_fatal(0, "%s: destination field must be a register", s_);
+    }
+
+    if (n_bits < 16) {
+        ovs_fatal(0, "%s: %d-bit destination field has %u possible values, "
+                  "less than required 65536", s_, n_bits, 1u << n_bits);
+    }
+
+    memset(ap, 0, sizeof *ap);
+    ap->type = htons(OFPAT_VENDOR);
+    ap->len = htons(sizeof *ap);
+    ap->vendor = htonl(NX_VENDOR_ID);
+    ap->subtype = htons(NXAST_AUTOPATH);
+    ap->id = htonl(id_int);
+    ap->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits);
+    ap->dst = htonl(reg);
+
+    free(s);
+}
+
+int
+autopath_check(const struct nx_action_autopath *ap)
+{
+    uint32_t dst = ntohl(ap->dst);
+    int ofs = nxm_decode_ofs(ap->ofs_nbits);
+    int n_bits = nxm_decode_n_bits(ap->ofs_nbits);
+
+    if (!NXM_IS_NX_REG(dst) || NXM_NX_REG_IDX(dst) >= FLOW_N_REGS) {
+        VLOG_WARN_RL(&rl, "unsupported destination field %#"PRIx32, dst);
+    } else if (ofs + n_bits > nxm_field_bits(dst)) {
+        VLOG_WARN_RL(&rl, "destination overflows output field");
+    } else if (n_bits < 16) {
+        VLOG_WARN_RL(&rl, "minimum of 16 bits required in output field");
+    } else {
+        return 0;
+    }
+
+    return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
+}
diff --git a/lib/autopath.h b/lib/autopath.h
new file mode 100644 (file)
index 0000000..ba55f90
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Nicira Networks.
+ *
+ * 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 AUTOPATH_H
+#define AUTOPATH_H 1
+
+#include <stdint.h>
+
+struct flow;
+struct nx_action_autopath;
+
+/* NXAST_AUTOPATH  helper functions.
+ *
+ * See include/openflow/nicira-ext.h for NXAST_AUTOPATH specification. */
+
+void autopath_execute(const struct nx_action_autopath *, struct flow *,
+                      uint16_t ofp_port);
+void autopath_parse(struct nx_action_autopath *, const char *);
+int autopath_check(const struct nx_action_autopath *);
+
+#endif /* autopath.h */
index de7cd9c..4c4811b 100644 (file)
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <stdlib.h>
 
+#include "autopath.h"
 #include "byte-order.h"
 #include "dynamic-string.h"
 #include "netdev.h"
@@ -453,6 +454,10 @@ str_to_action(char *str, struct ofpbuf *b)
             struct nx_action_multipath *nam;
             nam = ofpbuf_put_uninit(b, sizeof *nam);
             multipath_parse(nam, arg);
+        } else if (!strcasecmp(act, "autopath")) {
+            struct nx_action_autopath *naa;
+            naa = ofpbuf_put_uninit(b, sizeof *naa);
+            autopath_parse(naa, arg);
         } else if (!strcasecmp(act, "output")) {
             put_output_action(b, str_to_u32(arg));
         } else if (!strcasecmp(act, "enqueue")) {
index 1cd9462..f5eb9ad 100644 (file)
@@ -219,6 +219,7 @@ nx_action_len(enum nx_action_subtype subtype)
     case NXAST_NOTE: return -1;
     case NXAST_SET_TUNNEL64: return sizeof(struct nx_action_set_tunnel64);
     case NXAST_MULTIPATH: return sizeof(struct nx_action_multipath);
+    case NXAST_AUTOPATH: return sizeof (struct nx_action_autopath);
     default: return -1;
     }
 }
@@ -244,6 +245,7 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
         const struct nx_action_reg_move *move;
         const struct nx_action_reg_load *load;
         const struct nx_action_multipath *nam;
+        const struct nx_action_autopath *naa;
 
         switch ((enum nx_action_subtype) subtype) {
         case NXAST_RESUBMIT:
@@ -295,6 +297,15 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
             multipath_format(nam, string);
             return;
 
+        case NXAST_AUTOPATH:
+            naa = (const struct nx_action_autopath *)nah;
+            ds_put_format(string, "autopath(%u,", ntohl(naa->id));
+            nxm_format_field_bits(string, ntohl(naa->dst),
+                                  nxm_decode_ofs(naa->ofs_nbits),
+                                  nxm_decode_n_bits(naa->ofs_nbits));
+            ds_put_char(string, ')');
+            return;
+
         case NXAST_SNAT__OBSOLETE:
         default:
             break;
index cc448bc..c49b079 100644 (file)
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
+#include "autopath.h"
 #include "byte-order.h"
 #include "classifier.h"
 #include "dynamic-string.h"
@@ -2014,6 +2015,14 @@ check_nicira_action(const union ofp_action *a, unsigned int len,
         }
         return multipath_check((const struct nx_action_multipath *) a);
 
+    case NXAST_AUTOPATH:
+        error = check_nx_action_exact_len(
+            nah, len, sizeof(struct nx_action_autopath));
+        if (error) {
+            return error;
+        }
+        return autopath_check((const struct nx_action_autopath *) a);
+
     case NXAST_SNAT__OBSOLETE:
     default:
         VLOG_WARN_RL(&bad_ofmsg_rl,
index 1865277..0b85e61 100644 (file)
@@ -24,6 +24,7 @@
 #include <netinet/in.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include "autopath.h"
 #include "byte-order.h"
 #include "cfm.h"
 #include "classifier.h"
@@ -2222,8 +2223,11 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
     const struct nx_action_set_tunnel *nast;
     const struct nx_action_set_queue *nasq;
     const struct nx_action_multipath *nam;
+    const struct nx_action_autopath *naa;
     enum nx_action_subtype subtype = ntohs(nah->subtype);
+    const struct ofhooks *ofhooks = ctx->ofproto->ofhooks;
     struct xlate_reg_state state;
+    uint16_t autopath_port;
     ovs_be64 tun_id;
 
     assert(nah->vendor == htonl(NX_VENDOR_ID));
@@ -2285,6 +2289,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         multipath_execute(nam, &ctx->flow);
         break;
 
+    case NXAST_AUTOPATH:
+        naa = (const struct nx_action_autopath *) nah;
+        autopath_port = (ofhooks->autopath_cb
+                         ? ofhooks->autopath_cb(&ctx->flow, ntohl(naa->id),
+                                                &ctx->tags, ctx->ofproto->aux)
+                         : OFPP_NONE);
+        autopath_execute(naa, &ctx->flow, autopath_port);
+        break;
+
     /* If you add a new action here that modifies flow data, don't forget to
      * update the flow key in ctx->flow at the same time. */
 
@@ -4415,5 +4428,6 @@ static const struct ofhooks default_ofhooks = {
     default_normal_ofhook_cb,
     NULL,
     NULL,
+    NULL,
     NULL
 };
index 96f0098..9a56bee 100644 (file)
@@ -161,6 +161,9 @@ struct ofhooks {
                             size_t actions_len,
                             uint64_t n_bytes, void *aux);
     void (*account_checkpoint_cb)(void *aux);
+
+    uint16_t (*autopath_cb)(const struct flow *, uint32_t id,
+                            tag_type *, void *aux);
 };
 void ofproto_revalidate(struct ofproto *, tag_type);
 struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
index 2ce3368..d9742c8 100644 (file)
@@ -642,6 +642,19 @@ Currently, \fIfields\fR must be either \fBeth_src\fR or
 the \fBiter_hash\fR algorithm uses \fIarg\fR.
 .IP
 Refer to \fBnicira\-ext.h\fR for more details.
+.
+.IP "\fBautopath(\fIid\fB, \fIdst\fB[\fIstart\fB..\fIend\fB])\fR"
+Given \fIid\fR, chooses an OpenFlow port and populates it in
+\fIdst\fB[\fIstart\fB..\fIend\fB]\fR, which must be an NXM register as
+described above.
+.IP
+Currently, \fIid\fR should be the OpenFlow port number of an interface on the
+bridge.  If it isn't then \fIdst\fB[\fIstart\fB..\fIend\fB]\fR will be
+populated with the OpenFlow port "none".  If \fIid\fR is a member of a bond,
+the normal bond selection logic will be used to choose the destination port.
+Otherwise, the register will be populated with \fIid\fR itself.
+.IP
+Refer to \fBnicira\-ext.h\fR for more details.
 .RE
 .
 .IP
index 59100cc..7997402 100644 (file)
@@ -2694,11 +2694,37 @@ bridge_account_checkpoint_ofhook_cb(void *br_)
     }
 }
 
+static uint16_t
+bridge_autopath_ofhook_cb(const struct flow *flow, uint32_t ofp_port,
+                          tag_type *tags, void *br_)
+{
+    struct bridge *br = br_;
+    uint16_t odp_port = ofp_port_to_odp_port(ofp_port);
+    struct port *port = port_from_dp_ifidx(br, odp_port);
+    uint16_t ret;
+
+    if (!port) {
+        ret = ODPP_NONE;
+    } else if (list_is_short(&port->ifaces)) {
+        ret = odp_port;
+    } else {
+        struct iface *iface;
+
+        /* Autopath does not support VLAN hashing. */
+        iface = bond_choose_output_slave(port->bond, flow,
+                                         OFP_VLAN_NONE, tags);
+        ret = iface ? iface->dp_ifidx : ODPP_NONE;
+    }
+
+    return odp_port_to_ofp_port(ret);
+}
+
 static struct ofhooks bridge_ofhooks = {
     bridge_normal_ofhook_cb,
     bridge_special_ofhook_cb,
     bridge_account_flow_ofhook_cb,
     bridge_account_checkpoint_ofhook_cb,
+    bridge_autopath_ofhook_cb,
 };
 \f
 /* Port functions. */