Needed for partner builds.
#include "util.h"
/* Logging importance levels. */
+#define VLOG_LEVELS \
+ VLOG_LEVEL(EMER) \
+ VLOG_LEVEL(ERR) \
+ VLOG_LEVEL(WARN) \
+ VLOG_LEVEL(DBG)
enum vlog_level {
- VLL_EMER,
- VLL_ERR,
- VLL_WARN,
- VLL_DBG,
+#define VLOG_LEVEL(NAME) VLL_##NAME,
+ VLOG_LEVELS
+#undef VLOG_LEVEL
VLL_N_LEVELS
};
enum vlog_level vlog_get_level_val(const char *name);
/* Facilities that we can log to. */
+#define VLOG_FACILITIES \
+ VLOG_FACILITY(SYSLOG) \
+ VLOG_FACILITY(CONSOLE)
enum vlog_facility {
- VLF_SYSLOG,
- VLF_CONSOLE,
+#define VLOG_FACILITY(NAME) VLF_##NAME,
+ VLOG_FACILITIES
+#undef VLOG_FACILITY
VLF_N_FACILITIES,
VLF_ANY_FACILITY = -1
};
size_t max_args; /* Maximum number of arguments. */
};
-static struct option_class classes[DHCP_N_OPTIONS] = {
- [0 ... 255] = {NULL, DHCP_ARG_UINT8, 0, SIZE_MAX},
-#define DHCP_OPT(NAME, CODE, TYPE, MIN, MAX) \
- [CODE] = {#NAME, DHCP_ARG_##TYPE, MIN, MAX},
- DHCP_OPTS
+static const struct option_class *
+get_option_class(int code)
+{
+ static struct option_class classes[DHCP_N_OPTIONS];
+ static bool init = false;
+ if (!init) {
+ int i;
+
+ init = true;
+#define DHCP_OPT(NAME, CODE, TYPE, MIN, MAX) \
+ classes[CODE].name = #NAME; \
+ classes[CODE].type = DHCP_ARG_##TYPE; \
+ classes[CODE].min_args = MIN; \
+ classes[CODE].max_args = MAX;
+ DHCP_OPTS
#undef DHCP_OPT
-};
+
+ for (i = 0; i < DHCP_N_OPTIONS; i++) {
+ if (!classes[i].name) {
+ classes[i].name = xasprintf("option-%d", i);
+ classes[i].type = DHCP_ARG_UINT8;
+ classes[i].min_args = 0;
+ classes[i].max_args = SIZE_MAX;
+ }
+ }
+ }
+ assert(code >= 0 && code < DHCP_N_OPTIONS);
+ return &classes[code];
+}
/* A single (bad) DHCP message can in theory dump out many, many log messages,
* especially at high logging levels, so the burst size is set quite high
const char *
dhcp_option_to_string(const struct dhcp_option *opt, int code, struct ds *ds)
{
- struct option_class *class = &classes[code];
+ const struct option_class *class = get_option_class(code);
const struct arg_type *type = &types[class->type];
size_t offset;
+ const char *cp;
- if (class->name) {
- const char *cp;
- for (cp = class->name; *cp; cp++) {
- unsigned char c = *cp;
- ds_put_char(ds, c == '_' ? '-' : tolower(c));
- }
- } else {
- ds_put_format(ds, "option-%d", code);
+ for (cp = class->name; *cp; cp++) {
+ unsigned char c = *cp;
+ ds_put_char(ds, c == '_' ? '-' : tolower(c));
}
ds_put_char(ds, '=');
for (code = 0; code < DHCP_N_OPTIONS; code++) {
struct dhcp_option *opt = &msg->options[code];
- struct option_class *class = &classes[code];
+ const struct option_class *class = get_option_class(code);
struct arg_type *type = &types[class->type];
if (opt->data) {
size_t n_elems = opt->n / type->size;
}
}
+static size_t
+min_size(uint8_t type)
+{
+ return (type == OFPT_FEATURES_REPLY ? sizeof(struct ofp_switch_features)
+ : type == OFPT_PACKET_IN ? offsetof (struct ofp_packet_in, data)
+ : sizeof(struct ofp_header));
+}
+
/* Processes 'msg', which should be an OpenFlow received on 'rconn', according
* to the learning switch state in 'sw'. The most likely result of processing
* is that flow-setup and packet-out OpenFlow messages will be sent out on
lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
const struct ofpbuf *msg)
{
- static const size_t min_size[UINT8_MAX + 1] = {
- [0 ... UINT8_MAX] = sizeof (struct ofp_header),
- [OFPT_FEATURES_REPLY] = sizeof (struct ofp_switch_features),
- [OFPT_PACKET_IN] = offsetof (struct ofp_packet_in, data),
- };
struct ofp_header *oh;
oh = msg->data;
- if (msg->size < min_size[oh->type]) {
+ if (msg->size < min_size(oh->type)) {
VLOG_WARN_RL(&rl,
"%s: too short (%zu bytes) for type %"PRIu8" (min %zu)",
rconn_get_name(rconn),
- msg->size, oh->type, min_size[oh->type]);
+ msg->size, oh->type, min_size(oh->type));
return;
}
};
struct stats_type {
+ int type;
const char *name;
struct stats_msg request;
struct stats_msg reply;
};
static const struct stats_type stats_types[] = {
- [OFPST_DESC] = {
+ {
+ OFPST_DESC,
"description",
{ 0, 0, NULL },
{ 0, SIZE_MAX, ofp_desc_stats_reply },
},
- [OFPST_FLOW] = {
+ {
+ OFPST_FLOW,
"flow",
{ sizeof(struct ofp_flow_stats_request),
sizeof(struct ofp_flow_stats_request),
ofp_flow_stats_request },
{ 0, SIZE_MAX, ofp_flow_stats_reply },
},
- [OFPST_AGGREGATE] = {
+ {
+ OFPST_AGGREGATE,
"aggregate",
{ sizeof(struct ofp_aggregate_stats_request),
sizeof(struct ofp_aggregate_stats_request),
sizeof(struct ofp_aggregate_stats_reply),
ofp_aggregate_stats_reply },
},
- [OFPST_TABLE] = {
+ {
+ OFPST_TABLE,
"table",
{ 0, 0, NULL },
{ 0, SIZE_MAX, ofp_table_stats_reply },
},
- [OFPST_PORT] = {
+ {
+ OFPST_PORT,
"port",
{ 0, 0, NULL, },
{ 0, SIZE_MAX, ofp_port_stats_reply },
},
- [OFPST_SWITCH] = {
+ {
+ OFPST_SWITCH,
"switch status",
{ 0, 0, NULL, },
{ 0, SIZE_MAX, switch_status_reply },
},
+ {
+ -1,
+ "unknown",
+ { 0, 0, NULL, },
+ { 0, 0, NULL, },
+ },
};
const struct stats_type *s;
ds_put_format(string, " ***unknown type %d***", type);
return;
}
- s = &stats_types[type];
+ for (s = stats_types; s->type >= 0; s++) {
+ if (s->type == type) {
+ break;
+ }
+ }
ds_put_format(string, " type=%d(%s)\n", type, s->name);
m = direction == REQUEST ? &s->request : &s->reply;
}
struct openflow_packet {
+ uint8_t type;
const char *name;
size_t min_size;
void (*printer)(struct ds *, const void *, size_t len, int verbosity);
};
static const struct openflow_packet packets[] = {
- [OFPT_FEATURES_REQUEST] = {
+ {
+ OFPT_FEATURES_REQUEST,
"features_request",
sizeof (struct ofp_header),
NULL,
},
- [OFPT_FEATURES_REPLY] = {
+ {
+ OFPT_FEATURES_REPLY,
"features_reply",
sizeof (struct ofp_switch_features),
ofp_print_switch_features,
},
- [OFPT_GET_CONFIG_REQUEST] = {
+ {
+ OFPT_GET_CONFIG_REQUEST,
"get_config_request",
sizeof (struct ofp_header),
NULL,
},
- [OFPT_GET_CONFIG_REPLY] = {
+ {
+ OFPT_GET_CONFIG_REPLY,
"get_config_reply",
sizeof (struct ofp_switch_config),
ofp_print_switch_config,
},
- [OFPT_SET_CONFIG] = {
+ {
+ OFPT_SET_CONFIG,
"set_config",
sizeof (struct ofp_switch_config),
ofp_print_switch_config,
},
- [OFPT_PACKET_IN] = {
+ {
+ OFPT_PACKET_IN,
"packet_in",
offsetof(struct ofp_packet_in, data),
ofp_packet_in,
},
- [OFPT_PACKET_OUT] = {
+ {
+ OFPT_PACKET_OUT,
"packet_out",
sizeof (struct ofp_packet_out),
ofp_packet_out,
},
- [OFPT_FLOW_MOD] = {
+ {
+ OFPT_FLOW_MOD,
"flow_mod",
sizeof (struct ofp_flow_mod),
ofp_print_flow_mod,
},
- [OFPT_FLOW_EXPIRED] = {
+ {
+ OFPT_FLOW_EXPIRED,
"flow_expired",
sizeof (struct ofp_flow_expired),
ofp_print_flow_expired,
},
- [OFPT_PORT_MOD] = {
+ {
+ OFPT_PORT_MOD,
"port_mod",
sizeof (struct ofp_port_mod),
NULL,
},
- [OFPT_PORT_STATUS] = {
+ {
+ OFPT_PORT_STATUS,
"port_status",
sizeof (struct ofp_port_status),
ofp_print_port_status
},
- [OFPT_ERROR_MSG] = {
+ {
+ OFPT_ERROR_MSG,
"error_msg",
sizeof (struct ofp_error_msg),
ofp_print_error_msg,
},
- [OFPT_STATS_REQUEST] = {
+ {
+ OFPT_STATS_REQUEST,
"stats_request",
sizeof (struct ofp_stats_request),
ofp_stats_request,
},
- [OFPT_STATS_REPLY] = {
+ {
+ OFPT_STATS_REPLY,
"stats_reply",
sizeof (struct ofp_stats_reply),
ofp_stats_reply,
},
- [OFPT_ECHO_REQUEST] = {
+ {
+ OFPT_ECHO_REQUEST,
"echo_request",
sizeof (struct ofp_header),
ofp_echo,
},
- [OFPT_ECHO_REPLY] = {
+ {
+ OFPT_ECHO_REPLY,
"echo_reply",
sizeof (struct ofp_header),
ofp_echo,
ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n", oh->version);
ds_put_hex_dump(&string, oh, len, 0, true);
return ds_cstr(&string);
- } else if (oh->type >= ARRAY_SIZE(packets) || !packets[oh->type].name) {
- ds_put_format(&string, "Unknown OpenFlow packet type %"PRIu8":\n",
- oh->type);
- ds_put_hex_dump(&string, oh, len, 0, true);
- return ds_cstr(&string);
}
- pkt = &packets[oh->type];
+ for (pkt = packets; ; pkt++) {
+ if (pkt >= &packets[ARRAY_SIZE(packets)]) {
+ ds_put_format(&string, "Unknown OpenFlow packet type %"PRIu8":\n",
+ oh->type);
+ ds_put_hex_dump(&string, oh, len, 0, true);
+ return ds_cstr(&string);
+ } else if (oh->type == pkt->type) {
+ break;
+ }
+ }
+
ds_put_format(&string, "%s (xid=0x%"PRIx32"):", pkt->name, oh->xid);
if (ntohs(oh->length) > len)
/* Name for each logging level. */
static const char *level_names[VLL_N_LEVELS] = {
- [VLL_EMER] = "EMER",
- [VLL_ERR] = "ERR",
- [VLL_WARN] = "WARN",
- [VLL_DBG] = "DBG",
+#define VLOG_LEVEL(NAME) #NAME,
+ VLOG_LEVELS
+#undef VLOG_LEVEL
};
/* Name for each logging facility. */
static const char *facility_names[VLF_N_FACILITIES] = {
- [VLF_CONSOLE] = "console",
- [VLF_SYSLOG] = "syslog",
+#define VLOG_FACILITY(NAME) #NAME,
+ VLOG_FACILITIES
+#undef VLOG_FACILITY
};
/* Name for each logging module */
}
if (log_syslog) {
- static const int syslog_levels[VLL_N_LEVELS] = {
- [VLL_EMER] = LOG_ALERT,
- [VLL_ERR] = LOG_ERR,
- [VLL_WARN] = LOG_WARNING,
- [VLL_DBG] = LOG_DEBUG,
- };
+ int syslog_level = LOG_ALERT;
char *save_ptr = NULL;
char *line;
+ switch (level) {
+ case VLL_EMER: syslog_level = LOG_ALERT; break;
+ case VLL_ERR: syslog_level = LOG_ERR; break;
+ case VLL_WARN: syslog_level = LOG_WARNING; break;
+ case VLL_DBG: syslog_level = LOG_DEBUG; break;
+ case VLL_N_LEVELS: NOT_REACHED();
+ }
for (line = strtok_r(&s.string[time_len], "\n", &save_ptr); line;
line = strtok_r(NULL, "\n", &save_ptr)) {
- syslog(syslog_levels[level], "%s", line);
+ syslog(syslog_level, "%s", line);
}
}
}
struct stats_type {
+ /* Value for 'type' member of struct ofp_stats_request. */
+ int type;
+
/* Minimum and maximum acceptable number of bytes in body member of
* struct ofp_stats_request. */
size_t min_body, max_body;
};
static const struct stats_type stats[] = {
- [OFPST_DESC] = {
+ {
+ OFPST_DESC,
0,
0,
NULL,
desc_stats_dump,
NULL
},
- [OFPST_FLOW] = {
+ {
+ OFPST_FLOW,
sizeof(struct ofp_flow_stats_request),
sizeof(struct ofp_flow_stats_request),
flow_stats_init,
flow_stats_dump,
flow_stats_done
},
- [OFPST_AGGREGATE] = {
+ {
+ OFPST_AGGREGATE,
sizeof(struct ofp_aggregate_stats_request),
sizeof(struct ofp_aggregate_stats_request),
aggregate_stats_init,
aggregate_stats_dump,
aggregate_stats_done
},
- [OFPST_TABLE] = {
+ {
+ OFPST_TABLE,
0,
0,
NULL,
table_stats_dump,
NULL
},
- [OFPST_PORT] = {
+ {
+ OFPST_PORT,
0,
0,
port_stats_init,
osr = make_openflow_reply(sizeof *osr, OFPT_STATS_REPLY, &cb->sender,
&buffer);
- osr->type = htons(cb->s - stats);
+ osr->type = htons(cb->s->type);
osr->flags = 0;
err = cb->s->dump(dp, cb->state, buffer);
{
const struct ofp_stats_request *rq = oh;
size_t rq_len = ntohs(rq->header.length);
+ const struct stats_type *st;
struct stats_dump_cb *cb;
int type, body_len;
int err;
type = ntohs(rq->type);
- if (type >= ARRAY_SIZE(stats) || !stats[type].dump) {
- VLOG_WARN_RL(&rl, "received stats request of unknown type %d", type);
- return -EINVAL;
+ for (st = stats; ; st++) {
+ if (st >= &stats[ARRAY_SIZE(stats)]) {
+ VLOG_WARN_RL(&rl, "received stats request of unknown type %d",
+ type);
+ return -EINVAL;
+ } else if (type == st->type) {
+ break;
+ }
}
cb = xmalloc(sizeof *cb);
cb->done = false;
cb->rq = xmemdup(rq, rq_len);
cb->sender = *sender;
- cb->s = &stats[type];
+ cb->s = st;
cb->state = NULL;
body_len = rq_len - offsetof(struct ofp_stats_request, body);
fwd_control_input(struct datapath *dp, const struct sender *sender,
const void *msg, size_t length)
{
- struct openflow_packet {
- size_t min_size;
- int (*handler)(struct datapath *, const struct sender *, const void *);
- };
-
- static const struct openflow_packet packets[] = {
- [OFPT_FEATURES_REQUEST] = {
- sizeof (struct ofp_header),
- recv_features_request,
- },
- [OFPT_GET_CONFIG_REQUEST] = {
- sizeof (struct ofp_header),
- recv_get_config_request,
- },
- [OFPT_SET_CONFIG] = {
- sizeof (struct ofp_switch_config),
- recv_set_config,
- },
- [OFPT_PACKET_OUT] = {
- sizeof (struct ofp_packet_out),
- recv_packet_out,
- },
- [OFPT_FLOW_MOD] = {
- sizeof (struct ofp_flow_mod),
- recv_flow,
- },
- [OFPT_PORT_MOD] = {
- sizeof (struct ofp_port_mod),
- recv_port_mod,
- },
- [OFPT_STATS_REQUEST] = {
- sizeof (struct ofp_stats_request),
- recv_stats_request,
- },
- [OFPT_ECHO_REQUEST] = {
- sizeof (struct ofp_header),
- recv_echo_request,
- },
- [OFPT_ECHO_REPLY] = {
- sizeof (struct ofp_header),
- recv_echo_reply,
- },
- };
-
- const struct openflow_packet *pkt;
+ int (*handler)(struct datapath *, const struct sender *, const void *);
struct ofp_header *oh;
+ size_t min_size;
+ /* Check encapsulated length. */
oh = (struct ofp_header *) msg;
- assert(oh->version == OFP_VERSION);
- if (oh->type >= ARRAY_SIZE(packets) || ntohs(oh->length) > length)
+ if (ntohs(oh->length) > length) {
return -EINVAL;
+ }
+ assert(oh->version == OFP_VERSION);
- pkt = &packets[oh->type];
- if (!pkt->handler)
+ /* Figure out how to handle it. */
+ switch (oh->type) {
+ case OFPT_FEATURES_REQUEST:
+ min_size = sizeof(struct ofp_header);
+ handler = recv_features_request;
+ break;
+ case OFPT_GET_CONFIG_REQUEST:
+ min_size = sizeof(struct ofp_header);
+ handler = recv_get_config_request;
+ break;
+ case OFPT_SET_CONFIG:
+ min_size = sizeof(struct ofp_switch_config);
+ handler = recv_set_config;
+ break;
+ case OFPT_PACKET_OUT:
+ min_size = sizeof(struct ofp_packet_out);
+ handler = recv_packet_out;
+ break;
+ case OFPT_FLOW_MOD:
+ min_size = sizeof(struct ofp_flow_mod);
+ handler = recv_flow;
+ break;
+ case OFPT_PORT_MOD:
+ min_size = sizeof(struct ofp_port_mod);
+ handler = recv_port_mod;
+ break;
+ case OFPT_STATS_REQUEST:
+ min_size = sizeof(struct ofp_stats_request);
+ handler = recv_stats_request;
+ break;
+ case OFPT_ECHO_REQUEST:
+ min_size = sizeof(struct ofp_header);
+ handler = recv_echo_request;
+ break;
+ case OFPT_ECHO_REPLY:
+ min_size = sizeof(struct ofp_header);
+ handler = recv_echo_reply;
+ break;
+ default:
return -ENOSYS;
- if (length < pkt->min_size)
- return -EFAULT;
+ }
- return pkt->handler(dp, sender, msg);
+ /* Handle it. */
+ if (length < min_size)
+ return -EFAULT;
+ return handler(dp, sender, msg);
}
\f
/* Packet buffering. */