mirror of
https://github.com/openvswitch/ovs
synced 2025-10-17 14:28:02 +00:00
Older versions of Open vSwitch supported a management protocol based on OpenFlow message framing. The current Open vSwitch instead uses the OVSDB protocol for the same purposes. We don't plan to support this older protocol any longer, so this commit deletes support. This commit also deletes the management_id column from the vswitch's database schema. The management_id was used by the older management protocol to match up OpenFlow switch connections to management connections, but the current implementation instead matches up connections based on the datapath IDs exported by the configuration database. In fact, the OpenFlow connections had no way to actually export the management ID, so this just deletes code that was essentially without function anyhow.
251 lines
7.7 KiB
C
251 lines
7.7 KiB
C
/*
|
|
* Copyright (c) 2008, 2009, 2010 Nicira Networks.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include "status.h"
|
|
#include <arpa/inet.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "dynamic-string.h"
|
|
#include "list.h"
|
|
#include "ofpbuf.h"
|
|
#include "ofproto.h"
|
|
#include "openflow/nicira-ext.h"
|
|
#include "packets.h"
|
|
#include "rconn.h"
|
|
#include "svec.h"
|
|
#include "timeval.h"
|
|
#include "vconn.h"
|
|
|
|
#define THIS_MODULE VLM_status
|
|
#include "vlog.h"
|
|
|
|
struct status_category {
|
|
struct list node;
|
|
char *name;
|
|
void (*cb)(struct status_reply *, void *aux);
|
|
void *aux;
|
|
};
|
|
|
|
struct switch_status {
|
|
time_t booted;
|
|
struct status_category *config_cat;
|
|
struct status_category *switch_cat;
|
|
struct list categories;
|
|
};
|
|
|
|
struct status_reply {
|
|
struct status_category *category;
|
|
struct ds request;
|
|
struct ds output;
|
|
};
|
|
|
|
int
|
|
switch_status_handle_request(struct switch_status *ss, struct rconn *rconn,
|
|
struct nicira_header *request)
|
|
{
|
|
struct status_category *c;
|
|
struct nicira_header *reply;
|
|
struct status_reply sr;
|
|
struct ofpbuf *b;
|
|
int retval;
|
|
|
|
sr.request.string = (void *) (request + 1);
|
|
sr.request.length = ntohs(request->header.length) - sizeof *request;
|
|
ds_init(&sr.output);
|
|
LIST_FOR_EACH (c, struct status_category, node, &ss->categories) {
|
|
if (!memcmp(c->name, sr.request.string,
|
|
MIN(strlen(c->name), sr.request.length))) {
|
|
sr.category = c;
|
|
c->cb(&sr, c->aux);
|
|
}
|
|
}
|
|
reply = make_openflow_xid(sizeof *reply + sr.output.length,
|
|
OFPT_VENDOR, request->header.xid, &b);
|
|
reply->vendor = htonl(NX_VENDOR_ID);
|
|
reply->subtype = htonl(NXT_STATUS_REPLY);
|
|
memcpy(reply + 1, sr.output.string, sr.output.length);
|
|
retval = rconn_send(rconn, b, NULL);
|
|
if (retval && retval != EAGAIN) {
|
|
VLOG_WARN("send failed (%s)", strerror(retval));
|
|
}
|
|
ds_destroy(&sr.output);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rconn_status_cb(struct status_reply *sr, void *rconn_)
|
|
{
|
|
struct rconn *rconn = rconn_;
|
|
time_t now = time_now();
|
|
uint32_t remote_ip = rconn_get_remote_ip(rconn);
|
|
uint32_t local_ip = rconn_get_local_ip(rconn);
|
|
|
|
status_reply_put(sr, "name=%s", rconn_get_name(rconn));
|
|
if (remote_ip) {
|
|
status_reply_put(sr, "remote-ip="IP_FMT, IP_ARGS(&remote_ip));
|
|
status_reply_put(sr, "remote-port=%d",
|
|
ntohs(rconn_get_remote_port(rconn)));
|
|
status_reply_put(sr, "local-ip="IP_FMT, IP_ARGS(&local_ip));
|
|
status_reply_put(sr, "local-port=%d",
|
|
ntohs(rconn_get_local_port(rconn)));
|
|
}
|
|
status_reply_put(sr, "state=%s", rconn_get_state(rconn));
|
|
status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn));
|
|
status_reply_put(sr, "probe-interval=%d", rconn_get_probe_interval(rconn));
|
|
status_reply_put(sr, "is-connected=%s",
|
|
rconn_is_connected(rconn) ? "true" : "false");
|
|
status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn));
|
|
status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn));
|
|
status_reply_put(sr, "attempted-connections=%u",
|
|
rconn_get_attempted_connections(rconn));
|
|
status_reply_put(sr, "successful-connections=%u",
|
|
rconn_get_successful_connections(rconn));
|
|
status_reply_put(sr, "last-connection=%ld",
|
|
(long int) (now - rconn_get_last_connection(rconn)));
|
|
status_reply_put(sr, "last-received=%ld",
|
|
(long int) (now - rconn_get_last_received(rconn)));
|
|
status_reply_put(sr, "time-connected=%lu",
|
|
rconn_get_total_time_connected(rconn));
|
|
status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn));
|
|
}
|
|
|
|
static void
|
|
config_status_cb(struct status_reply *sr, void *ofproto_)
|
|
{
|
|
const struct ofproto *ofproto = ofproto_;
|
|
uint64_t datapath_id;
|
|
struct svec listeners;
|
|
int probe_interval, max_backoff;
|
|
size_t i;
|
|
|
|
datapath_id = ofproto_get_datapath_id(ofproto);
|
|
if (datapath_id) {
|
|
status_reply_put(sr, "datapath-id=%"PRIx64, datapath_id);
|
|
}
|
|
|
|
svec_init(&listeners);
|
|
ofproto_get_listeners(ofproto, &listeners);
|
|
for (i = 0; i < listeners.n; i++) {
|
|
status_reply_put(sr, "management%zu=%s", i, listeners.names[i]);
|
|
}
|
|
svec_destroy(&listeners);
|
|
|
|
probe_interval = ofproto_get_probe_interval(ofproto);
|
|
if (probe_interval) {
|
|
status_reply_put(sr, "probe-interval=%d", probe_interval);
|
|
}
|
|
|
|
max_backoff = ofproto_get_max_backoff(ofproto);
|
|
if (max_backoff) {
|
|
status_reply_put(sr, "max-backoff=%d", max_backoff);
|
|
}
|
|
}
|
|
|
|
static void
|
|
switch_status_cb(struct status_reply *sr, void *ss_)
|
|
{
|
|
struct switch_status *ss = ss_;
|
|
time_t now = time_now();
|
|
|
|
status_reply_put(sr, "now=%ld", (long int) now);
|
|
status_reply_put(sr, "uptime=%ld", (long int) (now - ss->booted));
|
|
status_reply_put(sr, "pid=%ld", (long int) getpid());
|
|
}
|
|
|
|
struct switch_status *
|
|
switch_status_create(const struct ofproto *ofproto)
|
|
{
|
|
struct switch_status *ss = xzalloc(sizeof *ss);
|
|
ss->booted = time_now();
|
|
list_init(&ss->categories);
|
|
ss->config_cat = switch_status_register(ss, "config", config_status_cb,
|
|
(void *) ofproto);
|
|
ss->switch_cat = switch_status_register(ss, "switch", switch_status_cb,
|
|
ss);
|
|
return ss;
|
|
}
|
|
|
|
void
|
|
switch_status_destroy(struct switch_status *ss)
|
|
{
|
|
if (ss) {
|
|
/* Orphan any remaining categories, so that unregistering them later
|
|
* won't write to bad memory. */
|
|
struct status_category *c, *next;
|
|
LIST_FOR_EACH_SAFE (c, next,
|
|
struct status_category, node, &ss->categories) {
|
|
list_init(&c->node);
|
|
}
|
|
switch_status_unregister(ss->config_cat);
|
|
switch_status_unregister(ss->switch_cat);
|
|
free(ss);
|
|
}
|
|
}
|
|
|
|
struct status_category *
|
|
switch_status_register(struct switch_status *ss,
|
|
const char *category,
|
|
status_cb_func *cb, void *aux)
|
|
{
|
|
struct status_category *c = xmalloc(sizeof *c);
|
|
c->cb = cb;
|
|
c->aux = aux;
|
|
c->name = xstrdup(category);
|
|
list_push_back(&ss->categories, &c->node);
|
|
return c;
|
|
}
|
|
|
|
void
|
|
switch_status_unregister(struct status_category *c)
|
|
{
|
|
if (c) {
|
|
if (!list_is_empty(&c->node)) {
|
|
list_remove(&c->node);
|
|
}
|
|
free(c->name);
|
|
free(c);
|
|
}
|
|
}
|
|
|
|
void
|
|
status_reply_put(struct status_reply *sr, const char *content, ...)
|
|
{
|
|
size_t old_length = sr->output.length;
|
|
size_t added;
|
|
va_list args;
|
|
|
|
/* Append the status reply to the output. */
|
|
ds_put_format(&sr->output, "%s.", sr->category->name);
|
|
va_start(args, content);
|
|
ds_put_format_valist(&sr->output, content, args);
|
|
va_end(args);
|
|
if (ds_last(&sr->output) != '\n') {
|
|
ds_put_char(&sr->output, '\n');
|
|
}
|
|
|
|
/* Drop what we just added if it doesn't match the request. */
|
|
added = sr->output.length - old_length;
|
|
if (added < sr->request.length
|
|
|| memcmp(&sr->output.string[old_length],
|
|
sr->request.string, sr->request.length)) {
|
|
ds_truncate(&sr->output, old_length);
|
|
}
|
|
}
|