Restore ovs-vswitchd VLAN, mirror, bonding, QoS features ("xflow" only).
authorBen Pfaff <blp@nicira.com>
Mon, 12 Jul 2010 17:42:56 +0000 (10:42 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 12 Jul 2010 17:42:56 +0000 (10:42 -0700)
The OVS restructuring from "master" to "wdp" unfortunately left behind a
of features that were implemented by ovs-vswitchd (rather than ofproto).
This commit starts to add them back in.  They are still not implemented
the "right way", because unfortunately that will require more time, but
they will work specifically with the wdp-xflow backend.

The netflow and sflow features need more work.

ofproto/ofproto.c
ofproto/ofproto.h
ofproto/wdp-provider.h
ofproto/wdp-xflow.c
ofproto/wdp.c
ofproto/wdp.h
vswitchd/bridge.c

index 4be3478..f7ce9db 100644 (file)
@@ -247,6 +247,7 @@ ofproto_create(const char *datapath, const char *datapath_type,
     }
     wdp_flow_flush(wdp);
     wdp_recv_purge(wdp);
+    wdp_set_ofhooks(wdp, ofhooks, aux);
 
     /* Initialize settings. */
     p = xzalloc(sizeof *p);
@@ -1024,9 +1025,15 @@ ofproto_wait(struct ofproto *p)
 }
 
 void
-ofproto_revalidate(struct ofproto *ofproto OVS_UNUSED, tag_type tag OVS_UNUSED)
+ofproto_revalidate(struct ofproto *ofproto, tag_type tag)
 {
-    //XXX tag_set_add(&ofproto->revalidate_set, tag);
+    wdp_revalidate(ofproto->wdp, tag);
+}
+
+void
+ofproto_revalidate_all(struct ofproto *ofproto)
+{
+    wdp_revalidate_all(ofproto->wdp);
 }
 
 bool
