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
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);
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)
{
sizeof (struct ofp_port_mod),
recv_port_mod,
},
+ [OFPT_ECHO_REQUEST] = {
+ sizeof (struct ofp_header),
+ recv_echo_request,
+ },
};
const struct openflow_packet *pkt;
/* 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
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. */
struct buffer;
struct flow;
struct pollfd;
+struct ofp_header;
/* Client interface. */
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. */
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.
*
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) {
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));
+}
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;
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'
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;
+}
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
sizeof (struct ofp_stats_request),
recv_stats_request,
},
+ [OFPT_ECHO_REQUEST] = {
+ sizeof (struct ofp_header),
+ recv_echo_request,
+ },
};
const struct openflow_packet *pkt;