1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
4 * We are making the OpenFlow specification and associated documentation
5 * (Software) available for public use and benefit with the expectation
6 * that others will use, modify and enhance the Software and contribute
7 * those enhancements back to the community. However, since we would
8 * like to make the Software available for broadest use, with as few
9 * restrictions as possible permission is hereby granted, free of
10 * charge, to any person obtaining a copy of this Software to deal in
11 * the Software under the copyrights without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 * The name and trademarks of copyright holder(s) may NOT be used in
30 * advertising or publicity pertaining to the Software or any
31 * derivatives without specific, written prior permission.
36 #include <arpa/inet.h>
40 #include "dynamic-string.h"
41 #include "openflow/nicira-ext.h"
43 #include "openflow/openflow.h"
48 #define THIS_MODULE VLM_status
51 struct switch_status_category {
53 void (*cb)(struct status_reply *, void *aux);
57 struct switch_status {
58 const struct settings *s;
60 struct switch_status_category categories[8];
65 struct switch_status_category *category;
71 switch_status_remote_packet_cb(struct relay *r, void *ss_)
73 struct switch_status *ss = ss_;
74 struct rconn *rc = r->halves[HALF_REMOTE].rconn;
75 struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf;
76 struct switch_status_category *c;
77 struct nicira_header *request;
78 struct nicira_header *reply;
79 struct status_reply sr;
83 if (msg->size < sizeof(struct nicira_header)) {
87 if (request->header.type != OFPT_VENDOR
88 || request->vendor != htonl(NX_VENDOR_ID)
89 || request->subtype != htonl(NXT_STATUS_REQUEST)) {
93 sr.request.string = (void *) (request + 1);
94 sr.request.length = msg->size - sizeof *request;
96 for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) {
97 if (!memcmp(c->name, sr.request.string,
98 MIN(strlen(c->name), sr.request.length))) {
103 reply = make_openflow_xid(sizeof *reply + sr.output.length,
104 OFPT_VENDOR, request->header.xid, &b);
105 reply->vendor = htonl(NX_VENDOR_ID);
106 reply->subtype = htonl(NXT_STATUS_REPLY);
107 memcpy(reply + 1, sr.output.string, sr.output.length);
108 retval = rconn_send(rc, b, NULL);
109 if (retval && retval != EAGAIN) {
110 VLOG_WARN("send failed (%s)", strerror(retval));
112 ds_destroy(&sr.output);
117 rconn_status_cb(struct status_reply *sr, void *rconn_)
119 struct rconn *rconn = rconn_;
120 time_t now = time_now();
122 status_reply_put(sr, "name=%s", rconn_get_name(rconn));
123 status_reply_put(sr, "state=%s", rconn_get_state(rconn));
124 status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn));
125 status_reply_put(sr, "is-connected=%s",
126 rconn_is_connected(rconn) ? "true" : "false");
127 status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn));
128 status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn));
129 status_reply_put(sr, "attempted-connections=%u",
130 rconn_get_attempted_connections(rconn));
131 status_reply_put(sr, "successful-connections=%u",
132 rconn_get_successful_connections(rconn));
133 status_reply_put(sr, "last-connection=%ld",
134 (long int) (now - rconn_get_last_connection(rconn)));
135 status_reply_put(sr, "time-connected=%lu",
136 rconn_get_total_time_connected(rconn));
137 status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn));
141 config_status_cb(struct status_reply *sr, void *s_)
143 const struct settings *s = s_;
146 for (i = 0; i < s->n_listeners; i++) {
147 status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]);
149 if (s->probe_interval) {
150 status_reply_put(sr, "probe-interval=%d", s->probe_interval);
152 if (s->max_backoff) {
153 status_reply_put(sr, "max-backoff=%d", s->max_backoff);
158 switch_status_cb(struct status_reply *sr, void *ss_)
160 struct switch_status *ss = ss_;
161 time_t now = time_now();
163 status_reply_put(sr, "now=%ld", (long int) now);
164 status_reply_put(sr, "uptime=%ld", (long int) (now - ss->booted));
165 status_reply_put(sr, "pid=%ld", (long int) getpid());
168 static struct hook_class switch_status_hook_class = {
169 NULL, /* local_packet_cb */
170 switch_status_remote_packet_cb, /* remote_packet_cb */
171 NULL, /* periodic_cb */
173 NULL, /* closing_cb */
177 switch_status_start(struct secchan *secchan, const struct settings *s,
178 struct switch_status **ssp)
180 struct switch_status *ss = xcalloc(1, sizeof *ss);
182 ss->booted = time_now();
183 switch_status_register_category(ss, "config",
184 config_status_cb, (void *) s);
185 switch_status_register_category(ss, "switch", switch_status_cb, ss);
187 add_hook(secchan, &switch_status_hook_class, ss);
191 switch_status_register_category(struct switch_status *ss,
192 const char *category,
193 void (*cb)(struct status_reply *,
197 struct switch_status_category *c;
198 assert(ss->n_categories < ARRAY_SIZE(ss->categories));
199 c = &ss->categories[ss->n_categories++];
202 c->name = xstrdup(category);
206 status_reply_put(struct status_reply *sr, const char *content, ...)
208 size_t old_length = sr->output.length;
212 /* Append the status reply to the output. */
213 ds_put_format(&sr->output, "%s.", sr->category->name);
214 va_start(args, content);
215 ds_put_format_valist(&sr->output, content, args);
217 if (ds_last(&sr->output) != '\n') {
218 ds_put_char(&sr->output, '\n');
221 /* Drop what we just added if it doesn't match the request. */
222 added = sr->output.length - old_length;
223 if (added < sr->request.length
224 || memcmp(&sr->output.string[old_length],
225 sr->request.string, sr->request.length)) {
226 ds_truncate(&sr->output, old_length);