From 258f32a084f9ec065996c2309f195d199bdcb622 Mon Sep 17 00:00:00 2001
From: Ben Pfaff <blp@nicira.com>
Date: Fri, 27 Jun 2008 10:42:31 -0700
Subject: [PATCH] Respond to echo requests in OpenFlow implementations.

Nothing yet sends such requests.  This is preparation for their
use in following commits.
---
 datapath/datapath.c   | 16 ++++++++++++++++
 datapath/datapath.h   |  2 ++
 datapath/forward.c    | 11 +++++++++++
 include/openflow.h    |  6 ++++--
 include/vconn.h       |  2 ++
 lib/learning-switch.c | 13 ++++++++++++-
 lib/ofp-print.c       | 21 +++++++++++++++++++++
 lib/vconn.c           | 11 +++++++++++
 switch/datapath.c     | 11 +++++++++++
 9 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 840364480..55c2c6122 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -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
diff --git a/datapath/datapath.h b/datapath/datapath.h
index b822ae4fa..bb714d357 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -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);
diff --git a/datapath/forward.c b/datapath/forward.c
index fcbc59b31..4c43cd910 100644
--- a/datapath/forward.c
+++ b/datapath/forward.c
@@ -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;
diff --git a/include/openflow.h b/include/openflow.h
index 6303b4900..e126dde98 100644
--- a/include/openflow.h
+++ b/include/openflow.h
@@ -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. */
diff --git a/include/vconn.h b/include/vconn.h
index 72cb8791b..e4de5caa1 100644
--- a/include/vconn.h
+++ b/include/vconn.h
@@ -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);
 
 /* Provider interface. */
 
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 874e2cbe4..79858f4f6 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -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));
+}
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index d1a8f8d64..6ba3694eb 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -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'
diff --git a/lib/vconn.c b/lib/vconn.c
index 9c7d2e27f..1fa83faea 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -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;
+}
diff --git a/switch/datapath.c b/switch/datapath.c
index e1ba2b92a..487677a6c 100644
--- a/switch/datapath.c
+++ b/switch/datapath.c
@@ -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;
-- 
2.47.0