connmgr: Do not persist OpenFlow settings from one session to another.
[cascardo/ovs.git] / ofproto / connmgr.c
index 28d9488..db848fb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,13 +43,25 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
 /* An OpenFlow connection. */
 struct ofconn {
-    struct connmgr *connmgr;    /* Connection's manager. */
+/* Configuration that persists from one connection to the next. */
+
     struct list node;           /* In struct connmgr's "all_conns" list. */
+    struct hmap_node hmap_node; /* In struct connmgr's "controllers" map. */
+
+    struct connmgr *connmgr;    /* Connection's manager. */
     struct rconn *rconn;        /* OpenFlow connection. */
     enum ofconn_type type;      /* Type. */
+    enum ofproto_band band;     /* In-band or out-of-band? */
+
+/* State that should be cleared from one connection to the next. */
+
+    /* OpenFlow state. */
+    enum nx_role role;           /* Role. */
     enum nx_flow_format flow_format; /* Currently selected flow format. */
     enum nx_packet_in_format packet_in_format; /* OFPT_PACKET_IN format. */
     bool flow_mod_table_id;     /* NXT_FLOW_MOD_TABLE_ID enabled? */
+    bool invalid_ttl_to_controller; /* Send packets with invalid TTL
+                                       to the controller. */
 
     /* Asynchronous flow table operation support. */
     struct list opgroups;       /* Contains pending "ofopgroups", if any. */
@@ -68,16 +80,12 @@ struct ofconn {
      * requests.  */
 #define OFCONN_REPLY_MAX 100
     struct rconn_packet_counter *reply_counter;
-
-    /* type == OFCONN_PRIMARY only. */
-    enum nx_role role;           /* Role. */
-    struct hmap_node hmap_node;  /* In struct connmgr's "controllers" map. */
-    enum ofproto_band band;      /* In-band or out-of-band? */
 };
 
 static struct ofconn *ofconn_create(struct connmgr *, struct rconn *,
                                     enum ofconn_type);
 static void ofconn_destroy(struct ofconn *);
+static void ofconn_flush(struct ofconn *);
 
 static void ofconn_reconfigure(struct ofconn *,
                                const struct ofproto_controller *);
@@ -552,7 +560,6 @@ add_controller(struct connmgr *mgr, const char *target)
 
     ofconn = ofconn_create(mgr, rconn_create(5, 8), OFCONN_PRIMARY);
     ofconn->pktbuf = pktbuf_create();
-    ofconn->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
     rconn_connect(ofconn->rconn, target, name);
     hmap_insert(&mgr->controllers, &ofconn->hmap_node, hash_string(target, 0));
 
@@ -754,6 +761,18 @@ ofconn_set_role(struct ofconn *ofconn, enum nx_role role)
     ofconn->role = role;
 }
 
+void
+ofconn_set_invalid_ttl_to_controller(struct ofconn *ofconn, bool val)
+{
+    ofconn->invalid_ttl_to_controller = val;
+}
+
+bool
+ofconn_get_invalid_ttl_to_controller(struct ofconn *ofconn)
+{
+    return ofconn->invalid_ttl_to_controller;
+}
+
 /* Returns the currently configured flow format for 'ofconn', one of NXFF_*.
  *
  * The default, if no other format has been set, is NXFF_OPENFLOW10. */
@@ -917,37 +936,66 @@ ofconn_get_target(const struct ofconn *ofconn)
 static struct ofconn *
 ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type)
 {
-    struct ofconn *ofconn = xzalloc(sizeof *ofconn);
+    struct ofconn *ofconn;
+
+    ofconn = xzalloc(sizeof *ofconn);
     ofconn->connmgr = mgr;
     list_push_back(&mgr->all_conns, &ofconn->node);
     ofconn->rconn = rconn;
     ofconn->type = type;
-    ofconn->flow_format = NXFF_OPENFLOW10;
-    ofconn->packet_in_format = NXPIF_OPENFLOW10;
-    ofconn->flow_mod_table_id = false;
+
     list_init(&ofconn->opgroups);
-    ofconn->role = NX_ROLE_OTHER;
-    ofconn->packet_in_counter = rconn_packet_counter_create ();
-    ofconn->pktbuf = NULL;
-    ofconn->miss_send_len = 0;
-    ofconn->reply_counter = rconn_packet_counter_create ();
+
+    ofconn_flush(ofconn);
+
     return ofconn;
 }
 
