Respond to echo requests in OpenFlow implementations.
authorBen Pfaff <blp@nicira.com>
Fri, 27 Jun 2008 17:42:31 +0000 (10:42 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 1 Jul 2008 17:51:50 +0000 (10:51 -0700)
Nothing yet sends such requests.  This is preparation for their
use in following commits.

datapath/datapath.c
datapath/datapath.h
datapath/forward.c
include/openflow.h
include/vconn.h
lib/learning-switch.c
lib/ofp-print.c
lib/vconn.c
switch/datapath.c

index 8403644..55c2c61 100644 (file)
@@ -813,6 +813,22 @@ dp_send_error_msg(struct datapath *dp, const struct sender *sender,
        return send_openflow_skb(skb, sender);
 }
 
+int
+dp_send_echo_reply(struct datapath *dp, const struct sender *sender,
+                  const struct ofp_header *rq)
+{
+       struct sk_buff *skb;
+       struct ofp_header *reply;
+
+       reply = alloc_openflow_skb(dp, ntohs(rq->length), OFPT_ECHO_REPLY,
+                                  sender, &skb);
+       if (!reply)
+               return -ENOMEM;
+
+       memcpy(reply + 1, rq + 1, ntohs(rq->length) - sizeof *rq);
+       return send_openflow_skb(skb, sender);
+}
+
 /* Generic Netlink interface.
  *
  * See netlink(7) for an introduction to netlink.  See
index b822ae4..bb714d3 100644 (file)
@@ -77,6 +77,8 @@ int dp_send_flow_expired(struct datapath *, struct sw_flow *);
 int dp_send_error_msg(struct datapath *, const struct sender *, 
                        uint16_t, uint16_t, const uint8_t *, size_t);
 int dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp);
+int dp_send_echo_reply(struct datapath *, const struct sender *,
+                      const struct ofp_header *);
 
 /* Should hold at least RCU read lock when calling */
 struct datapath *dp_get(int dp_idx);
index fcbc59b..4c43cd9 100644 (file)
@@ -354,6 +354,13 @@ recv_port_mod(struct sw_chain *chain, const struct sender *sender,
        return 0;
 }
 
+static int
+recv_echo_request(struct sw_chain *chain, const struct sender *sender,
+                 const void *msg) 
+{
+       return dp_send_echo_reply(chain->dp, sender, msg);
+}
+
 static int
 add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm)
 {
@@ -484,6 +491,10 @@ fwd_control_input(struct sw_chain *chain, const struct sender *sender,
                        sizeof (struct ofp_port_mod),
                        recv_port_mod,
                },
+               [OFPT_ECHO_REQUEST] = {
+                       sizeof (struct ofp_header),
+                       recv_echo_request,
+               },
        };
 
        const struct openflow_packet *pkt;
index 6303b49..e126dde 100644 (file)
@@ -50,7 +50,7 @@
 /* The most significant bit being set in the version field indicates an
  * experimental OpenFlow version.  
  */
-#define OFP_VERSION   0x83
+#define OFP_VERSION   0x84
 
 #define OFP_MAX_TABLE_NAME_LEN 32
 #define OFP_MAX_PORT_NAME_LEN  16
@@ -94,7 +94,9 @@ enum ofp_type {
     OFPT_PORT_STATUS,         /* 11 Async message */
     OFPT_ERROR_MSG,           /* 12 Async message */
     OFPT_STATS_REQUEST,       /* 13 Controller/switch message */
-    OFPT_STATS_REPLY          /* 14 Controller/switch message */
+    OFPT_STATS_REPLY,         /* 14 Controller/switch message */
+    OFPT_ECHO_REQUEST,        /* 15 Symmetric message */
+    OFPT_ECHO_REPLY           /* 16 Symmetric message */
 };
 
 /* Header on all OpenFlow packets. */
index 72cb879..e4de5ca 100644 (file)
@@ -40,6 +40,7 @@
 struct buffer;
 struct flow;
 struct pollfd;
+struct ofp_header;
 
 /* Client interface. */
 
@@ -81,6 +82,7 @@ struct buffer *make_buffered_packet_out(uint32_t buffer_id,
                                         uint16_t in_port, uint16_t out_port);
 struct buffer *make_unbuffered_packet_out(const struct buffer *packet,
                                           uint16_t in_port, uint16_t out_port);
