[ovs-dev] [PATCH 2/4] v2 Add Openflow 1.2 role request/reply processing, update OF 1.2 tests.

Jarno Rajahalme jarno.rajahalme at nsn.com
Tue Dec 18 11:19:45 UTC 2012


v2 adds struct ofputil_role_request and
 encode/decode functions for role request/reply.

Signed-off-by: Jarno Rajahalme <jarno.rajahalme at nsn.com>
---
 lib/ofp-msgs.h     |   24 ++++++++++-----
 lib/ofp-print.c    |   43 +++++++++++++++++++++------
 lib/ofp-util.c     |   83 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ofp-util.h     |   13 ++++++++
 ofproto/connmgr.c  |   25 ++++++++++++++++
 ofproto/connmgr.h  |    1 +
 ofproto/ofproto.c  |   34 +++++++++++++++------
 tests/ofp-print.at |   30 +++++++++++++++++++
 tests/ofproto.at   |   47 ++++++++++++++++++++++++++---
 9 files changed, 270 insertions(+), 30 deletions(-)

diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index 808f295..2db4fc9 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -198,6 +198,16 @@ enum ofpraw {
     /* OFPT 1.1+ (23): struct ofp11_queue_get_config_reply, struct ofp_packet_queue[]. */
     OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY,
 
+    /* OFPT 1.2+ (24): struct ofp12_role_request. */
+    OFPRAW_OFPT12_ROLE_REQUEST,
+    /* NXT 1.0+ (10): struct nx_role_request. */
+    OFPRAW_NXT_ROLE_REQUEST,
+
+    /* OFPT 1.2+ (25): struct ofp12_role_request. */
+    OFPRAW_OFPT12_ROLE_REPLY,
+    /* NXT 1.0+ (11): struct nx_role_request. */
+    OFPRAW_NXT_ROLE_REPLY,
+
     /* OFPT 1.3+ (26): void. */
     OFPRAW_OFPT13_GET_ASYNC_REQUEST,
     /* OFPT 1.3+ (27): struct ofp13_async_config. */
@@ -339,12 +349,6 @@ enum ofpraw {
  * Nicira extensions that correspond to standard OpenFlow messages are listed
  * alongside the standard versions above. */
 
-    /* NXT 1.0+ (10): struct nx_role_request. */
-    OFPRAW_NXT_ROLE_REQUEST,
-
-    /* NXT 1.0+ (11): struct nx_role_request. */
-    OFPRAW_NXT_ROLE_REPLY,
-
     /* NXT 1.0 (12): struct nx_set_flow_format. */
     OFPRAW_NXT_SET_FLOW_FORMAT,
 
@@ -468,6 +472,12 @@ enum ofptype {
     OFPTYPE_QUEUE_GET_CONFIG_REQUEST, /* OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST. */
     OFPTYPE_QUEUE_GET_CONFIG_REPLY, /* OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY. */
 
+    /* Controller role change request messages. */
+    OFPTYPE_ROLE_REQUEST,         /* OFPRAW_OFPT12_ROLE_REQUEST.
+                                   * OFPRAW_NXT_ROLE_REQUEST. */
+    OFPTYPE_ROLE_REPLY,           /* OFPRAW_OFPT12_ROLE_REPLY.
+                                   * OFPRAW_NXT_ROLE_REPLY. */
+
     /* Asynchronous message configuration. */
     OFPTYPE_GET_ASYNC_REQUEST,    /* OFPRAW_OFPT13_GET_ASYNC_REQUEST. */
     OFPTYPE_GET_ASYNC_REPLY,      /* OFPRAW_OFPT13_GET_ASYNC_REPLY. */
@@ -543,8 +553,6 @@ enum ofptype {
                                       * OFPRAW_OFPST11_PORT_DESC_REPLY. */
 
     /* Nicira extensions. */
-    OFPTYPE_ROLE_REQUEST,         /* OFPRAW_NXT_ROLE_REQUEST. */
-    OFPTYPE_ROLE_REPLY,           /* OFPRAW_NXT_ROLE_REPLY. */
     OFPTYPE_SET_FLOW_FORMAT,      /* OFPRAW_NXT_SET_FLOW_FORMAT. */
     OFPTYPE_FLOW_MOD_TABLE_ID,    /* OFPRAW_NXT_FLOW_MOD_TABLE_ID. */
     OFPTYPE_SET_PACKET_IN_FORMAT, /* OFPRAW_NXT_SET_PACKET_IN_FORMAT. */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index f45ffa4..35d4bf8 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -1511,14 +1511,34 @@ ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
 }
 
 static void
-ofp_print_nxt_role_message(struct ds *string,
-                           const struct nx_role_request *nrr)
+ofp_print_role_message(struct ds *string, enum ofpraw raw,
+                       const struct ofp12_role_request *orr)
 {
-    unsigned int role = ntohl(nrr->role);
+    unsigned int role = ntohl(orr->role);
+    bool have_gen_id = false;
 
     ds_put_cstr(string, " role=");
+
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+        || raw == OFPRAW_OFPT12_ROLE_REPLY ) {
+
+        if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+            /* OFPCR12_ROLE_NOCHANGE is a pseudo-role, valid for role requests.
+             * Response must include the current role instead. */
+            if (role == OFPCR12_ROLE_NOCHANGE) {
+                ds_put_cstr(string, "nochange");
+                return;
+            }
+            /* generation_id is meaningful for master/slave election requests
+             * only */
+            have_gen_id = (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE);
+        }
+        /* Map to Nicira role */
+        role -= 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */
+    }
+
     if (role == NX_ROLE_OTHER) {
-        ds_put_cstr(string, "other");
+        ds_put_cstr(string, "equal"); /* OF 1.2 wording */
     } else if (role == NX_ROLE_MASTER) {
         ds_put_cstr(string, "master");
     } else if (role == NX_ROLE_SLAVE) {
@@ -1526,6 +1546,11 @@ ofp_print_nxt_role_message(struct ds *string,
     } else {
         ds_put_format(string, "%u", role);
     }
+
+    if (have_gen_id) {
+        ds_put_format(string, " generation_id=%"PRIu64,
+                      ntohll(orr->generation_id));
+    }
 }
 
 static void
@@ -1895,6 +1920,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
     case OFPTYPE_BARRIER_REPLY:
         break;
 
+    case OFPTYPE_ROLE_REQUEST:
+    case OFPTYPE_ROLE_REPLY:
+        ofp_print_role_message(string, raw, ofpmsg_body(oh));
+        break;
+
     case OFPTYPE_DESC_STATS_REQUEST:
     case OFPTYPE_PORT_DESC_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
@@ -1955,11 +1985,6 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
         ofp_print_ofpst_port_desc_reply(string, oh);
         break;
 
-    case OFPTYPE_ROLE_REQUEST:
-    case OFPTYPE_ROLE_REPLY:
-        ofp_print_nxt_role_message(string, ofpmsg_body(oh));
-        break;
-
     case OFPTYPE_FLOW_MOD_TABLE_ID:
         ofp_print_nxt_flow_mod_table_id(string, ofpmsg_body(oh));
         break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index f772551..af143ce 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3348,6 +3348,89 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     return b;
 }
 
+/* ofputil_role_request */
+
+/* Decodes the OpenFlow "role request" message in '*oh' into an abstract form
+ * in '*rr'.  Returns 0 if successful, otherwise an OFPERR_* value. */
+enum ofperr
+ofputil_decode_role_request(const struct ofp_header *oh,
+                            struct ofputil_role_request *rr)
+{
+    const struct ofp12_role_request *orr = ofpmsg_body(oh);
+    struct ofpbuf b;
+    enum ofpraw raw;
+    uint32_t role = ntohl(orr->role);
+
+    memset(rr, 0, sizeof *rr);
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+        if (role == OFPCR12_ROLE_NOCHANGE) {
+            rr->request_current_role_only = true;
+            return 0;
+        }
+        if (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE) {
+            rr->generation_id = ntohll(orr->generation_id);
+            rr->have_generation_id = true;
+        }
+        /* Map to enum nx_role */
+        rr->role = role - 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+        rr->role = role;
+    } else {
+        return OFPERR_OFPBRC_BAD_TYPE;
+    }
+
+    return 0;
+}
+
+/* Returns an encoded form of a role reply suitable for the "request" in a
+ * buffer owned by the caller. */
+struct ofpbuf *
+ofputil_encode_role_reply(const struct ofp_header *request,
+                          enum nx_role role)
+{
+    struct ofp12_role_request *reply;
+    struct ofpbuf *buf;
+    size_t reply_size;
+
+    struct ofpbuf b;
+    enum ofpraw raw;
+
+    ofpbuf_use_const(&b, request, ntohs(request->length));
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+        reply_size = sizeof (struct ofp12_role_request);
+        raw = OFPRAW_OFPT12_ROLE_REPLY;
+    }
+    else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+        reply_size = sizeof (struct nx_role_request);
+        raw = OFPRAW_NXT_ROLE_REPLY;
+    } else {
+        NOT_REACHED();
+    }
+
+    buf = ofpraw_alloc_reply(raw, request, reply_size);
+    reply = ofpbuf_put_zeros(buf, reply_size);
+
+    if (raw == OFPRAW_OFPT12_ROLE_REPLY) {
+        /* Map to OpenFlow enum ofp12_controller_role */
+        role += 1; /* NX_ROLE_MASTER -> OFPCR12_ROLE_MASTER etc. */
+        /*
+         * OpenFlow specification does not specify use of generation_id field
+         * on reply messages.  Intuitively, it would seem a good idea to return
+         * the current value.  However, the current value is undefined
+         * initially, and there is no way to insert an undefined value in the
+         * message.  Therefore we leave the generation_id zeroed on reply
+         * messages.
+         */
+    }
+    reply->role = htonl(role);
+
+    return buf;
+}
+
 /* Table stats. */
 
 static void
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index c8bf11e..ba5eaca 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -507,6 +507,19 @@ enum ofperr ofputil_decode_port_mod(const struct ofp_header *,
 struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
                                        enum ofputil_protocol);
 
