From: Ben Pfaff Date: Fri, 27 Jun 2008 17:42:31 +0000 (-0700) Subject: Respond to echo requests in OpenFlow implementations. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=258f32a084f9ec065996c2309f195d199bdcb622;p=openvswitch Respond to echo requests in OpenFlow implementations. Nothing yet sends such requests. This is preparation for their use in following commits. --- diff --git a/datapath/datapath.c b/datapath/datapath.c index 84036448..55c2c612 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 b822ae4f..bb714d35 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 fcbc59b3..4c43cd91 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 6303b490..e126dde9 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 72cb8791..e4de5caa 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 874e2cbe..79858f4f 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 d1a8f8d6..6ba3694e 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 9c7d2e27..1fa83fae 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 e1ba2b92..487677a6 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;