+struct buffer *make_echo_reply(const struct ofp_header *rq);
 \f
 /* Provider interface. */
 
index 874e2cb..79858f4 100644 (file)
@@ -67,6 +67,8 @@ static void queue_tx(struct lswitch *, struct rconn *, struct buffer *);
 static void send_features_request(struct lswitch *, struct rconn *);
 static void process_packet_in(struct lswitch *, struct rconn *,
                               struct ofp_packet_in *);
+static void process_echo_request(struct lswitch *, struct rconn *,
+                                 struct ofp_header *);
 
 /* Creates and returns a new learning switch.
  *
@@ -124,7 +126,9 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
         return;
     }
 
-    if (oh->type == OFPT_FEATURES_REPLY) {
+    if (oh->type == OFPT_ECHO_REQUEST) {
+        process_echo_request(sw, rconn, msg->data);
+    } else if (oh->type == OFPT_FEATURES_REPLY) {
         struct ofp_switch_features *osf = msg->data;
         sw->datapath_id = osf->datapath_id;
     } else if (sw->datapath_id == 0) {
@@ -242,3 +246,10 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn,
         queue_tx(sw, rconn, b);
     }
 }
+
+static void
+process_echo_request(struct lswitch *sw, struct rconn *rconn,
+                     struct ofp_header *rq)
+{
+    queue_tx(sw, rconn, make_echo_reply(rq));
+}
index d1a8f8d..6ba3694 100644 (file)
@@ -780,6 +780,17 @@ ofp_stats_reply(struct ds *string, const void *oh, size_t len, int verbosity)
                 verbosity, REPLY);
 }
 
+static void
+ofp_echo(struct ds *string, const void *oh, size_t len, int verbosity)
+{
+    const struct ofp_header *hdr = oh;
+
+    ds_put_format(string, " %zu bytes of payload\n", len - sizeof *hdr);
+    if (verbosity > 1) {
+        ds_put_hex_dump(string, hdr, len - sizeof *hdr, 0, true); 
+    }
+}
+
 struct openflow_packet {
     const char *name;
     size_t min_size;
@@ -857,6 +868,16 @@ static const struct openflow_packet packets[] = {
         sizeof (struct ofp_stats_reply),
         ofp_stats_reply,
     },
+    [OFPT_ECHO_REQUEST] = {
+        "echo_request",
+        sizeof (struct ofp_header),
+        ofp_echo,
+    },
+    [OFPT_ECHO_REPLY] = {
+        "echo_reply",
+        sizeof (struct ofp_header),
+        ofp_echo,
+    },
 };
 
 /* Composes and returns a string representing the OpenFlow packet of 'len'
index 9c7d2e2..1fa83fa 100644 (file)
@@ -440,3 +440,14 @@ make_buffered_packet_out(uint32_t buffer_id,
     return out;
 }
 
+/* Creates and returns an OFPT_ECHO_REPLY message matching the
+ * OFPT_ECHO_REQUEST message in 'rq'. */
+struct buffer *
+make_echo_reply(const struct ofp_header *rq)
+{
+    size_t size = ntohs(rq->length);
+    struct buffer *out = buffer_new(size);
+    struct ofp_header *reply = buffer_put(out, rq, size);
+    reply->type = OFPT_ECHO_REPLY;
+    return out;
+}
index e1ba2b9..487677a 100644 (file)
@@ -1494,6 +1494,13 @@ error:
     return err;
 }
 
+static int
+recv_echo_request(struct datapath *dp, const struct sender *sender,
+                  const void *oh)
+{
+    return send_openflow_buffer(dp, make_echo_reply(oh), sender);
+}
+
 /* 'msg', which is 'length' bytes long, was received from the control path.
  * Apply it to 'chain'. */
 int
@@ -1534,6 +1541,10 @@ fwd_control_input(struct datapath *dp, const struct sender *sender,
             sizeof (struct ofp_stats_request),
             recv_stats_request,
         },
+        [OFPT_ECHO_REQUEST] = {
+            sizeof (struct ofp_header),
+            recv_echo_request,
+        },
     };
 
     const struct openflow_packet *pkt;