+/* Abstract ofp_role_request. */
+struct ofputil_role_request {
+    bool request_current_role_only; /* no role change */
+    bool have_generation_id;
+    enum nx_role role;
+    uint64_t generation_id;
+};
+
+enum ofperr ofputil_decode_role_request(const struct ofp_header *,
+                                        struct ofputil_role_request *);
+struct ofpbuf *ofputil_encode_role_reply(const struct ofp_header *,
+                                         enum nx_role current_role);
+
 /* Abstract table stats.
  *
  * For now we use ofp12_table_stats as a superset of the other protocol
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 77b7b39..2dc5249 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -154,6 +154,9 @@ struct connmgr {
     /* OpenFlow connections. */
     struct hmap controllers;   /* Controller "struct ofconn"s. */
     struct list all_conns;     /* Contains "struct ofconn"s. */
+    uint64_t master_election_id; /* monotonically increasing sequence number
+                                  * for master election */
+    bool master_election_id_defined;
 
     /* OpenFlow listeners. */
     struct hmap services;       /* Contains "struct ofservice"s. */
@@ -193,6 +196,8 @@ connmgr_create(struct ofproto *ofproto,
 
     hmap_init(&mgr->controllers);
     list_init(&mgr->all_conns);
+    mgr->master_election_id = 0;
+    mgr->master_election_id_defined = false;
 
     hmap_init(&mgr->services);
     mgr->snoops = NULL;
@@ -817,6 +822,26 @@ ofconn_get_type(const struct ofconn *ofconn)
     return ofconn->type;
 }
 
