Fix handling of port flags.
[openvswitch] / secchan / secchan.c
index 48f1bb7c992e8c36dd4a52266b336e21f63b9834..cd6b567d82b905da6fa33ff5db96f865d9b20cc0 100644 (file)
@@ -58,6 +58,7 @@
 #include "list.h"
 #include "mac-learning.h"
 #include "netdev.h"
+#include "nicira-ext.h"
 #include "openflow.h"
 #include "packets.h"
 #include "poll-loop.h"
@@ -109,9 +110,6 @@ struct settings {
     regex_t accept_controller_regex;  /* Controller vconns to accept. */
     const char *accept_controller_re; /* String version of regex. */
     bool update_resolv_conf;          /* Update /etc/resolv.conf? */
-
-    /* Spanning tree protocol. */
-    bool stp;                   /* Enable spanning tree protocol? */
 };
 
 struct half {
@@ -231,6 +229,7 @@ main(int argc, char *argv[])
     struct relay *controller_relay;
     struct discovery *discovery;
     struct switch_status *switch_status;
+    struct port_watcher *pw;
     int i;
     int retval;
 
@@ -288,11 +287,8 @@ main(int argc, char *argv[])
     list_push_back(&relays, &controller_relay->node);
 
     /* Set up hooks. */
-    if (s.stp) {
-        struct port_watcher *pw;
-        hooks[n_hooks++] = port_watcher_create(local_rconn, remote_rconn, &pw);
-        hooks[n_hooks++] = stp_hook_create(&s, pw, local_rconn, remote_rconn);
-    }
+    hooks[n_hooks++] = port_watcher_create(local_rconn, remote_rconn, &pw);
+    hooks[n_hooks++] = stp_hook_create(&s, pw, local_rconn, remote_rconn);
     if (s.in_band) {
         hooks[n_hooks++] = in_band_hook_create(&s, switch_status,
                                                remote_rconn);
@@ -731,6 +727,31 @@ port_watcher_local_packet_cb(struct relay *r, void *pw_)
     return false;
 }
 
+static bool
+port_watcher_remote_packet_cb(struct relay *r, void *pw_)
+{
+    struct port_watcher *pw = pw_;
+    struct buffer *msg = r->halves[HALF_REMOTE].rxbuf;
+    struct ofp_header *oh = msg->data;
+
+    if (oh->type == OFPT_PORT_MOD
+        && msg->size >= sizeof(struct ofp_port_mod)) {
+        struct ofp_port_mod *opm = msg->data;
+        uint16_t port_no = ntohs(opm->desc.port_no);
+        int idx = port_no_to_pw_idx(port_no);
+        if (idx >= 0) {
+            struct ofp_phy_port *pw_opp = &pw->ports[idx];
+            if (pw_opp->port_no != htons(OFPP_NONE)) {
+                struct ofp_phy_port old = *pw_opp;
+                pw_opp->flags = ((pw_opp->flags & ~opm->mask)
+                                 | (opm->desc.flags & opm->mask));
+                call_pw_callbacks(pw, port_no, &old, pw_opp);
+            }
+        }
+    }
+    return false;
+}
+
 static void
 port_watcher_periodic_cb(void *pw_)
 {
@@ -848,7 +869,7 @@ port_watcher_set_flags(struct port_watcher *pw,
     old = *p;
 
     /* Update our idea of the flags. */
-    p->flags = ntohl(flags);
+    p->flags = htonl((ntohl(p->flags) & ~mask) | (flags & mask));
     call_pw_callbacks(pw, port_no, &old, p);
 
     /* Change the flags in the datapath. */
@@ -885,7 +906,8 @@ port_watcher_create(struct rconn *local_rconn, struct rconn *remote_rconn,
         pw->ports[i].port_no = htons(OFPP_NONE);
     }
     port_watcher_register_callback(pw, log_port_status, NULL);
-    return make_hook(port_watcher_local_packet_cb, NULL,
+    return make_hook(port_watcher_local_packet_cb,
+                     port_watcher_remote_packet_cb,
                      port_watcher_periodic_cb, NULL, pw);
 }
 \f
@@ -1424,9 +1446,7 @@ fail_open_hook_create(const struct settings *s, struct switch_status *ss,
     fail_open->remote_rconn = remote_rconn;
     fail_open->lswitch = NULL;
     fail_open->boot_deadline = time_now() + s->probe_interval * 3;
-    if (s->stp) {
-        fail_open->boot_deadline += STP_EXTRA_BOOT_TIME;
-    }
+    fail_open->boot_deadline += STP_EXTRA_BOOT_TIME;
     switch_status_register_category(ss, "fail-open",
                                     fail_open_status_cb, fail_open);
     return make_hook(fail_open_local_packet_cb, NULL,
@@ -1664,30 +1684,24 @@ switch_status_remote_packet_cb(struct relay *r, void *ss_)
     struct rconn *rc = r->halves[HALF_REMOTE].rconn;
     struct buffer *msg = r->halves[HALF_REMOTE].rxbuf;
     struct switch_status_category *c;
-    struct ofp_stats_request *osr;
-    struct ofp_stats_reply *reply;
+    struct nicira_header *request;
+    struct nicira_header *reply;
     struct status_reply sr;
-    struct ofp_header *oh;
     struct buffer *b;
     int retval;
 
-    oh = msg->data;
-    if (oh->type != OFPT_STATS_REQUEST) {
-        return false;
-    }
-    if (msg->size < sizeof(struct ofp_stats_request)) {
-        VLOG_WARN_RL(&vrl, "packet too short (%zu bytes) for stats_request",
-                     msg->size);
+    if (msg->size < sizeof(struct nicira_header)) {
         return false;
     }
-
-    osr = msg->data;
-    if (osr->type != htons(OFPST_SWITCH)) {
+    request = msg->data;
+    if (request->header.type != OFPT_VENDOR
+        || request->vendor_id != htonl(NX_VENDOR_ID)
+        || request->subtype != htonl(NXT_STATUS_REQUEST)) {
         return false;
     }
 
-    sr.request.string = (void *) (osr + 1);
-    sr.request.length = msg->size - sizeof *osr;
+    sr.request.string = (void *) (request + 1);
+    sr.request.length = msg->size - sizeof *request;
     ds_init(&sr.output);
     for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) {
         if (!memcmp(c->name, sr.request.string,
@@ -1696,12 +1710,11 @@ switch_status_remote_packet_cb(struct relay *r, void *ss_)
             c->cb(&sr, c->aux);
         }
     }
-    reply = make_openflow_xid((offsetof(struct ofp_stats_reply, body)
-                               + sr.output.length),
-                              OFPT_STATS_REPLY, osr->header.xid, &b);
-    reply->type = htons(OFPST_SWITCH);
-    reply->flags = 0;
-    memcpy(reply->body, sr.output.string, sr.output.length);
+    reply = make_openflow_xid(sizeof *reply + sr.output.length,
+                              OFPT_VENDOR, request->header.xid, &b);
+    reply->vendor_id = htonl(NX_VENDOR_ID);
+    reply->subtype = htonl(NXT_STATUS_REPLY);
+    memcpy(reply + 1, sr.output.string, sr.output.length);
     retval = rconn_send(rc, b, NULL);
     if (retval && retval != EAGAIN) {
         VLOG_WARN("send failed (%s)", strerror(retval));