Fix handling of port flags.
[openvswitch] / secchan / secchan.c
index 190fb28defa34a85319203db83f6e6e09f4f1125..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"
@@ -726,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_)
 {
@@ -843,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. */
@@ -880,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
@@ -1657,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) {
+    if (msg->size < sizeof(struct nicira_header)) {
         return false;
     }
-    if (msg->size < sizeof(struct ofp_stats_request)) {
-        VLOG_WARN_RL(&vrl, "packet too short (%zu bytes) for stats_request",
-                     msg->size);
-        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,
@@ -1689,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));