+/* Sets the master election id.
+ *
+ * Returns true if successful, false if the id is stale
+ */
+bool
+ofconn_set_master_election_id(struct ofconn *ofconn, uint64_t id)
+{
+    if (ofconn->connmgr->master_election_id_defined
+        &&
+        /* Unsigned difference interpreted as a two's complement signed
+         * value */
+        (int64_t)(id - ofconn->connmgr->master_election_id) < 0) {
+        return false;
+    }
+    ofconn->connmgr->master_election_id = id;
+    ofconn->connmgr->master_election_id_defined = true;
+
+    return true;
+}
+
 /* Returns the role configured for 'ofconn'.
  *
  * The default role, if no other role has been set, is NX_ROLE_OTHER. */
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 4122bc1..a2f7d5a 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -96,6 +96,7 @@ void connmgr_get_snoops(const struct connmgr *, struct sset *snoops);
 /* Individual connections to OpenFlow controllers. */
 enum ofconn_type ofconn_get_type(const struct ofconn *);
 
+bool ofconn_set_master_election_id(struct ofconn *, uint64_t);
 enum nx_role ofconn_get_role(const struct ofconn *);
 void ofconn_set_role(struct ofconn *, enum nx_role);
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f95d6ef..638251b 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3618,12 +3618,23 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
 static enum ofperr
 handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    const struct nx_role_request *nrr = ofpmsg_body(oh);