index b1c8308..2925ebc 100644 (file)
@@ -130,7 +130,9 @@ void ofproto_add_flow(struct ofproto *, const flow_t *,
 void ofproto_delete_flow(struct ofproto *, const flow_t *);
 void ofproto_flush_flows(struct ofproto *);
 
-/* Hooks for ovs-vswitchd. */
+/* Hooks for ovs-vswitchd.
+ *
+ * This needs to be redesigned; it only makes sense for wdp-xflow. */
 struct ofhooks {
     void (*port_changed_cb)(enum ofp_port_reason, const struct ofp_phy_port *,
                             void *aux);
@@ -143,7 +145,7 @@ struct ofhooks {
     void (*account_checkpoint_cb)(void *aux);
 };
 void ofproto_revalidate(struct ofproto *, tag_type);
-struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
+void ofproto_revalidate_all(struct ofproto *);
 
 #ifdef  __cplusplus
 }
index 09c9015..6414a80 100644 (file)
@@ -21,6 +21,7 @@
  * datapath. */
 
 #include <assert.h>
+#include "tag.h"
 #include "util.h"
 #include "wdp.h"
 
@@ -426,6 +427,41 @@ struct wdp_class {
     /* Arranges for the poll loop to wake up when 'wdp' has a message queued
      * to be received with the recv member function. */
     void (*recv_wait)(struct wdp *wdp);
+\f
+    /* ovs-vswitchd interface.
+     *
+     * This needs to be redesigned, because it only makes sense for wdp-xflow.
+     * Other implementations cannot practically use these interfaces and should
+     * just set these pointers to NULL.
+     *
+     * The ofhooks are currently the key to implementing the OFPP_NORMAL
+     * feature of ovs-vswitchd.  This design is not adequate for the long
+     * term; it needs to be redone. */
+
+    /* Sets the ofhooks for 'wdp' to 'ofhooks' with the accompanying 'aux'
+     * value.
+     *
+     * This needs to be redesigned, because it only makes sense for wdp-xflow.
+     * Other implementations cannot practically use this interface and should
+     * just set this to NULL. */
+    int (*set_ofhooks)(struct wdp *wdp,
+                       const struct ofhooks *ofhooks, void *aux);
+
+    /* Tell 'wdp' to revalidate all the flows that match 'tag'.
+     *
+     * This needs to be redesigned, because it only makes sense for wdp-xflow.
+     * Other implementations cannot practically use this interface and should
+     * just set this to NULL. */
+    void (*revalidate)(struct wdp *wdp, tag_type tag);
+
+    /* Tell 'wdp' to revalidate every flow.  (This is not the same as calling
+     * 'revalidate' with all-1-bits for 'tag' because it also revalidates flows
+     * that do not have any tag at all.)
+     *
+     * This needs to be redesigned, because it only makes sense for wdp-xflow.
+     * Other implementations cannot practically use this interface and should
+     * just set this to NULL. */
+    void (*revalidate_all)(struct wdp *wdp);
 };
 
 extern const struct wdp_class wdp_linux_class;
index 0328c5f..71f0455 100644 (file)
 
 #include "coverage.h"
 #include "dhcp.h"
+#include "mac-learning.h"
 #include "netdev.h"
 #include "netflow.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
+#include "ofproto.h"
 #include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
 #include "packets.h"
@@ -64,10 +66,23 @@ struct wx {
     struct port_array ports;    /* Index is xflow port nr;
                                  * wdp_port->opp.port_no is OFP port nr. */
     struct shash port_by_name;
-    bool need_revalidate;
     long long int next_expiration;
+
+    /* Rules that might need to be revalidated. */
+    bool need_revalidate;      /* Revalidate all subrules? */
+    bool revalidate_all;       /* Revalidate all subrules and other rules? */
+    struct tag_set revalidate_set; /* Tag set of (sub)rules to revalidate. */
+
+    /* Hooks for ovs-vswitchd. */
+    const struct ofhooks *ofhooks;
+    void *aux;
+
+    /* Used by default ofhooks. */
+    struct mac_learning *ml;
 };
 
+static const struct ofhooks default_ofhooks;
+
 static struct list all_wx = LIST_INITIALIZER(&all_wx);
 
 static int wx_port_init(struct wx *);
@@ -89,7 +104,8 @@ wx_cast(const struct wdp *wdp)
 static int
 wx_xlate_actions(struct wx *, const union ofp_action *, size_t n,
                  const flow_t *flow, const struct ofpbuf *packet,
-                 struct xflow_actions *out, bool *may_set_up_flow);
+                 tag_type *tags, struct xflow_actions *out,
+                 bool *may_set_up_flow);
 \f
 struct wx_rule {
     struct wdp_rule wr;
@@ -98,6 +114,7 @@ struct wx_rule {
     uint64_t byte_count;        /* Number of bytes received. */
     uint64_t accounted_bytes;   /* Number of bytes passed to account_cb. */
     long long int used;         /* Last-used time (0 if never used). */
+    tag_type tags;              /* Tags (set only by hooks). */
 
     /* If 'super' is non-NULL, this rule is a subrule, that is, it is an
      * exact-match rule (having cr.wc.wildcards of 0) generated from the
@@ -397,7 +414,7 @@ wx_rule_execute(struct wx *wx, struct wx_rule *rule,
     {
         struct wx_rule *super = rule->super ? rule->super : rule;
         if (wx_xlate_actions(wx, super->wr.actions, super->wr.n_actions, flow,
-                             packet, &a, NULL)) {
+                             packet, NULL, &a, NULL)) {
             return;
         }
         actions = a.actions;
@@ -481,7 +498,8 @@ wx_rule_make_actions(struct wx *wx, struct wx_rule *rule,
 
     super = rule->super ? rule->super : rule;
     wx_xlate_actions(wx, super->wr.actions, super->wr.n_actions,
-                     &rule->wr.cr.flow, packet, &a, &rule->may_install);
+                     &rule->wr.cr.flow, packet,
+                     &rule->tags, &a, &rule->may_install);
 
     actions_len = a.n_actions * sizeof *a.actions;
     if (rule->n_xflow_actions != a.n_actions
@@ -608,7 +626,7 @@ struct wx_xlate_ctx {
 
     /* Output. */
     struct xflow_actions *out;    /* Datapath actions. */
-    //tag_type *tags;             /* Tags associated with OFPP_NORMAL actions. */
+    tag_type *tags;             /* Tags associated with OFPP_NORMAL actions. */
     bool may_set_up_flow;       /* True ordinarily; false if the actions must
                                  * be reassessed for every packet. */
     uint16_t nf_output_iface;   /* Output interface index for NetFlow. */
@@ -701,8 +719,7 @@ xlate_output_action(struct wx_xlate_ctx *ctx,
         xlate_table_action(ctx, ctx->flow.in_port);
         break;
     case OFPP_NORMAL:
-#if 0
-        if (!ctx->wx->ofhooks->normal_cb(ctx->flow, ctx->packet,
+        if (!ctx->wx->ofhooks->normal_cb(&ctx->flow, ctx->packet,
                                          ctx->out, ctx->tags,
                                          &ctx->nf_output_iface,
                                          ctx->wx->aux)) {
@@ -710,9 +727,7 @@ xlate_output_action(struct wx_xlate_ctx *ctx,
             ctx->may_set_up_flow = false;
         }
         break;
-#else
-        /* fall through to flood for now */
-#endif
+
     case OFPP_FLOOD:
         add_output_group_action(ctx->out, WX_GROUP_FLOOD,
                                 &ctx->nf_output_iface);
@@ -953,9 +968,10 @@ wx_may_set_up(const flow_t *flow, const struct xflow_actions *actions)
 static int
 wx_xlate_actions(struct wx *wx, const union ofp_action *in, size_t n_in,
                  const flow_t *flow, const struct ofpbuf *packet,
-                 struct xflow_actions *out, bool *may_set_up_flow)
+                 tag_type *tags, struct xflow_actions *out,
+                 bool *may_set_up_flow)
 {
-    //tag_type no_tags = 0;
+    tag_type no_tags = 0;
     struct wx_xlate_ctx ctx;
     COVERAGE_INC(wx_ofp2xflow);
     xflow_actions_init(out);
@@ -964,7 +980,7 @@ wx_xlate_actions(struct wx *wx, const union ofp_action *in, size_t n_in,
     ctx.wx = wx;
     ctx.packet = packet;
     ctx.out = out;
-    //ctx.tags = tags ? tags : &no_tags;
+    ctx.tags = tags ? tags : &no_tags;
     ctx.may_set_up_flow = true;
     ctx.nf_output_iface = NF_OUT_DROP;
     do_xlate_actions(in, n_in, &ctx);
@@ -1084,7 +1100,7 @@ struct revalidate_cbdata {
     struct wx *wx;
     bool revalidate_all;        /* Revalidate all exact-match rules? */
     bool revalidate_subrules;   /* Revalidate all exact-match subrules? */
-    //struct tag_set revalidate_set; /* Set of tags to revalidate. */
+    struct tag_set revalidate_set; /* Set of tags to revalidate. */
 };
 
 static bool
@@ -1123,7 +1139,7 @@ revalidate_cb(struct cls_rule *sub_, void *cbdata_)
 
     if (cbdata->revalidate_all
         || (cbdata->revalidate_subrules && sub->super)
-        /*|| (tag_set_intersects(&cbdata->revalidate_set, sub->tags))*/) {
+        || tag_set_intersects(&cbdata->revalidate_set, sub->tags)) {
         revalidate_rule(cbdata->wx, sub);
     }
 }
@@ -1141,13 +1157,13 @@ wx_run_one(struct wx *wx)
         /* XXX account_checkpoint_cb */
     }
 
-    if (wx->need_revalidate /*|| !tag_set_is_empty(&p->revalidate_set)*/) {
+    if (wx->need_revalidate || !tag_set_is_empty(&wx->revalidate_set)) {
         struct revalidate_cbdata cbdata;
         cbdata.wx = wx;
-        cbdata.revalidate_all = false;
+        cbdata.revalidate_all = wx->revalidate_all;
         cbdata.revalidate_subrules = wx->need_revalidate;
-        //cbdata.revalidate_set = wx->revalidate_set;
-        //tag_set_init(&wx->revalidate_set);
+        cbdata.revalidate_set = wx->revalidate_set;
+        tag_set_init(&wx->revalidate_set);
         COVERAGE_INC(wx_revalidate);
         classifier_for_each(&wx->cls, CLS_INC_EXACT, revalidate_cb, &cbdata);
         wx->need_revalidate = false;
@@ -1168,7 +1184,7 @@ wx_run(void)
 static void
 wx_wait_one(struct wx *wx)
 {
-    if (wx->need_revalidate /*|| !tag_set_is_empty(&p->revalidate_set)*/) {
+    if (wx->need_revalidate || !tag_set_is_empty(&wx->revalidate_set)) {
         poll_immediate_wake();
     } else if (wx->next_expiration != LLONG_MAX) {
         poll_timer_wait_until(wx->next_expiration);
@@ -1219,9 +1235,14 @@ wx_open(const struct wdp_class *wdp_class, const char *name, bool create,
         port_array_init(&wx->ports);
         shash_init(&wx->port_by_name);
         wx->next_expiration = time_msec() + 1000;
+        tag_set_init(&wx->revalidate_set);
 
         wx_port_init(wx);
 
+        wx->ofhooks = &default_ofhooks;
+        wx->aux = wx;
+        wx->ml = mac_learning_create();
+
         *wdpp = &wx->wdp;
     }
 
@@ -1238,6 +1259,7 @@ wx_close(struct wdp *wdp)
     classifier_destroy(&wx->cls);
     netdev_monitor_destroy(wx->netdev_monitor);
     list_remove(&wx->list_node);
+    mac_learning_destroy(wx->ml);
     free(wx);
 }
 
@@ -1751,7 +1773,7 @@ wx_execute(struct wdp *wdp, uint16_t in_port,
 
     flow_extract((struct ofpbuf *) packet, 0, in_port, &flow);
     error = wx_xlate_actions(wx, actions, n_actions, &flow, packet,
-                             &xflow_actions, NULL);
+                             NULL, &xflow_actions, NULL);
     if (error) {
         return error;
     }
@@ -2028,6 +2050,37 @@ wx_recv_wait(struct wdp *wdp)
 
     xfif_recv_wait(wx->xfif);
 }
+
+static int
+wx_set_ofhooks(struct wdp *wdp, const struct ofhooks *ofhooks, void *aux)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    if (wx->ofhooks == &default_ofhooks) {
+        mac_learning_destroy(wx->ml);
+        wx->ml = NULL;
+    }
+
+    wx->ofhooks = ofhooks;
+    wx->aux = aux;
+    return 0;
+}
+
+static void
+wx_revalidate(struct wdp *wdp, tag_type tag)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    tag_set_add(&wx->revalidate_set, tag);
+}
+
+static void
+wx_revalidate_all(struct wdp *wdp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    wx->revalidate_all = true;
+}
 \f
 static void wx_port_update(struct wx *, const char *devname,
                            wdp_port_poll_cb_func *cb, void *aux);
@@ -2364,6 +2417,9 @@ wdp_xflow_register(void)
         wx_recv,
         wx_recv_purge,
         wx_recv_wait,
+        wx_set_ofhooks,
+        wx_revalidate,
+        wx_revalidate_all,
     };
 
     static bool inited = false;
@@ -2399,3 +2455,53 @@ wdp_xflow_register(void)
 
     svec_destroy(&types);
 }
+\f
+static bool
+default_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet,
+                         struct xflow_actions *actions, tag_type *tags,
+                         uint16_t *nf_output_iface, void *wx_)
+{
+    struct wx *wx = wx_;
+    int out_port;
+
+    /* Drop frames for reserved multicast addresses. */
+    if (eth_addr_is_reserved(flow->dl_dst)) {
+        return true;
+    }
+
+    /* Learn source MAC (but don't try to learn from revalidation). */
+    if (packet != NULL) {
+        tag_type rev_tag = mac_learning_learn(wx->ml, flow->dl_src,
+                                              0, flow->in_port,
+                                              GRAT_ARP_LOCK_NONE);
+        if (rev_tag) {
+            /* The log messages here could actually be useful in debugging,
+             * so keep the rate limit relatively high. */
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
+            VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16,
+                        ETH_ADDR_ARGS(flow->dl_src), flow->in_port);
+            tag_set_add(&wx->revalidate_set, rev_tag);
+        }
+    }
+
+    /* Determine output port. */
+    out_port = mac_learning_lookup_tag(wx->ml, flow->dl_dst, 0, tags,
+                                       NULL);
+    if (out_port < 0) {
+        add_output_group_action(actions, WX_GROUP_FLOOD, nf_output_iface);
+    } else if (out_port != flow->in_port) {
+        xflow_actions_add(actions, XFLOWAT_OUTPUT)->output.port = out_port;
+        *nf_output_iface = out_port;
+    } else {
+        /* Drop. */
+    }
+
+    return true;
+}
+
+static const struct ofhooks default_ofhooks = {
+    NULL,
+    default_normal_ofhook_cb,
+    NULL,
+    NULL
+};
index d67120a..72519ee 100644 (file)
@@ -977,6 +977,60 @@ wdp_get_netflow_ids(const struct wdp *wdp,
     *engine_id = wdp->netflow_engine_id;
 }
 \f
+/* ovs-vswitchd interface.
+ *
+ * This needs to be redesigned, because it only makes sense for wdp-xflow.  The
+ * ofhooks are currently the key to implementing the OFPP_NORMAL feature of
+ * ovs-vswitchd. */
+
+/* Sets the ofhooks for 'wdp' to 'ofhooks' with the accompanying 'aux' value.
+ * Only the xflow implementation of wdp is expected to implement this function;
+ * other implementations should just set it to NULL.
+ *
+ * The ofhooks are currently the key to implementing the OFPP_NORMAL feature of
+ * ovs-vswitchd.  This design is not adequate for the long term; it needs to be
+ * redone.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+wdp_set_ofhooks(struct wdp *wdp, const struct ofhooks *ofhooks, void *aux)
+{
+    int error;
+    error = (wdp->wdp_class->set_ofhooks
+             ? wdp->wdp_class->set_ofhooks(wdp, ofhooks, aux)
+             : EOPNOTSUPP);
+    log_operation(wdp, "set_ofhooks", error);
+    return error;
+}
+
+/* Tell 'wdp' to revalidate all the flows that match 'tag'.
+ *
+ * This needs to be redesigned, because it only makes sense for wdp-xflow.
+ * Other implementations cannot practically use this interface and should just
+ * set this to NULL. */
+void
+wdp_revalidate(struct wdp *wdp, tag_type tag)
+{
+    if (wdp->wdp_class->revalidate) {
+        wdp->wdp_class->revalidate(wdp, tag);
+    }
+}
+
+/* Tell 'wdp' to revalidate every flow.  (This is not the same as calling
+ * 'revalidate' with all-1-bits for 'tag' because it also revalidates flows
+ * that do not have any tag at all.)
+ *
+ * This needs to be redesigned, because it only makes sense for wdp-xflow.
+ * Other implementations cannot practically use this interface and should just
+ * set this to NULL. */
+void
+wdp_revalidate_all(struct wdp *wdp)
+{
+    if (wdp->wdp_class->revalidate_all) {
+        wdp->wdp_class->revalidate_all(wdp);
+    }
+}
+\f
 /* Returns a copy of 'old'.  The packet's payload, if any, is copied as well,
  * but if it is longer than 'trim' bytes it is truncated to that length. */
 struct wdp_packet *
index 2ba5839..b20079a 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "classifier.h"
 #include "list.h"
+#include "tag.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -29,6 +30,7 @@ enum {
     TABLEID_CLASSIFIER = 1
 };
 
+struct ofhooks;
 struct ofpbuf;
 struct svec;
 struct wdp;
@@ -84,9 +86,6 @@ void wdp_enumerate_types(struct svec *types);
 int wdp_enumerate_names(const char *type, struct svec *names);
 void wdp_parse_name(const char *datapath_name, char **name, char **type);
 
-void wdp_run_expiration(struct wdp *);
-void wdp_run_revalidation(struct wdp *, bool revalidate_all);
-
 int wdp_open(const char *name, const char *type, struct wdp **);
 int wdp_create(const char *name, const char *type, struct wdp **);
 int wdp_create_and_open(const char *name, const char *type, struct wdp **);
@@ -196,6 +195,16 @@ int wdp_execute(struct wdp *, uint16_t in_port,
                   const union ofp_action[], size_t n_actions,
                   const struct ofpbuf *);
 
+/* ovs-vswitchd interface.
+ *
+ * This needs to be redesigned, because it only makes sense for wdp-xflow.  The
+ * ofhooks are currently the key to implementing the OFPP_NORMAL feature of
+ * ovs-vswitchd. */
+
+int wdp_set_ofhooks(struct wdp *, const struct ofhooks *, void *aux);
+void wdp_revalidate(struct wdp *, tag_type);
+void wdp_revalidate_all(struct wdp *);
+
 /* Receiving packets that miss the flow table. */
 enum wdp_channel {
     WDP_CHAN_MISS,              /* Packet missed in flow table. */
index 4d27049..0abb416 100644 (file)
@@ -1193,7 +1193,7 @@ static void
 bridge_flush(struct bridge *br)
 {
     COVERAGE_INC(bridge_flush);
-    br->flush = true;
+    ofproto_revalidate_all(br->ofproto);
     mac_learning_flush(br->ml);
 }
 
@@ -1284,8 +1284,6 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
     shash_init(&br->port_by_name);
     shash_init(&br->iface_by_name);
 
-    br->flush = false;
-
     list_push_back(&all_bridges, &br->node);
 
     VLOG_INFO("created bridge %s on %s", br->name, xfif_name(br->xfif));
@@ -1381,20 +1379,9 @@ bridge_unixctl_reconnect(struct unixctl_conn *conn,
 static int
 bridge_run_one(struct bridge *br)
 {
-    int error;
-
-    error = ofproto_run1(br->ofproto);
-    if (error) {
-        return error;
-    }
-
-    //XXX mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
+    ofproto_revalidate(br->ofproto, mac_learning_run(br->ml));
     bond_run(br);
-
-    error = ofproto_run2(br->ofproto, br->flush);
-    br->flush = false;
-
-    return error;
+    return ofproto_run(br->ofproto);
 }
 
 static size_t