secchan: Make default normal action do switching.
authorBen Pfaff <blp@nicira.com>
Wed, 18 Mar 2009 00:23:35 +0000 (17:23 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 18 Mar 2009 00:25:52 +0000 (17:25 -0700)
The default normal action is what OFPP_NORMAL does in secchan when vswitchd
is not running.  Before, this was equivalent to OFPP_FLOOD.  With this
change, the behavior changes to acting as a learning switch.

This makes the recent changes to in-band control more efficient when
running in secchan without vswitchd, since we don't really want to flood
all the packets to and from the controller.

secchan/ofproto.c

index e866ba9e52e9e39de8710150d13d79639e9c07a7..9525581e64071b772160ee32a162fae1b19eb5f2 100644 (file)
@@ -45,6 +45,7 @@
 #include "executer.h"
 #include "fail-open.h"
 #include "in-band.h"
+#include "mac-learning.h"
 #include "netdev.h"
 #include "netflow.h"
 #include "odp-util.h"
@@ -227,11 +228,14 @@ struct ofproto {
     /* Hooks for vswitchd. */
     const struct ofhooks *ofhooks;
     void *aux;
+
+    /* Used by default ofhooks. */
+    struct mac_learning *ml;
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
-static const struct ofhooks null_ofhooks;
+static const struct ofhooks default_ofhooks;
 
 static uint64_t pick_datapath_id(struct dpif *, uint64_t fallback_dpid);
 static uint64_t pick_fallback_dpid(void);
@@ -331,8 +335,15 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
     p->n_snoops = 0;
 
     /* Initialize hooks. */
-    p->ofhooks = ofhooks ? ofhooks : &null_ofhooks;
-    p->aux = aux;
+    if (ofhooks) {
+        p->ofhooks = ofhooks;
+        p->aux = aux;
+        p->ml = NULL;
+    } else {
+        p->ofhooks = &default_ofhooks;
+        p->aux = p;
+        p->ml = mac_learning_create();
+    }
 
     /* Register switch status category. */
     p->ss_cat = switch_status_register(p->switch_status, "remote",
@@ -712,6 +723,8 @@ ofproto_destroy(struct ofproto *p)
     }
     free(p->snoops);
 
+    mac_learning_destroy(p->ml);
+
     free(p);
 }
 
@@ -1691,13 +1704,9 @@ xlate_output_action(struct action_xlate_ctx *ctx,
         xlate_table_action(ctx, ctx->flow->in_port);
         break;
     case OFPP_NORMAL:
-        if (ctx->ofproto->ofhooks->normal_cb) {
-            ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->revalidating,
-                                             ctx->out, ctx->tags,
-                                             ctx->ofproto->aux);
-        } else {
-            add_output_group_action(ctx->out, DP_GROUP_FLOOD);
-        }
+        ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->revalidating,
+                                         ctx->out, ctx->tags,
+                                         ctx->ofproto->aux);
         break;
     case OFPP_FLOOD:
         add_output_group_action(ctx->out, DP_GROUP_FLOOD);
@@ -3102,3 +3111,48 @@ pick_fallback_dpid(void)
     ea[2] = 0x20;
     return eth_addr_to_uint64(ea);
 }
+\f
+static void
+default_normal_ofhook_cb(const flow_t *flow, bool revalidating,
+                         struct odp_actions *actions, tag_type *tags,
+                         void *ofproto_)
+{
+    struct ofproto *ofproto = ofproto_;
+    int out_port;
+
+    /* Drop frames for reserved multicast addresses. */
+    if (eth_addr_is_reserved(flow->dl_dst)) {
+        return;
+    }
+
+    /* Learn source MAC (but don't try to learn from revalidation). */
+    if (!revalidating) {
+        tag_type rev_tag = mac_learning_learn(ofproto->ml, flow->dl_src,
+                                              0, flow->in_port);
+        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);
+            ofproto_revalidate(ofproto, rev_tag);
+        }
+    }
+
+    /* Determine output port. */
+    out_port = mac_learning_lookup_tag(ofproto->ml, flow->dl_dst, 0, tags);
+    if (out_port < 0) {
+        add_output_group_action(actions, DP_GROUP_FLOOD);
+    } else if (out_port != flow->in_port) {
+        add_output_action(actions, out_port);
+    } else {
+        /* Drop. */
+    }
+}
+
+static const struct ofhooks default_ofhooks = {
+    NULL,
+    NULL,
+    NULL,
+    default_normal_ofhook_cb,
+};