-    struct nx_role_request *reply;
+    struct ofputil_role_request rr;
     struct ofpbuf *buf;
     uint32_t role;
+    enum ofperr error;
+
+    error = ofputil_decode_role_request(oh, &rr);
+    if (error) {
+        return error;
+    }
+
+    if (rr.request_current_role_only) {
+        role = ofconn_get_role(ofconn); /* NX_ROLE_* */
+        goto reply;
+    }
+
+    role = rr.role;
 
-    role = ntohl(nrr->role);
     if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
         && role != NX_ROLE_SLAVE) {
         return OFPERR_OFPRRFC_BAD_ROLE;
@@ -3634,11 +3645,16 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
         return OFPROTO_POSTPONE;
     }
 
+    if (rr.have_generation_id) {
+        if (!ofconn_set_master_election_id(ofconn, rr.generation_id)) {
+            return OFPERR_OFPRRFC_STALE;
+        }
+    }
+
     ofconn_set_role(ofconn, role);
 
-    buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, oh, 0);
-    reply = ofpbuf_put_zeros(buf, sizeof *reply);
-    reply->role = htonl(role);
+reply:
+    buf = ofputil_encode_role_reply(oh, role);
     ofconn_send_reply(ofconn, buf);
 
     return 0;
@@ -4049,14 +4065,14 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_BARRIER_REQUEST:
         return handle_barrier_request(ofconn, oh);
 
+    case OFPTYPE_ROLE_REQUEST:
+        return handle_role_request(ofconn, oh);
+
         /* OpenFlow replies. */
     case OFPTYPE_ECHO_REPLY:
         return 0;
 
         /* Nicira extension requests. */