-/* Disassociates 'ofconn' from all of the ofopgroups that it initiated that
- * have not yet completed.  (Those ofopgroups will still run to completion in
- * the usual way, but any errors that they run into will not be reported on any
- * OpenFlow channel.)
- *
- * Also discards any blocked operation on 'ofconn'. */
+/* Clears all of the state in 'ofconn' that should not persist from one
+ * connection to the next. */
 static void
 ofconn_flush(struct ofconn *ofconn)
 {
+    int i;
+
+    ofconn->role = NX_ROLE_OTHER;
+    ofconn->flow_format = NXFF_OPENFLOW10;
+    ofconn->packet_in_format = NXPIF_OPENFLOW10;
+    ofconn->flow_mod_table_id = false;
+
+    /* Disassociate 'ofconn' from all of the ofopgroups that it initiated that
+     * have not yet completed.  (Those ofopgroups will still run to completion
+     * in the usual way, but any errors that they run into will not be reported
+     * on any OpenFlow channel.)
+     *
+     * Also discard any blocked operation on 'ofconn'. */
     while (!list_is_empty(&ofconn->opgroups)) {
         list_init(list_pop_front(&ofconn->opgroups));
     }
     ofpbuf_delete(ofconn->blocked);
     ofconn->blocked = NULL;
+
+    rconn_packet_counter_destroy(ofconn->packet_in_counter);
+    ofconn->packet_in_counter = rconn_packet_counter_create();
+    for (i = 0; i < N_SCHEDULERS; i++) {
+        if (ofconn->schedulers[i]) {
+            int rate, burst;
+
+            pinsched_get_limits(ofconn->schedulers[i], &rate, &burst);
+            pinsched_destroy(ofconn->schedulers[i]);
+            ofconn->schedulers[i] = pinsched_create(rate, burst);
+        }
+    }
+    if (ofconn->pktbuf) {
+        pktbuf_destroy(ofconn->pktbuf);
+        ofconn->pktbuf = pktbuf_create();
+    }
+    ofconn->miss_send_len = (ofconn->type == OFCONN_PRIMARY
+                             ? OFP_DEFAULT_MISS_SEND_LEN
+                             : 0);
+
+    rconn_packet_counter_destroy(ofconn->reply_counter);
+    ofconn->reply_counter = rconn_packet_counter_create();
 }
 
 static void
@@ -1054,11 +1102,9 @@ ofconn_wait(struct ofconn *ofconn, bool handling_openflow)
 
 /* Returns true if 'ofconn' should receive asynchronous messages. */
 static bool
-ofconn_receives_async_msgs(const struct ofconn *ofconn)
+ofconn_receives_async_msgs__(const struct ofconn *ofconn)
 {
-    if (!rconn_is_connected(ofconn->rconn)) {
-        return false;
-    } else if (ofconn->type == OFCONN_PRIMARY) {
+    if (ofconn->type == OFCONN_PRIMARY) {
         /* Primary controllers always get asynchronous messages unless they
          * have configured themselves as "slaves".  */
         return ofconn->role != NX_ROLE_SLAVE;
@@ -1069,6 +1115,29 @@ ofconn_receives_async_msgs(const struct ofconn *ofconn)
     }
 }
 
+static bool
+ofconn_receives_async_msgs(const struct ofconn *ofconn)
+{
+    if (!rconn_is_connected(ofconn->rconn)) {
+        return false;
+    } else {
+        return ofconn_receives_async_msgs__(ofconn);
+    }
+}
+
+static bool
+ofconn_interested_in_packet(const struct ofconn *ofconn,
+                            const struct ofputil_packet_in *pin)
+{
+    if (!rconn_is_connected(ofconn->rconn)) {
+        return false;
+    } else if (pin->reason == OFPR_INVALID_TTL) {
+        return ofconn->invalid_ttl_to_controller;
+    } else {
+        return ofconn_receives_async_msgs__(ofconn);
+    }
+}
+
 /* Returns a human-readable name for an OpenFlow connection between 'mgr' and
  * 'target', suitable for use in log messages for identifying the connection.
  *
@@ -1178,7 +1247,7 @@ connmgr_send_packet_in(struct connmgr *mgr,
     struct ofconn *ofconn;
 
     LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
-        if (ofconn_receives_async_msgs(ofconn)) {
+        if (ofconn_interested_in_packet(ofconn, pin)) {
             schedule_packet_in(ofconn, *pin, flow);
         }
     }