-    case OFPTYPE_ROLE_REQUEST:
-        return handle_role_request(ofconn, oh);
-
     case OFPTYPE_FLOW_MOD_TABLE_ID:
         return handle_nxt_flow_mod_table_id(ofconn, oh);
 
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 8491dd0..a8adda2 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1515,6 +1515,26 @@ OFPT_SET_ASYNC (OF1.3) (xid=0x0):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_ROLE_REQUEST - OF1.2])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 18 00 18 00 00 00 02 00 00 00 02 00 00 00 00 \
+00 00 00 00 00 00 00 03 \
+"], [0], [dnl
+OFPT_ROLE_REQUEST (OF1.2) (xid=0x2): role=master generation_id=3
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_ROLE_REQUEST - nochange - OF1.2])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 18 00 18 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_ROLE_REQUEST (OF1.2) (xid=0x2): role=nochange
+])
+AT_CLEANUP
+
 AT_SETUP([NXT_ROLE_REQUEST])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1525,6 +1545,16 @@ NXT_ROLE_REQUEST (xid=0x2): role=master
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_ROLE_REPLY - OF1.2])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 19 00 18 00 00 00 02 00 00 00 03 00 00 00 00 \
+00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=slave
+])
+AT_CLEANUP
+
 AT_SETUP([NXT_ROLE_REPLY])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 9c0c6df..8ee701a 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1191,8 +1191,8 @@ check_async 2 OFPR_ACTION OFPPR_ADD OFPPR_DELETE OFPRR_DELETE
 ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700040080
 check_async 3 OFPR_ACTION OFPR_INVALID_TTL OFPPR_ADD OFPPR_DELETE OFPRR_DELETE
 
-# Become slave, which should disable everything except port status.
-ovs-appctl -t ovs-ofctl ofctl/send 0304001400000002000023200000000a00000002
+# Become slave (OF 1.2), which should disable everything except port status.
+ovs-appctl -t ovs-ofctl ofctl/send 031800180000000200000003000000000000000000000001
 check_async 4 OFPPR_ADD OFPPR_DELETE
 
 # Use NXT_SET_ASYNC_CONFIG to enable a patchwork of asynchronous messages.
@@ -1206,14 +1206,53 @@ check_async 6 OFPR_NO_MATCH OFPPR_DELETE OFPRR_DELETE
 # Restore controller ID 0.
 ovs-appctl -t ovs-ofctl ofctl/send 030400180000000300002320000000140000000000000000
 
-# Become master.
-ovs-appctl -t ovs-ofctl ofctl/send 0304001400000002000023200000000a00000001
+# Become master (OF 1.2).
+ovs-appctl -t ovs-ofctl ofctl/send 031800180000000400000002000000000000000000000002
 check_async 7 OFPR_ACTION OFPPR_ADD
 
 ovs-appctl -t ovs-ofctl exit
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+dnl This test checks that the role request/response messaging works
+dnl and that generation_id is handled properly.
+AT_SETUP([ofproto - controller role (OpenFlow 1.2)])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl -O OpenFlow12 monitor br0 --detach --no-chdir --pidfile])
+
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+: > expout
+
+# find out current role
+ovs-appctl -t ovs-ofctl ofctl/send 031800180000000200000000000000000000000000000000
+echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x2): role=nochange"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=equal"
+
+# Become slave (generation_id is initially undefined, so 2^63+2 should not be stale)
+ovs-appctl -t ovs-ofctl ofctl/send 031800180000000300000003000000008000000000000002
+echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x3): role=slave generation_id=9223372036854775810"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x3): role=slave"
+
+# Try to become the master using a stale generation ID
+ovs-appctl -t ovs-ofctl ofctl/send 031800180000000400000002000000000000000000000002
+echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x4): role=master generation_id=2"
+echo >>expout "OFPT_ERROR (OF1.2) (xid=0x4): OFPRRFC_STALE"
+echo >>expout "OFPT_ROLE_REQUEST (OF1.2) (xid=0x4): role=master generation_id=2"
+
+# Become master using a valid generation ID
+ovs-appctl -t ovs-ofctl ofctl/send 031800180000000500000002000000000000000000000001
+echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x5): role=master generation_id=1"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x5): role=master"
+ovs-appctl -t ovs-ofctl ofctl/barrier
+echo >>expout "OFPT_BARRIER_REPLY (OF1.2) (xid=0x3):"
+
+AT_CHECK([cat monitor.log], [0], [expout])
+
+ovs-appctl -t ovs-ofctl exit
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
 dnl specified by OpenFlow 1.0) and OFPP_CONTROLLER (used by some
 dnl controllers despite the spec) as meaning a packet that was generated
-- 
1.7.10.4




More information about the dev mailing list