2009-07-08 13:19:16 -07:00
|
|
|
|
/*
|
2012-01-12 11:35:50 -08:00
|
|
|
|
* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*
|
2009-06-15 15:11:30 -07:00
|
|
|
|
* 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:
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*
|
2009-06-15 15:11:30 -07:00
|
|
|
|
* 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.
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "ofp-print.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <inttypes.h>
|
2010-02-12 12:51:36 -08:00
|
|
|
|
#include <sys/types.h>
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
2011-06-10 17:45:45 -07:00
|
|
|
|
#include "bundle.h"
|
2010-10-28 17:13:18 -07:00
|
|
|
|
#include "byte-order.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "compiler.h"
|
|
|
|
|
#include "dynamic-string.h"
|
|
|
|
|
#include "flow.h"
|
2011-09-12 16:19:57 -07:00
|
|
|
|
#include "learn.h"
|
2010-12-17 14:38:50 -08:00
|
|
|
|
#include "multipath.h"
|
2011-12-28 12:42:14 -08:00
|
|
|
|
#include "meta-flow.h"
|
2010-12-07 13:22:46 -08:00
|
|
|
|
#include "nx-match.h"
|
2012-01-12 15:48:19 -08:00
|
|
|
|
#include "ofp-errors.h"
|
2010-11-10 16:22:18 -08:00
|
|
|
|
#include "ofp-util.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "ofpbuf.h"
|
|
|
|
|
#include "openflow/openflow.h"
|
|
|
|
|
#include "openflow/nicira-ext.h"
|
|
|
|
|
#include "packets.h"
|
|
|
|
|
#include "pcap.h"
|
2010-12-09 10:41:32 -08:00
|
|
|
|
#include "type-props.h"
|
2011-01-18 11:50:56 -08:00
|
|
|
|
#include "unaligned.h"
|
2009-07-08 13:19:16 -07:00
|
|
|
|
#include "util.h"
|
|
|
|
|
|
2010-09-16 15:36:57 -07:00
|
|
|
|
static void ofp_print_queue_name(struct ds *string, uint32_t port);
|
2012-01-12 15:48:19 -08:00
|
|
|
|
static void ofp_print_error(struct ds *, enum ofperr);
|
2010-12-07 13:22:46 -08:00
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
/* Returns a string that represents the contents of the Ethernet frame in the
|
2011-12-21 12:59:28 -08:00
|
|
|
|
* 'len' bytes starting at 'data'. The caller must free the returned string.*/
|
2009-07-08 13:19:16 -07:00
|
|
|
|
char *
|
2011-12-22 17:47:15 -08:00
|
|
|
|
ofp_packet_to_string(const void *data, size_t len)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
struct ds ds = DS_EMPTY_INITIALIZER;
|
|
|
|
|
struct ofpbuf buf;
|
2011-12-21 12:59:28 -08:00
|
|
|
|
struct flow flow;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2010-12-02 14:53:12 -08:00
|
|
|
|
ofpbuf_use_const(&buf, data, len);
|
2011-12-21 12:59:28 -08:00
|
|
|
|
flow_extract(&buf, 0, 0, 0, &flow);
|
|
|
|
|
flow_format(&ds, &flow);
|
2011-12-20 19:56:43 -08:00
|
|
|
|
|
|
|
|
|
if (buf.l7) {
|
|
|
|
|
if (flow.nw_proto == IPPROTO_TCP) {
|
|
|
|
|
struct tcp_header *th = buf.l4;
|
|
|
|
|
ds_put_format(&ds, " tcp_csum:%"PRIx16,
|
|
|
|
|
ntohs(th->tcp_csum));
|
|
|
|
|
} else if (flow.nw_proto == IPPROTO_UDP) {
|
|
|
|
|
struct udp_header *uh = buf.l4;
|
|
|
|
|
ds_put_format(&ds, " udp_csum:%"PRIx16,
|
|
|
|
|
ntohs(uh->udp_csum));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-21 12:59:28 -08:00
|
|
|
|
ds_put_char(&ds, '\n');
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
return ds_cstr(&ds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-12-22 16:35:23 -08:00
|
|
|
|
ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
|
2010-12-06 10:20:20 -08:00
|
|
|
|
int verbosity)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-12-22 16:35:23 -08:00
|
|
|
|
struct ofputil_packet_in pin;
|
|
|
|
|
int error;
|
2012-01-04 16:40:13 -08:00
|
|
|
|
int i;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-12-22 16:35:23 -08:00
|
|
|
|
error = ofputil_decode_packet_in(&pin, oh);
|
|
|
|
|
if (error) {
|
|
|
|
|
ofp_print_error(string, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-09 15:48:26 -08:00
|
|
|
|
if (pin.table_id) {
|
|
|
|
|
ds_put_format(string, " table_id=%"PRIu8, pin.table_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pin.cookie) {
|
|
|
|
|
ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-22 16:35:23 -08:00
|
|
|
|
ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len);
|
2012-01-04 16:40:13 -08:00
|
|
|
|
ofputil_format_port(pin.fmd.in_port, string);
|
|
|
|
|
|
|
|
|
|
if (pin.fmd.tun_id_mask) {
|
|
|
|
|
ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id));
|
|
|
|
|
if (pin.fmd.tun_id_mask != htonll(UINT64_MAX)) {
|
|
|
|
|
ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.tun_id_mask));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < FLOW_N_REGS; i++) {
|
|
|
|
|
if (pin.fmd.reg_masks[i]) {
|
|
|
|
|
ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.fmd.regs[i]);
|
|
|
|
|
if (pin.fmd.reg_masks[i] != UINT32_MAX) {
|
|
|
|
|
ds_put_format(string, "/0x%"PRIx32, pin.fmd.reg_masks[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-02-09 14:06:35 -08:00
|
|
|
|
ds_put_format(string, " (via %s)",
|
2012-02-07 14:46:34 -08:00
|
|
|
|
ofputil_packet_in_reason_to_string(pin.reason));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-12-22 16:35:23 -08:00
|
|
|
|
ds_put_format(string, " data_len=%zu", pin.packet_len);
|
|
|
|
|
if (pin.buffer_id == UINT32_MAX) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, " (unbuffered)");
|
2011-12-22 16:35:23 -08:00
|
|
|
|
if (pin.total_len != pin.packet_len) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, " (***total_len != data_len***)");
|
2011-12-22 16:35:23 -08:00
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
} else {
|
2011-12-22 16:35:23 -08:00
|
|
|
|
ds_put_format(string, " buffer=0x%08"PRIx32, pin.buffer_id);
|
|
|
|
|
if (pin.total_len < pin.packet_len) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, " (***total_len < data_len***)");
|
2011-12-22 16:35:23 -08:00
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
|
|
|
|
|
if (verbosity > 0) {
|
2011-12-22 16:35:23 -08:00
|
|
|
|
char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(string, packet);
|
|
|
|
|
free(packet);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 16:23:26 -08:00
|
|
|
|
static void
|
|
|
|
|
print_note(struct ds *string, const struct nx_action_note *nan)
|
|
|
|
|
{
|
|
|
|
|
size_t len;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, "note:");
|
|
|
|
|
len = ntohs(nan->len) - offsetof(struct nx_action_note, note);
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (i) {
|
|
|
|
|
ds_put_char(string, '.');
|
|
|
|
|
}
|
|
|
|
|
ds_put_format(string, "%02"PRIx8, nan->note[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2011-06-30 10:05:52 -07:00
|
|
|
|
ofp_print_action(struct ds *s, const union ofp_action *a,
|
|
|
|
|
enum ofputil_action_code code)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-06-30 10:05:52 -07:00
|
|
|
|
const struct ofp_action_enqueue *oae;
|
|
|
|
|
const struct ofp_action_dl_addr *oada;
|
|
|
|
|
const struct nx_action_set_tunnel64 *nast64;
|
|
|
|
|
const struct nx_action_set_tunnel *nast;
|
|
|
|
|
const struct nx_action_set_queue *nasq;
|
|
|
|
|
const struct nx_action_resubmit *nar;
|
|
|
|
|
const struct nx_action_reg_move *move;
|
|
|
|
|
const struct nx_action_reg_load *load;
|
|
|
|
|
const struct nx_action_multipath *nam;
|
|
|
|
|
const struct nx_action_autopath *naa;
|
2011-08-10 13:05:17 -07:00
|
|
|
|
const struct nx_action_output_reg *naor;
|
2012-02-15 10:37:03 -08:00
|
|
|
|
const struct nx_action_fin_timeout *naft;
|
2012-02-09 14:17:33 -08:00
|
|
|
|
const struct nx_action_controller *nac;
|
2011-12-28 12:42:14 -08:00
|
|
|
|
struct mf_subfield subfield;
|
2011-06-30 10:05:52 -07:00
|
|
|
|
uint16_t port;
|
|
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
|
case OFPUTIL_OFPAT_OUTPUT:
|
|
|
|
|
port = ntohs(a->output.port);
|
|
|
|
|
if (port < OFPP_MAX) {
|
|
|
|
|
ds_put_format(s, "output:%"PRIu16, port);
|
|
|
|
|
} else {
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(port, s);
|
2011-06-30 10:05:52 -07:00
|
|
|
|
if (port == OFPP_CONTROLLER) {
|
|
|
|
|
if (a->output.max_len != htons(0)) {
|
|
|
|
|
ds_put_format(s, ":%"PRIu16, ntohs(a->output.max_len));
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_cstr(s, ":all");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2010-12-09 11:03:35 -08:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_ENQUEUE:
|
|
|
|
|
oae = (const struct ofp_action_enqueue *) a;
|
|
|
|
|
ds_put_format(s, "enqueue:");
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(ntohs(oae->port), s);
|
2011-06-30 10:05:52 -07:00
|
|
|
|
ds_put_format(s, "q%"PRIu32, ntohl(oae->queue_id));
|
|
|
|
|
break;
|
2010-12-09 10:41:32 -08:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_VLAN_VID:
|
|
|
|
|
ds_put_format(s, "mod_vlan_vid:%"PRIu16,
|
|
|
|
|
ntohs(a->vlan_vid.vlan_vid));
|
|
|
|
|
break;
|
2010-10-02 00:27:23 -07:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_VLAN_PCP:
|
|
|
|
|
ds_put_format(s, "mod_vlan_pcp:%"PRIu8, a->vlan_pcp.vlan_pcp);
|
|
|
|
|
break;
|
2010-11-12 16:23:26 -08:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_STRIP_VLAN:
|
|
|
|
|
ds_put_cstr(s, "strip_vlan");
|
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_DL_SRC:
|
|
|
|
|
oada = (const struct ofp_action_dl_addr *) a;
|
|
|
|
|
ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT,
|
|
|
|
|
ETH_ADDR_ARGS(oada->dl_addr));
|
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_DL_DST:
|
|
|
|
|
oada = (const struct ofp_action_dl_addr *) a;
|
|
|
|
|
ds_put_format(s, "mod_dl_dst:"ETH_ADDR_FMT,
|
|
|
|
|
ETH_ADDR_ARGS(oada->dl_addr));
|
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_NW_SRC:
|
|
|
|
|
ds_put_format(s, "mod_nw_src:"IP_FMT, IP_ARGS(&a->nw_addr.nw_addr));
|
|
|
|
|
break;
|
2010-08-30 00:24:53 -07:00
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_NW_DST:
|
|
|
|
|
ds_put_format(s, "mod_nw_dst:"IP_FMT, IP_ARGS(&a->nw_addr.nw_addr));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_NW_TOS:
|
|
|
|
|
ds_put_format(s, "mod_nw_tos:%d", a->nw_tos.nw_tos);
|
2010-07-16 15:30:09 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_TP_SRC:
|
|
|
|
|
ds_put_format(s, "mod_tp_src:%d", ntohs(a->tp_port.tp_port));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_OFPAT_SET_TP_DST:
|
|
|
|
|
ds_put_format(s, "mod_tp_dst:%d", ntohs(a->tp_port.tp_port));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_RESUBMIT:
|
|
|
|
|
nar = (struct nx_action_resubmit *)a;
|
|
|
|
|
ds_put_format(s, "resubmit:");
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(ntohs(nar->in_port), s);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-08-09 09:24:18 -07:00
|
|
|
|
case OFPUTIL_NXAST_RESUBMIT_TABLE:
|
|
|
|
|
nar = (struct nx_action_resubmit *)a;
|
|
|
|
|
ds_put_format(s, "resubmit(");
|
|
|
|
|
if (nar->in_port != htons(OFPP_IN_PORT)) {
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(ntohs(nar->in_port), s);
|
2011-08-09 09:24:18 -07:00
|
|
|
|
}
|
|
|
|
|
ds_put_char(s, ',');
|
|
|
|
|
if (nar->table != 255) {
|
|
|
|
|
ds_put_format(s, "%"PRIu8, nar->table);
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(s, ')');
|
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_SET_TUNNEL:
|
|
|
|
|
nast = (struct nx_action_set_tunnel *)a;
|
|
|
|
|
ds_put_format(s, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_SET_QUEUE:
|
|
|
|
|
nasq = (struct nx_action_set_queue *)a;
|
|
|
|
|
ds_put_format(s, "set_queue:%u", ntohl(nasq->queue_id));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_POP_QUEUE:
|
|
|
|
|
ds_put_cstr(s, "pop_queue");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_NOTE:
|
|
|
|
|
print_note(s, (const struct nx_action_note *) a);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_REG_MOVE:
|
|
|
|
|
move = (const struct nx_action_reg_move *) a;
|
|
|
|
|
nxm_format_reg_move(move, s);
|
2009-11-11 14:59:49 -08:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_REG_LOAD:
|
|
|
|
|
load = (const struct nx_action_reg_load *) a;
|
|
|
|
|
nxm_format_reg_load(load, s);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_SET_TUNNEL64:
|
|
|
|
|
nast64 = (const struct nx_action_set_tunnel64 *) a;
|
|
|
|
|
ds_put_format(s, "set_tunnel64:%#"PRIx64,
|
|
|
|
|
ntohll(nast64->tun_id));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-30 10:05:52 -07:00
|
|
|
|
case OFPUTIL_NXAST_MULTIPATH:
|
|
|
|
|
nam = (const struct nx_action_multipath *) a;
|
|
|
|
|
multipath_format(nam, s);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_NXAST_AUTOPATH:
|
|
|
|
|
naa = (const struct nx_action_autopath *)a;
|
|
|
|
|
ds_put_format(s, "autopath(%u,", ntohl(naa->id));
|
2011-12-28 12:42:14 -08:00
|
|
|
|
nxm_decode(&subfield, naa->dst, naa->ofs_nbits);
|
|
|
|
|
mf_format_subfield(&subfield, s);
|
2011-06-30 10:05:52 -07:00
|
|
|
|
ds_put_char(s, ')');
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
|
2011-06-10 17:45:45 -07:00
|
|
|
|
case OFPUTIL_NXAST_BUNDLE:
|
2011-07-20 15:07:46 -07:00
|
|
|
|
case OFPUTIL_NXAST_BUNDLE_LOAD:
|
2011-06-10 17:45:45 -07:00
|
|
|
|
bundle_format((const struct nx_action_bundle *) a, s);
|
|
|
|
|
break;
|
|
|
|
|
|
2011-08-10 13:05:17 -07:00
|
|
|
|
case OFPUTIL_NXAST_OUTPUT_REG:
|
|
|
|
|
naor = (const struct nx_action_output_reg *) a;
|
|
|
|
|
ds_put_cstr(s, "output:");
|
2011-12-28 12:42:14 -08:00
|
|
|
|
nxm_decode(&subfield, naor->src, naor->ofs_nbits);
|
|
|
|
|
mf_format_subfield(&subfield, s);
|
2011-08-15 15:18:12 -07:00
|
|
|
|
break;
|
2011-08-10 13:05:17 -07:00
|
|
|
|
|
2011-09-12 16:19:57 -07:00
|
|
|
|
case OFPUTIL_NXAST_LEARN:
|
|
|
|
|
learn_format((const struct nx_action_learn *) a, s);
|
|
|
|
|
break;
|
|
|
|
|
|
2012-01-13 17:54:04 -08:00
|
|
|
|
case OFPUTIL_NXAST_DEC_TTL:
|
|
|
|
|
ds_put_cstr(s, "dec_ttl");
|
|
|
|
|
break;
|
|
|
|
|
|
2011-10-28 14:46:42 -07:00
|
|
|
|
case OFPUTIL_NXAST_EXIT:
|
|
|
|
|
ds_put_cstr(s, "exit");
|
|
|
|
|
break;
|
|
|
|
|
|
2012-02-15 10:37:03 -08:00
|
|
|
|
case OFPUTIL_NXAST_FIN_TIMEOUT:
|
|
|
|
|
naft = (const struct nx_action_fin_timeout *) a;
|
|
|
|
|
ds_put_cstr(s, "fin_timeout(");
|
|
|
|
|
if (naft->fin_idle_timeout) {
|
|
|
|
|
ds_put_format(s, "idle_timeout=%"PRIu16",",
|
|
|
|
|
ntohs(naft->fin_idle_timeout));
|
|
|
|
|
}
|
|
|
|
|
if (naft->fin_hard_timeout) {
|
|
|
|
|
ds_put_format(s, "hard_timeout=%"PRIu16",",
|
|
|
|
|
ntohs(naft->fin_hard_timeout));
|
|
|
|
|
}
|
|
|
|
|
ds_chomp(s, ',');
|
|
|
|
|
ds_put_char(s, ')');
|
|
|
|
|
break;
|
|
|
|
|
|
2012-02-09 14:17:33 -08:00
|
|
|
|
case OFPUTIL_NXAST_CONTROLLER:
|
|
|
|
|
nac = (const struct nx_action_controller *) a;
|
|
|
|
|
ds_put_cstr(s, "controller(");
|
|
|
|
|
if (nac->reason != OFPR_ACTION) {
|
|
|
|
|
ds_put_format(s, "reason=%s,",
|
|
|
|
|
ofputil_packet_in_reason_to_string(nac->reason));
|
|
|
|
|
}
|
|
|
|
|
if (nac->max_len != htons(UINT16_MAX)) {
|
|
|
|
|
ds_put_format(s, "max_len=%"PRIu16",", ntohs(nac->max_len));
|
|
|
|
|
}
|
|
|
|
|
if (nac->controller_id != htons(0)) {
|
|
|
|
|
ds_put_format(s, "id=%"PRIu16",", ntohs(nac->controller_id));
|
|
|
|
|
}
|
|
|
|
|
ds_chomp(s, ',');
|
|
|
|
|
ds_put_char(s, ')');
|
|
|
|
|
break;
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-30 00:24:53 -07:00
|
|
|
|
void
|
2011-06-30 10:04:09 -07:00
|
|
|
|
ofp_print_actions(struct ds *string, const union ofp_action *actions,
|
|
|
|
|
size_t n_actions)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-06-30 10:04:09 -07:00
|
|
|
|
const union ofp_action *a;
|
|
|
|
|
size_t left;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, "actions=");
|
2011-06-30 10:04:09 -07:00
|
|
|
|
if (!n_actions) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(string, "drop");
|
|
|
|
|
}
|
2011-06-30 10:05:52 -07:00
|
|
|
|
|
2011-06-30 10:04:09 -07:00
|
|
|
|
OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) {
|
2011-06-30 10:05:52 -07:00
|
|
|
|
int code = ofputil_decode_action(a);
|
|
|
|
|
if (code >= 0) {
|
|
|
|
|
if (a != actions) {
|
|
|
|
|
ds_put_cstr(string, ",");
|
|
|
|
|
}
|
|
|
|
|
ofp_print_action(string, a, code);
|
|
|
|
|
} else {
|
|
|
|
|
ofp_print_error(string, -code);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2011-06-30 10:04:09 -07:00
|
|
|
|
}
|
|
|
|
|
if (left > 0) {
|
|
|
|
|
ds_put_format(string, " ***%zu leftover bytes following actions",
|
|
|
|
|
left * sizeof *a);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
|
|
|
|
|
int verbosity)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2012-02-06 14:17:49 -08:00
|
|
|
|
struct ofputil_packet_out po;
|
|
|
|
|
enum ofperr error;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2012-02-06 14:17:49 -08:00
|
|
|
|
error = ofputil_decode_packet_out(&po, opo);
|
|
|
|
|
if (error) {
|
|
|
|
|
ofp_print_error(string, error);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
2012-02-06 14:17:49 -08:00
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " in_port=");
|
|
|
|
|
ofputil_format_port(po.in_port, string);
|
|
|
|
|
|
|
|
|
|
ds_put_char(string, ' ');
|
|
|
|
|
ofp_print_actions(string, po.actions, po.n_actions);
|
|
|
|
|
|
|
|
|
|
if (po.buffer_id == UINT32_MAX) {
|
2012-02-09 01:39:49 -08:00
|
|
|
|
ds_put_format(string, " data_len=%zu", po.packet_len);
|
2012-02-06 14:17:49 -08:00
|
|
|
|
if (verbosity > 0 && po.packet_len > 0) {
|
|
|
|
|
char *packet = ofp_packet_to_string(po.packet, po.packet_len);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
ds_put_cstr(string, packet);
|
|
|
|
|
free(packet);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2012-02-06 14:17:49 -08:00
|
|
|
|
ds_put_format(string, " buffer=0x%08"PRIx32, po.buffer_id);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* qsort comparison function. */
|
|
|
|
|
static int
|
|
|
|
|
compare_ports(const void *a_, const void *b_)
|
|
|
|
|
{
|
|
|
|
|
const struct ofp_phy_port *a = a_;
|
|
|
|
|
const struct ofp_phy_port *b = b_;
|
|
|
|
|
uint16_t ap = ntohs(a->port_no);
|
|
|
|
|
uint16_t bp = ntohs(b->port_no);
|
|
|
|
|
|
|
|
|
|
return ap < bp ? -1 : ap > bp;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-14 15:17:33 -07:00
|
|
|
|
struct bit_name {
|
|
|
|
|
uint32_t bit;
|
|
|
|
|
const char *name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofp_print_bit_names(struct ds *string, uint32_t bits,
|
|
|
|
|
const struct bit_name bit_names[])
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-07-14 15:17:33 -07:00
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
if (!bits) {
|
|
|
|
|
ds_put_cstr(string, "0");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
2011-07-14 15:17:33 -07:00
|
|
|
|
|
|
|
|
|
for (; bits && bit_names->name; bit_names++) {
|
|
|
|
|
if (bits & bit_names->bit) {
|
|
|
|
|
if (n++) {
|
|
|
|
|
ds_put_char(string, ' ');
|
|
|
|
|
}
|
|
|
|
|
ds_put_cstr(string, bit_names->name);
|
|
|
|
|
bits &= ~bit_names->bit;
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2011-07-14 15:17:33 -07:00
|
|
|
|
|
|
|
|
|
if (bits) {
|
|
|
|
|
if (n++) {
|
|
|
|
|
ds_put_char(string, ' ');
|
|
|
|
|
}
|
|
|
|
|
ds_put_format(string, "0x%"PRIx32, bits);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2011-07-14 15:17:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofp_print_port_features(struct ds *string, uint32_t features)
|
|
|
|
|
{
|
|
|
|
|
static const struct bit_name feature_bits[] = {
|
|
|
|
|
{ OFPPF_10MB_HD, "10MB-HD" },
|
|
|
|
|
{ OFPPF_10MB_FD, "10MB-FD" },
|
|
|
|
|
{ OFPPF_100MB_HD, "100MB-HD" },
|
|
|
|
|
{ OFPPF_100MB_FD, "100MB-FD" },
|
|
|
|
|
{ OFPPF_1GB_HD, "1GB-HD" },
|
|
|
|
|
{ OFPPF_1GB_FD, "1GB-FD" },
|
|
|
|
|
{ OFPPF_10GB_FD, "10GB-FD" },
|
|
|
|
|
{ OFPPF_COPPER, "COPPER" },
|
|
|
|
|
{ OFPPF_FIBER, "FIBER" },
|
|
|
|
|
{ OFPPF_AUTONEG, "AUTO_NEG" },
|
|
|
|
|
{ OFPPF_PAUSE, "AUTO_PAUSE" },
|
|
|
|
|
{ OFPPF_PAUSE_ASYM, "AUTO_PAUSE_ASYM" },
|
|
|
|
|
{ 0, NULL },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ofp_print_bit_names(string, features, feature_bits);
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofp_print_port_config(struct ds *string, uint32_t config)
|
|
|
|
|
{
|
|
|
|
|
static const struct bit_name config_bits[] = {
|
|
|
|
|
{ OFPPC_PORT_DOWN, "PORT_DOWN" },
|
|
|
|
|
{ OFPPC_NO_STP, "NO_STP" },
|
|
|
|
|
{ OFPPC_NO_RECV, "NO_RECV" },
|
|
|
|
|
{ OFPPC_NO_RECV_STP, "NO_RECV_STP" },
|
|
|
|
|
{ OFPPC_NO_FLOOD, "NO_FLOOD" },
|
|
|
|
|
{ OFPPC_NO_FWD, "NO_FWD" },
|
|
|
|
|
{ OFPPC_NO_PACKET_IN, "NO_PACKET_IN" },
|
|
|
|
|
{ 0, NULL },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ofp_print_bit_names(string, config, config_bits);
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofp_print_port_state(struct ds *string, uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
static const struct bit_name state_bits[] = {
|
|
|
|
|
{ OFPPS_LINK_DOWN, "LINK_DOWN" },
|
|
|
|
|
{ 0, NULL },
|
|
|
|
|
};
|
|
|
|
|
uint32_t stp_state;
|
|
|
|
|
|
|
|
|
|
/* The STP state is a 2-bit field so it doesn't fit in with the bitmask
|
|
|
|
|
* pattern. We have to special case it.
|
|
|
|
|
*
|
|
|
|
|
* OVS doesn't support STP, so this field will always be 0 if we are
|
|
|
|
|
* talking to OVS, so we'd always print STP_LISTEN in that case.
|
|
|
|
|
* Therefore, we don't print anything at all if the value is STP_LISTEN, to
|
|
|
|
|
* avoid confusing users. */
|
|
|
|
|
stp_state = state & OFPPS_STP_MASK;
|
|
|
|
|
if (stp_state) {
|
|
|
|
|
ds_put_cstr(string, (stp_state == OFPPS_STP_LEARN ? "STP_LEARN"
|
|
|
|
|
: stp_state == OFPPS_STP_FORWARD ? "STP_FORWARD"
|
|
|
|
|
: "STP_BLOCK"));
|
|
|
|
|
state &= ~OFPPS_STP_MASK;
|
|
|
|
|
if (state) {
|
|
|
|
|
ofp_print_bit_names(string, state, state_bits);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ofp_print_bit_names(string, state, state_bits);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
|
|
|
|
|
{
|
2010-11-16 11:05:48 -08:00
|
|
|
|
char name[OFP_MAX_PORT_NAME_LEN];
|
2009-07-08 13:19:16 -07:00
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
memcpy(name, port->name, sizeof name);
|
|
|
|
|
for (j = 0; j < sizeof name - 1; j++) {
|
2011-04-15 09:31:36 -07:00
|
|
|
|
if (!isprint((unsigned char) name[j])) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
name[j] = '\0';
|
|
|
|
|
|
|
|
|
|
ds_put_char(string, ' ');
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(ntohs(port->port_no), string);
|
2011-07-14 15:17:33 -07:00
|
|
|
|
ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT"\n",
|
|
|
|
|
name, ETH_ADDR_ARGS(port->hw_addr));
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " config: ");
|
|
|
|
|
ofp_print_port_config(string, ntohl(port->config));
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " state: ");
|
|
|
|
|
ofp_print_port_state(string, ntohl(port->state));
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (port->curr) {
|
|
|
|
|
ds_put_format(string, " current: ");
|
|
|
|
|
ofp_print_port_features(string, ntohl(port->curr));
|
|
|
|
|
}
|
|
|
|
|
if (port->advertised) {
|
|
|
|
|
ds_put_format(string, " advertised: ");
|
|
|
|
|
ofp_print_port_features(string, ntohl(port->advertised));
|
|
|
|
|
}
|
|
|
|
|
if (port->supported) {
|
|
|
|
|
ds_put_format(string, " supported: ");
|
|
|
|
|
ofp_print_port_features(string, ntohl(port->supported));
|
|
|
|
|
}
|
|
|
|
|
if (port->peer) {
|
|
|
|
|
ds_put_format(string, " peer: ");
|
|
|
|
|
ofp_print_port_features(string, ntohl(port->peer));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_switch_features(struct ds *string,
|
|
|
|
|
const struct ofp_switch_features *osf)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-06 10:20:20 -08:00
|
|
|
|
size_t len = ntohs(osf->header.length);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
struct ofp_phy_port *port_list;
|
|
|
|
|
int n_ports;
|
|
|
|
|
int i;
|
|
|
|
|
|
2010-08-30 00:24:53 -07:00
|
|
|
|
ds_put_format(string, " ver:0x%x, dpid:%016"PRIx64"\n",
|
2009-07-08 13:19:16 -07:00
|
|
|
|
osf->header.version, ntohll(osf->datapath_id));
|
|
|
|
|
ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
|
|
|
|
|
ntohl(osf->n_buffers));
|
|
|
|
|
ds_put_format(string, "features: capabilities:%#x, actions:%#x\n",
|
|
|
|
|
ntohl(osf->capabilities), ntohl(osf->actions));
|
|
|
|
|
|
|
|
|
|
n_ports = (len - sizeof *osf) / sizeof *osf->ports;
|
|
|
|
|
|
2010-08-30 00:24:53 -07:00
|
|
|
|
port_list = xmemdup(osf->ports, len - sizeof *osf);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
qsort(port_list, n_ports, sizeof *port_list, compare_ports);
|
|
|
|
|
for (i = 0; i < n_ports; i++) {
|
|
|
|
|
ofp_print_phy_port(string, &port_list[i]);
|
|
|
|
|
}
|
|
|
|
|
free(port_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2012-01-13 17:54:04 -08:00
|
|
|
|
enum ofp_config_flags flags;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
flags = ntohs(osc->flags);
|
2010-12-14 12:08:10 -08:00
|
|
|
|
|
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It
has not been possible to match on L4 headers, even in fragments with offset
0 where they are actually present. This means that there was no way to
implement ACLs that treat, say, different TCP ports differently, on
fragmented traffic; instead, all decisions for fragment forwarding had to
be made on the basis of L2 and L3 headers alone.
This commit improves the situation significantly. It is still not possible
to match on L4 headers in fragments with nonzero offset, because that
information is simply not present in such fragments, but this commit adds
the ability to match on L4 headers for fragments with zero offset. This
means that it becomes possible to implement ACLs that drop such "first
fragments" on the basis of L4 headers. In practice, that effectively
blocks even fragmented traffic on an L4 basis, because the receiving IP
stack cannot reassemble a full packet when the first fragment is missing.
This commit works by adding a new "fragment type" to the kernel flow match
and making it available through OpenFlow as a new NXM field named
NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields
are always 0 for IP fragments, it adds a new OpenFlow fragment handling
mode that fills in the L4 fields for "first fragments". It also enhances
ovs-ofctl to allow users to configure this new fragment handling mode and
to parse the new field.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Bug #7557.
2011-10-19 21:33:44 -07:00
|
|
|
|
ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags));
|
|
|
|
|
flags &= ~OFPC_FRAG_MASK;
|
|
|
|
|
|
2012-01-13 17:54:04 -08:00
|
|
|
|
if (flags & OFPC_INVALID_TTL_TO_CONTROLLER) {
|
|
|
|
|
ds_put_format(string, " invalid_ttl_to_controller");
|
|
|
|
|
flags &= ~OFPC_INVALID_TTL_TO_CONTROLLER;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (flags) {
|
|
|
|
|
ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ds_put_format(string, " miss_send_len=%"PRIu16"\n", ntohs(osc->miss_send_len));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void print_wild(struct ds *string, const char *leader, int is_wild,
|
2010-08-30 00:24:53 -07:00
|
|
|
|
int verbosity, const char *format, ...)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
__attribute__((format(printf, 5, 6)));
|
|
|
|
|
|
|
|
|
|
static void print_wild(struct ds *string, const char *leader, int is_wild,
|
2010-08-30 00:24:53 -07:00
|
|
|
|
int verbosity, const char *format, ...)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
if (is_wild && verbosity < 2) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ds_put_cstr(string, leader);
|
|
|
|
|
if (!is_wild) {
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
ds_put_format_valist(string, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_char(string, '*');
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, ',');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-03-29 14:42:20 -07:00
|
|
|
|
print_ip_netmask(struct ds *string, const char *leader, ovs_be32 ip,
|
2009-07-08 13:19:16 -07:00
|
|
|
|
uint32_t wild_bits, int verbosity)
|
|
|
|
|
{
|
|
|
|
|
if (wild_bits >= 32 && verbosity < 2) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ds_put_cstr(string, leader);
|
|
|
|
|
if (wild_bits < 32) {
|
|
|
|
|
ds_put_format(string, IP_FMT, IP_ARGS(&ip));
|
|
|
|
|
if (wild_bits) {
|
|
|
|
|
ds_put_format(string, "/%d", 32 - wild_bits);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_char(string, '*');
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, ',');
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-14 13:03:57 -07:00
|
|
|
|
void
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ofp_print_match(struct ds *f, const struct ofp_match *om, int verbosity)
|
|
|
|
|
{
|
|
|
|
|
char *s = ofp_match_to_string(om, verbosity);
|
|
|
|
|
ds_put_cstr(f, s);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
ofp_match_to_string(const struct ofp_match *om, int verbosity)
|
|
|
|
|
{
|
|
|
|
|
struct ds f = DS_EMPTY_INITIALIZER;
|
|
|
|
|
uint32_t w = ntohl(om->wildcards);
|
|
|
|
|
bool skip_type = false;
|
|
|
|
|
bool skip_proto = false;
|
|
|
|
|
|
|
|
|
|
if (!(w & OFPFW_DL_TYPE)) {
|
|
|
|
|
skip_type = true;
|
|
|
|
|
if (om->dl_type == htons(ETH_TYPE_IP)) {
|
|
|
|
|
if (!(w & OFPFW_NW_PROTO)) {
|
|
|
|
|
skip_proto = true;
|
2011-02-02 11:33:20 -08:00
|
|
|
|
if (om->nw_proto == IPPROTO_ICMP) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(&f, "icmp,");
|
2011-02-02 11:33:20 -08:00
|
|
|
|
} else if (om->nw_proto == IPPROTO_TCP) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(&f, "tcp,");
|
2011-02-02 11:33:20 -08:00
|
|
|
|
} else if (om->nw_proto == IPPROTO_UDP) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(&f, "udp,");
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_cstr(&f, "ip,");
|
|
|
|
|
skip_proto = false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_cstr(&f, "ip,");
|
|
|
|
|
}
|
|
|
|
|
} else if (om->dl_type == htons(ETH_TYPE_ARP)) {
|
|
|
|
|
ds_put_cstr(&f, "arp,");
|
|
|
|
|
} else {
|
|
|
|
|
skip_type = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
print_wild(&f, "in_port=", w & OFPFW_IN_PORT, verbosity,
|
|
|
|
|
"%d", ntohs(om->in_port));
|
|
|
|
|
print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
|
2010-04-10 01:20:23 -07:00
|
|
|
|
"%d", ntohs(om->dl_vlan));
|
2009-11-11 14:59:49 -08:00
|
|
|
|
print_wild(&f, "dl_vlan_pcp=", w & OFPFW_DL_VLAN_PCP, verbosity,
|
|
|
|
|
"%d", om->dl_vlan_pcp);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
print_wild(&f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
|
|
|
|
|
ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
|
|
|
|
|
print_wild(&f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
|
|
|
|
|
ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
|
|
|
|
|
if (!skip_type) {
|
|
|
|
|
print_wild(&f, "dl_type=", w & OFPFW_DL_TYPE, verbosity,
|
|
|
|
|
"0x%04x", ntohs(om->dl_type));
|
|
|
|
|
}
|
|
|
|
|
print_ip_netmask(&f, "nw_src=", om->nw_src,
|
|
|
|
|
(w & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT, verbosity);
|
|
|
|
|
print_ip_netmask(&f, "nw_dst=", om->nw_dst,
|
|
|
|
|
(w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity);
|
|
|
|
|
if (!skip_proto) {
|
2009-11-09 16:43:47 -08:00
|
|
|
|
if (om->dl_type == htons(ETH_TYPE_ARP)) {
|
2011-06-24 14:36:24 -07:00
|
|
|
|
print_wild(&f, "arp_op=", w & OFPFW_NW_PROTO, verbosity,
|
2009-11-09 16:43:47 -08:00
|
|
|
|
"%u", om->nw_proto);
|
|
|
|
|
} else {
|
|
|
|
|
print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
|
|
|
|
|
"%u", om->nw_proto);
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2010-11-05 10:47:50 +09:00
|
|
|
|
print_wild(&f, "nw_tos=", w & OFPFW_NW_TOS, verbosity,
|
|
|
|
|
"%u", om->nw_tos);
|
2011-02-02 11:33:20 -08:00
|
|
|
|
if (om->nw_proto == IPPROTO_ICMP) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity,
|
2011-10-05 11:06:12 -07:00
|
|
|
|
"%d", ntohs(om->tp_src));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
print_wild(&f, "icmp_code=", w & OFPFW_ICMP_CODE, verbosity,
|
2011-10-05 11:06:12 -07:00
|
|
|
|
"%d", ntohs(om->tp_dst));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
} else {
|
|
|
|
|
print_wild(&f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
|
|
|
|
|
"%d", ntohs(om->tp_src));
|
|
|
|
|
print_wild(&f, "tp_dst=", w & OFPFW_TP_DST, verbosity,
|
|
|
|
|
"%d", ntohs(om->tp_dst));
|
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (ds_last(&f) == ',') {
|
|
|
|
|
f.length--;
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
return ds_cstr(&f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
|
|
|
|
|
enum ofputil_msg_code code, int verbosity)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-08-08 14:46:38 -07:00
|
|
|
|
struct ofputil_flow_mod fm;
|
2010-12-14 11:36:04 -08:00
|
|
|
|
bool need_priority;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
enum ofperr error;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-05-12 12:05:42 -07:00
|
|
|
|
error = ofputil_decode_flow_mod(&fm, oh, true);
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ofp_print_error(s, error);
|
|
|
|
|
return;
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_char(s, ' ');
|
|
|
|
|
switch (fm.command) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
case OFPFC_ADD:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_cstr(s, "ADD");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
case OFPFC_MODIFY:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_cstr(s, "MOD");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
case OFPFC_MODIFY_STRICT:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_cstr(s, "MOD_STRICT");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
case OFPFC_DELETE:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_cstr(s, "DEL");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
case OFPFC_DELETE_STRICT:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_cstr(s, "DEL_STRICT");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_format(s, "cmd:%d", fm.command);
|
|
|
|
|
}
|
2011-05-12 09:58:01 -07:00
|
|
|
|
if (fm.table_id != 0) {
|
2011-06-08 12:36:53 -07:00
|
|
|
|
ds_put_format(s, " table:%d", fm.table_id);
|
2011-05-12 09:58:01 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
|
|
|
|
|
ds_put_char(s, ' ');
|
|
|
|
|
if (verbosity >= 3 && code == OFPUTIL_OFPT_FLOW_MOD) {
|
|
|
|
|
const struct ofp_flow_mod *ofm = (const struct ofp_flow_mod *) oh;
|
|
|
|
|
ofp_print_match(s, &ofm->match, verbosity);
|
2010-12-14 11:36:04 -08:00
|
|
|
|
|
|
|
|
|
/* ofp_print_match() doesn't print priority. */
|
|
|
|
|
need_priority = true;
|
2010-12-07 13:22:46 -08:00
|
|
|
|
} else if (verbosity >= 3 && code == OFPUTIL_NXT_FLOW_MOD) {
|
|
|
|
|
const struct nx_flow_mod *nfm = (const struct nx_flow_mod *) oh;
|
|
|
|
|
const void *nxm = nfm + 1;
|
2010-12-14 11:36:04 -08:00
|
|
|
|
char *nxm_s;
|
|
|
|
|
|
|
|
|
|
nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len));
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_cstr(s, nxm_s);
|
|
|
|
|
free(nxm_s);
|
2010-12-14 11:36:04 -08:00
|
|
|
|
|
|
|
|
|
/* nx_match_to_string() doesn't print priority. */
|
|
|
|
|
need_priority = true;
|
2010-12-07 13:22:46 -08:00
|
|
|
|
} else {
|
|
|
|
|
cls_rule_format(&fm.cr, s);
|
2010-12-14 11:36:04 -08:00
|
|
|
|
|
|
|
|
|
/* cls_rule_format() does print priority. */
|
|
|
|
|
need_priority = false;
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
|
|
|
|
|
if (ds_last(s) != ' ') {
|
|
|
|
|
ds_put_char(s, ' ');
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (fm.cookie != htonll(0)) {
|
|
|
|
|
ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.cookie));
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (fm.idle_timeout != OFP_FLOW_PERMANENT) {
|
|
|
|
|
ds_put_format(s, "idle:%"PRIu16" ", fm.idle_timeout);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
|
|
|
|
|
ds_put_format(s, "hard:%"PRIu16" ", fm.hard_timeout);
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-14 11:36:04 -08:00
|
|
|
|
if (fm.cr.priority != OFP_DEFAULT_PRIORITY && need_priority) {
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ds_put_format(s, "pri:%"PRIu16" ", fm.cr.priority);
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (fm.buffer_id != UINT32_MAX) {
|
|
|
|
|
ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (fm.flags != 0) {
|
2012-01-25 13:54:15 -08:00
|
|
|
|
uint16_t flags = fm.flags;
|
|
|
|
|
|
|
|
|
|
if (flags & OFPFF_SEND_FLOW_REM) {
|
|
|
|
|
ds_put_cstr(s, "send_flow_rem ");
|
|
|
|
|
}
|
|
|
|
|
if (flags & OFPFF_CHECK_OVERLAP) {
|
|
|
|
|
ds_put_cstr(s, "check_overlap ");
|
|
|
|
|
}
|
|
|
|
|
if (flags & OFPFF_EMERG) {
|
|
|
|
|
ds_put_cstr(s, "emerg ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flags &= ~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG);
|
|
|
|
|
if (flags) {
|
|
|
|
|
ds_put_format(s, "flags:0x%"PRIx16" ", flags);
|
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
}
|
|
|
|
|
|
2011-06-30 10:04:09 -07:00
|
|
|
|
ofp_print_actions(s, fm.actions, fm.n_actions);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 15:45:10 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
|
|
|
|
|
{
|
|
|
|
|
ds_put_format(string, "%u", sec);
|
|
|
|
|
if (nsec > 0) {
|
|
|
|
|
ds_put_format(string, ".%09u", nsec);
|
|
|
|
|
while (string->string[string->length - 1] == '0') {
|
|
|
|
|
string->length--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, 's');
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-09 14:06:35 -08:00
|
|
|
|
static const char *
|
|
|
|
|
ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason)
|
|
|
|
|
{
|
|
|
|
|
static char s[32];
|
|
|
|
|
|
|
|
|
|
switch (reason) {
|
|
|
|
|
case OFPRR_IDLE_TIMEOUT:
|
|
|
|
|
return "idle";
|
|
|
|
|
case OFPRR_HARD_TIMEOUT:
|
|
|
|
|
return "hard";
|
|
|
|
|
case OFPRR_DELETE:
|
|
|
|
|
return "delete";
|
|
|
|
|
default:
|
|
|
|
|
sprintf(s, "%d", (int) reason);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2010-12-09 10:31:49 -08:00
|
|
|
|
ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-09 10:31:49 -08:00
|
|
|
|
struct ofputil_flow_removed fr;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
enum ofperr error;
|
2010-12-09 10:31:49 -08:00
|
|
|
|
|
2011-04-26 09:42:18 -07:00
|
|
|
|
error = ofputil_decode_flow_removed(&fr, oh);
|
2010-12-09 10:31:49 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ofp_print_error(string, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-13 16:19:19 -08:00
|
|
|
|
ds_put_char(string, ' ');
|
2010-12-09 10:31:49 -08:00
|
|
|
|
cls_rule_format(&fr.rule, string);
|
|
|
|
|
|
2012-02-09 14:06:35 -08:00
|
|
|
|
ds_put_format(string, " reason=%s",
|
|
|
|
|
ofp_flow_removed_reason_to_string(fr.reason));
|
2010-10-01 13:05:59 -07:00
|
|
|
|
|
2010-12-09 10:31:49 -08:00
|
|
|
|
if (fr.cookie != htonll(0)) {
|
|
|
|
|
ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
|
2010-10-01 13:05:59 -07:00
|
|
|
|
}
|
2010-12-07 15:45:10 -08:00
|
|
|
|
ds_put_cstr(string, " duration");
|
2010-12-09 10:31:49 -08:00
|
|
|
|
ofp_print_duration(string, fr.duration_sec, fr.duration_nsec);
|
2010-12-07 15:45:10 -08:00
|
|
|
|
ds_put_format(string, " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n",
|
2010-12-09 10:31:49 -08:00
|
|
|
|
fr.idle_timeout, fr.packet_count, fr.byte_count);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
ds_put_format(string, "port: %d: addr:"ETH_ADDR_FMT", config: %#x, mask:%#x\n",
|
2010-08-30 00:24:53 -07:00
|
|
|
|
ntohs(opm->port_no), ETH_ADDR_ARGS(opm->hw_addr),
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ntohl(opm->config), ntohl(opm->mask));
|
|
|
|
|
ds_put_format(string, " advertise: ");
|
|
|
|
|
if (opm->advertise) {
|
|
|
|
|
ofp_print_port_features(string, ntohl(opm->advertise));
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_format(string, "UNCHANGED\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:22:46 -08:00
|
|
|
|
static void
|
2012-01-12 15:48:19 -08:00
|
|
|
|
ofp_print_error(struct ds *string, enum ofperr error)
|
2010-12-07 13:22:46 -08:00
|
|
|
|
{
|
|
|
|
|
if (string->length) {
|
|
|
|
|
ds_put_char(string, ' ');
|
|
|
|
|
}
|
2012-01-12 15:48:19 -08:00
|
|
|
|
ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
|
2010-12-07 21:57:09 -08:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-06 10:20:20 -08:00
|
|
|
|
size_t len = ntohs(oem->header.length);
|
2011-01-12 13:42:50 -08:00
|
|
|
|
size_t payload_ofs, payload_len;
|
|
|
|
|
const void *payload;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
enum ofperr error;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
char *s;
|
|
|
|
|
|
2012-01-12 15:48:19 -08:00
|
|
|
|
error = ofperr_decode_msg(&oem->header, &payload_ofs);
|
|
|
|
|
if (!error) {
|
|
|
|
|
ds_put_cstr(string, "***decode error***");
|
2011-01-12 13:42:50 -08:00
|
|
|
|
ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
|
|
|
|
|
return;
|
2010-12-07 21:57:09 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-01-12 15:48:19 -08:00
|
|
|
|
ds_put_format(string, " %s\n", ofperr_get_name(error));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-01-12 13:42:50 -08:00
|
|
|
|
payload = (const uint8_t *) oem + payload_ofs;
|
|
|
|
|
payload_len = len - payload_ofs;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
|
2011-01-12 13:42:50 -08:00
|
|
|
|
ds_put_printable(string, payload, payload_len);
|
2012-01-12 15:48:19 -08:00
|
|
|
|
} else {
|
2011-01-12 13:42:50 -08:00
|
|
|
|
s = ofp_to_string(payload, payload_len, 1);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(string, s);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
if (ops->reason == OFPPR_ADD) {
|
|
|
|
|
ds_put_format(string, " ADD:");
|
|
|
|
|
} else if (ops->reason == OFPPR_DELETE) {
|
|
|
|
|
ds_put_format(string, " DEL:");
|
|
|
|
|
} else if (ops->reason == OFPPR_MODIFY) {
|
|
|
|
|
ds_put_format(string, " MOD:");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ofp_print_phy_port(string, &ops->desc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-13 16:19:19 -08:00
|
|
|
|
ds_put_char(string, '\n');
|
2010-08-30 00:24:53 -07:00
|
|
|
|
ds_put_format(string, "Manufacturer: %.*s\n",
|
2010-01-22 15:12:34 -08:00
|
|
|
|
(int) sizeof ods->mfr_desc, ods->mfr_desc);
|
|
|
|
|
ds_put_format(string, "Hardware: %.*s\n",
|
|
|
|
|
(int) sizeof ods->hw_desc, ods->hw_desc);
|
|
|
|
|
ds_put_format(string, "Software: %.*s\n",
|
|
|
|
|
(int) sizeof ods->sw_desc, ods->sw_desc);
|
|
|
|
|
ds_put_format(string, "Serial Num: %.*s\n",
|
|
|
|
|
(int) sizeof ods->serial_num, ods->serial_num);
|
|
|
|
|
ds_put_format(string, "DP Description: %.*s\n",
|
|
|
|
|
(int) sizeof ods->dp_desc, ods->dp_desc);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-05-26 16:02:56 -07:00
|
|
|
|
ofp_print_flow_stats_request(struct ds *string,
|
|
|
|
|
const struct ofp_stats_msg *osm)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-08-08 14:48:48 -07:00
|
|
|
|
struct ofputil_flow_stats_request fsr;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
enum ofperr error;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-05-26 16:02:56 -07:00
|
|
|
|
error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
|
2010-12-07 14:52:26 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ofp_print_error(string, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fsr.table_id != 0xff) {
|
2011-06-08 12:36:53 -07:00
|
|
|
|
ds_put_format(string, " table=%"PRIu8, fsr.table_id);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 14:52:26 -08:00
|
|
|
|
if (fsr.out_port != OFPP_NONE) {
|
|
|
|
|
ds_put_cstr(string, " out_port=");
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(fsr.out_port, string);
|
2010-12-07 14:52:26 -08:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-24 16:58:40 -08:00
|
|
|
|
/* A flow stats request doesn't include a priority, but cls_rule_format()
|
|
|
|
|
* will print one unless it is OFP_DEFAULT_PRIORITY. */
|
|
|
|
|
fsr.match.priority = OFP_DEFAULT_PRIORITY;
|
|
|
|
|
|
2010-12-07 14:52:26 -08:00
|
|
|
|
ds_put_char(string, ' ');
|
|
|
|
|
cls_rule_format(&fsr.match, string);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-03-10 15:02:05 -08:00
|
|
|
|
ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-03-10 15:02:05 -08:00
|
|
|
|
struct ofpbuf b;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2011-03-10 15:02:05 -08:00
|
|
|
|
ofpbuf_use_const(&b, oh, ntohs(oh->length));
|
|
|
|
|
for (;;) {
|
|
|
|
|
struct ofputil_flow_stats fs;
|
|
|
|
|
int retval;
|
2010-12-08 12:05:20 -08:00
|
|
|
|
|
2012-02-07 10:13:52 -08:00
|
|
|
|
retval = ofputil_decode_flow_stats_reply(&fs, &b, true);
|
2011-03-10 15:02:05 -08:00
|
|
|
|
if (retval) {
|
|
|
|
|
if (retval != EOF) {
|
|
|
|
|
ds_put_cstr(string, " ***parse error***");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-09 12:31:31 -08:00
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
|
2010-12-07 15:45:10 -08:00
|
|
|
|
ds_put_format(string, " cookie=0x%"PRIx64", duration=",
|
2011-03-10 15:02:05 -08:00
|
|
|
|
ntohll(fs.cookie));
|
|
|
|
|
ofp_print_duration(string, fs.duration_sec, fs.duration_nsec);
|
2011-06-08 12:36:53 -07:00
|
|
|
|
ds_put_format(string, ", table=%"PRIu8", ", fs.table_id);
|
2011-03-10 15:02:05 -08:00
|
|
|
|
ds_put_format(string, "n_packets=%"PRIu64", ", fs.packet_count);
|
|
|
|
|
ds_put_format(string, "n_bytes=%"PRIu64", ", fs.byte_count);
|
|
|
|
|
if (fs.idle_timeout != OFP_FLOW_PERMANENT) {
|
|
|
|
|
ds_put_format(string, "idle_timeout=%"PRIu16",", fs.idle_timeout);
|
2010-12-07 14:21:38 -08:00
|
|
|
|
}
|
2011-03-10 15:02:05 -08:00
|
|
|
|
if (fs.hard_timeout != OFP_FLOW_PERMANENT) {
|
|
|
|
|
ds_put_format(string, "hard_timeout=%"PRIu16",", fs.hard_timeout);
|
2010-12-07 14:21:38 -08:00
|
|
|
|
}
|
2012-02-07 10:13:52 -08:00
|
|
|
|
if (fs.idle_age >= 0) {
|
|
|
|
|
ds_put_format(string, "idle_age=%d,", fs.idle_age);
|
|
|
|
|
}
|
|
|
|
|
if (fs.hard_age >= 0 && fs.hard_age != fs.duration_sec) {
|
|
|
|
|
ds_put_format(string, "hard_age=%d,", fs.hard_age);
|
|
|
|
|
}
|
2010-12-07 14:21:38 -08:00
|
|
|
|
|
2011-03-10 15:02:05 -08:00
|
|
|
|
cls_rule_format(&fs.rule, string);
|
2011-09-22 14:35:05 -07:00
|
|
|
|
if (string->string[string->length - 1] != ' ') {
|
|
|
|
|
ds_put_char(string, ' ');
|
|
|
|
|
}
|
2011-06-30 10:04:09 -07:00
|
|
|
|
ofp_print_actions(string, fs.actions, fs.n_actions);
|
2010-12-07 14:21:38 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_aggregate_reply(struct ds *string,
|
|
|
|
|
const struct ofp_aggregate_stats_reply *asr)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-01-18 11:50:56 -08:00
|
|
|
|
ds_put_format(string, " packet_count=%"PRIu64,
|
|
|
|
|
ntohll(get_32aligned_be64(&asr->packet_count)));
|
|
|
|
|
ds_put_format(string, " byte_count=%"PRIu64,
|
|
|
|
|
ntohll(get_32aligned_be64(&asr->byte_count)));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 15:07:54 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxst_aggregate_reply(struct ds *string,
|
|
|
|
|
const struct nx_aggregate_stats_reply *nasr)
|
|
|
|
|
{
|
2011-05-24 13:30:04 -07:00
|
|
|
|
ds_put_format(string, " packet_count=%"PRIu64, ntohll(nasr->packet_count));
|
|
|
|
|
ds_put_format(string, " byte_count=%"PRIu64, ntohll(nasr->byte_count));
|
|
|
|
|
ds_put_format(string, " flow_count=%"PRIu32, ntohl(nasr->flow_count));
|
2010-12-07 15:07:54 -08:00
|
|
|
|
}
|
|
|
|
|
|
2010-08-30 00:24:53 -07:00
|
|
|
|
static void print_port_stat(struct ds *string, const char *leader,
|
2011-01-18 11:50:56 -08:00
|
|
|
|
const ovs_32aligned_be64 *statp, int more)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-01-18 11:50:56 -08:00
|
|
|
|
uint64_t stat = ntohll(get_32aligned_be64(statp));
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(string, leader);
|
2011-01-18 11:50:56 -08:00
|
|
|
|
if (stat != UINT64_MAX) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, "%"PRIu64, stat);
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_char(string, '?');
|
|
|
|
|
}
|
|
|
|
|
if (more) {
|
|
|
|
|
ds_put_cstr(string, ", ");
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_cstr(string, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-19 22:35:18 -08:00
|
|
|
|
static void
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_port_request(struct ds *string,
|
|
|
|
|
const struct ofp_port_stats_request *psr)
|
2010-01-19 22:35:18 -08:00
|
|
|
|
{
|
2010-12-13 16:19:19 -08:00
|
|
|
|
ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no));
|
2010-01-19 22:35:18 -08:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
|
|
|
|
|
int verbosity)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-06 10:20:20 -08:00
|
|
|
|
const struct ofp_port_stats *ps = ofputil_stats_body(oh);
|
|
|
|
|
size_t n = ofputil_stats_body_len(oh) / sizeof *ps;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, " %zu ports\n", n);
|
|
|
|
|
if (verbosity < 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; n--; ps++) {
|
|
|
|
|
ds_put_format(string, " port %2"PRIu16": ", ntohs(ps->port_no));
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, "rx ");
|
2011-01-18 11:50:56 -08:00
|
|
|
|
print_port_stat(string, "pkts=", &ps->rx_packets, 1);
|
|
|
|
|
print_port_stat(string, "bytes=", &ps->rx_bytes, 1);
|
|
|
|
|
print_port_stat(string, "drop=", &ps->rx_dropped, 1);
|
|
|
|
|
print_port_stat(string, "errs=", &ps->rx_errors, 1);
|
|
|
|
|
print_port_stat(string, "frame=", &ps->rx_frame_err, 1);
|
|
|
|
|
print_port_stat(string, "over=", &ps->rx_over_err, 1);
|
|
|
|
|
print_port_stat(string, "crc=", &ps->rx_crc_err, 0);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " tx ");
|
2011-01-18 11:50:56 -08:00
|
|
|
|
print_port_stat(string, "pkts=", &ps->tx_packets, 1);
|
|
|
|
|
print_port_stat(string, "bytes=", &ps->tx_bytes, 1);
|
|
|
|
|
print_port_stat(string, "drop=", &ps->tx_dropped, 1);
|
|
|
|
|
print_port_stat(string, "errs=", &ps->tx_errors, 1);
|
|
|
|
|
print_port_stat(string, "coll=", &ps->collisions, 0);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
|
|
|
|
|
int verbosity)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-06 10:20:20 -08:00
|
|
|
|
const struct ofp_table_stats *ts = ofputil_stats_body(oh);
|
|
|
|
|
size_t n = ofputil_stats_body_len(oh) / sizeof *ts;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, " %zu tables\n", n);
|
|
|
|
|
if (verbosity < 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; n--; ts++) {
|
|
|
|
|
char name[OFP_MAX_TABLE_NAME_LEN + 1];
|
util: Don't read over 'size - 1' bytes of source string in ovs_strlcpy().
The blind replacement of strncpy() by ovs_strlcpy() is risky because
strncpy() never reads more bytes from its source string than necessary to
write its destination string, but ovs_strlcpy() and the OpenBSD function
that inspired it both read the entire source string. This avoids that
problem.
Given that change, we can use ovs_strlcpy() in a few more places, and
this commit does that too.
Coverity #10697,10696,10695,10694,10693,10692,10691,10690.
2011-02-22 10:41:15 -08:00
|
|
|
|
ovs_strlcpy(name, ts->name, sizeof name);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
ds_put_format(string, " %d: %-8s: ", ts->table_id, name);
|
|
|
|
|
ds_put_format(string, "wild=0x%05"PRIx32", ", ntohl(ts->wildcards));
|
|
|
|
|
ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries));
|
|
|
|
|
ds_put_format(string, "active=%"PRIu32"\n", ntohl(ts->active_count));
|
|
|
|
|
ds_put_cstr(string, " ");
|
2010-08-30 00:24:53 -07:00
|
|
|
|
ds_put_format(string, "lookup=%"PRIu64", ",
|
2011-01-18 11:50:56 -08:00
|
|
|
|
ntohll(get_32aligned_be64(&ts->lookup_count)));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_format(string, "matched=%"PRIu64"\n",
|
2011-01-18 11:50:56 -08:00
|
|
|
|
ntohll(get_32aligned_be64(&ts->matched_count)));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-16 15:36:57 -07:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_queue_name(struct ds *string, uint32_t queue_id)
|
|
|
|
|
{
|
|
|
|
|
if (queue_id == OFPQ_ALL) {
|
|
|
|
|
ds_put_cstr(string, "ALL");
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_format(string, "%"PRIu32, queue_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_queue_request(struct ds *string,
|
|
|
|
|
const struct ofp_queue_stats_request *qsr)
|
2010-09-16 15:36:57 -07:00
|
|
|
|
{
|
|
|
|
|
ds_put_cstr(string, "port=");
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(ntohs(qsr->port_no), string);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " queue=");
|
|
|
|
|
ofp_print_queue_name(string, ntohl(qsr->queue_id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
|
|
|
|
|
int verbosity)
|
2010-09-16 15:36:57 -07:00
|
|
|
|
{
|
2010-12-06 10:20:20 -08:00
|
|
|
|
const struct ofp_queue_stats *qs = ofputil_stats_body(oh);
|
|
|
|
|
size_t n = ofputil_stats_body_len(oh) / sizeof *qs;
|
2010-09-16 15:36:57 -07:00
|
|
|
|
ds_put_format(string, " %zu queues\n", n);
|
|
|
|
|
if (verbosity < 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; n--; qs++) {
|
|
|
|
|
ds_put_cstr(string, " port ");
|
2011-08-16 15:26:18 -07:00
|
|
|
|
ofputil_format_port(ntohs(qs->port_no), string);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
ds_put_cstr(string, " queue ");
|
|
|
|
|
ofp_print_queue_name(string, ntohl(qs->queue_id));
|
|
|
|
|
ds_put_cstr(string, ": ");
|
|
|
|
|
|
2011-01-18 11:50:56 -08:00
|
|
|
|
print_port_stat(string, "bytes=", &qs->tx_bytes, 1);
|
|
|
|
|
print_port_stat(string, "pkts=", &qs->tx_packets, 1);
|
|
|
|
|
print_port_stat(string, "errors=", &qs->tx_errors, 0);
|
2010-09-16 15:36:57 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_stats_request(struct ds *string, const struct ofp_header *oh)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-05-26 09:30:25 -07:00
|
|
|
|
const struct ofp_stats_msg *srq = (const struct ofp_stats_msg *) oh;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
if (srq->flags) {
|
|
|
|
|
ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
|
|
|
|
|
ntohs(srq->flags));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_stats_reply(struct ds *string, const struct ofp_header *oh)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-05-26 09:30:25 -07:00
|
|
|
|
const struct ofp_stats_msg *srp = (const struct ofp_stats_msg *) oh;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
if (srp->flags) {
|
2009-07-08 13:19:16 -07:00
|
|
|
|
uint16_t flags = ntohs(srp->flags);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " flags=");
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (flags & OFPSF_REPLY_MORE) {
|
|
|
|
|
ds_put_cstr(string, "[more]");
|
|
|
|
|
flags &= ~OFPSF_REPLY_MORE;
|
|
|
|
|
}
|
|
|
|
|
if (flags) {
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]",
|
|
|
|
|
flags);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2010-12-06 10:20:20 -08:00
|
|
|
|
size_t len = ntohs(oh->length);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ds_put_format(string, " %zu bytes of payload\n", len - sizeof *oh);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (verbosity > 1) {
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 14:36:18 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxt_role_message(struct ds *string,
|
|
|
|
|
const struct nx_role_request *nrr)
|
|
|
|
|
{
|
|
|
|
|
unsigned int role = ntohl(nrr->role);
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " role=");
|
|
|
|
|
if (role == NX_ROLE_OTHER) {
|
|
|
|
|
ds_put_cstr(string, "other");
|
|
|
|
|
} else if (role == NX_ROLE_MASTER) {
|
|
|
|
|
ds_put_cstr(string, "master");
|
|
|
|
|
} else if (role == NX_ROLE_SLAVE) {
|
|
|
|
|
ds_put_cstr(string, "slave");
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_format(string, "%u", role);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-12 09:58:01 -07:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxt_flow_mod_table_id(struct ds *string,
|
2012-01-12 11:35:50 -08:00
|
|
|
|
const struct nx_flow_mod_table_id *nfmti)
|
2011-05-12 09:58:01 -07:00
|
|
|
|
{
|
|
|
|
|
ds_put_format(string, " %s", nfmti->set ? "enable" : "disable");
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:22:46 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxt_set_flow_format(struct ds *string,
|
2012-01-12 11:35:50 -08:00
|
|
|
|
const struct nx_set_flow_format *nsff)
|
2010-12-07 13:22:46 -08:00
|
|
|
|
{
|
|
|
|
|
uint32_t format = ntohl(nsff->format);
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " format=");
|
|
|
|
|
if (ofputil_flow_format_is_valid(format)) {
|
|
|
|
|
ds_put_cstr(string, ofputil_flow_format_to_string(format));
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_format(string, "%"PRIu32, format);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-09 15:48:26 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxt_set_packet_in_format(struct ds *string,
|
2012-01-12 11:35:50 -08:00
|
|
|
|
const struct nx_set_packet_in_format *nspf)
|
2011-12-09 15:48:26 -08:00
|
|
|
|
{
|
|
|
|
|
uint32_t format = ntohl(nspf->format);
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " format=");
|
|
|
|
|
if (ofputil_packet_in_format_is_valid(format)) {
|
|
|
|
|
ds_put_cstr(string, ofputil_packet_in_format_to_string(format));
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_format(string, "%"PRIu32, format);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-09 14:06:35 -08:00
|
|
|
|
static const char *
|
|
|
|
|
ofp_port_reason_to_string(enum ofp_port_reason reason)
|
|
|
|
|
{
|
|
|
|
|
static char s[32];
|
|
|
|
|
|
|
|
|
|
switch (reason) {
|
|
|
|
|
case OFPPR_ADD:
|
|
|
|
|
return "add";
|
|
|
|
|
|
|
|
|
|
case OFPPR_DELETE:
|
|
|
|
|
return "delete";
|
|
|
|
|
|
|
|
|
|
case OFPPR_MODIFY:
|
|
|
|
|
return "modify";
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
sprintf(s, "%d", (int) reason);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxt_set_async_config(struct ds *string,
|
|
|
|
|
const struct nx_async_config *nac)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " PACKET_IN:");
|
|
|
|
|
for (j = 0; j < 32; j++) {
|
|
|
|
|
if (nac->packet_in_mask[i] & htonl(1u << j)) {
|
|
|
|
|
ds_put_format(string, " %s",
|
2012-02-07 14:46:34 -08:00
|
|
|
|
ofputil_packet_in_reason_to_string(j));
|
2012-02-09 14:06:35 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!nac->packet_in_mask[i]) {
|
|
|
|
|
ds_put_cstr(string, " (off)");
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " PORT_STATUS:");
|
|
|
|
|
for (j = 0; j < 32; j++) {
|
|
|
|
|
if (nac->port_status_mask[i] & htonl(1u << j)) {
|
|
|
|
|
ds_put_format(string, " %s", ofp_port_reason_to_string(j));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!nac->port_status_mask[i]) {
|
|
|
|
|
ds_put_cstr(string, " (off)");
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
|
|
|
|
|
ds_put_cstr(string, " FLOW_REMOVED:");
|
|
|
|
|
for (j = 0; j < 32; j++) {
|
|
|
|
|
if (nac->flow_removed_mask[i] & htonl(1u << j)) {
|
|
|
|
|
ds_put_format(string, " %s",
|
|
|
|
|
ofp_flow_removed_reason_to_string(j));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!nac->flow_removed_mask[i]) {
|
|
|
|
|
ds_put_cstr(string, " (off)");
|
|
|
|
|
}
|
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-09 14:17:33 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_print_nxt_set_controller_id(struct ds *string,
|
|
|
|
|
const struct nx_controller_id *nci)
|
|
|
|
|
{
|
|
|
|
|
ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
static void
|
|
|
|
|
ofp_to_string__(const struct ofp_header *oh,
|
|
|
|
|
const struct ofputil_msg_type *type, struct ds *string,
|
|
|
|
|
int verbosity)
|
|
|
|
|
{
|
2010-12-07 13:22:46 -08:00
|
|
|
|
enum ofputil_msg_code code;
|
2010-12-06 10:20:20 -08:00
|
|
|
|
const void *msg = oh;
|
|
|
|
|
|
|
|
|
|
ds_put_format(string, "%s (xid=0x%"PRIx32"):",
|
|
|
|
|
ofputil_msg_type_name(type), ntohl(oh->xid));
|
|
|
|
|
|
2010-12-07 13:22:46 -08:00
|
|
|
|
code = ofputil_msg_type_code(type);
|
|
|
|
|
switch (code) {
|
2011-06-24 13:58:08 -07:00
|
|
|
|
case OFPUTIL_MSG_INVALID:
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_HELLO:
|
2011-01-12 13:42:50 -08:00
|
|
|
|
ds_put_char(string, '\n');
|
|
|
|
|
ds_put_hex_dump(string, oh + 1, ntohs(oh->length) - sizeof *oh,
|
|
|
|
|
0, true);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_ERROR:
|
|
|
|
|
ofp_print_error_msg(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_ECHO_REQUEST:
|
|
|
|
|
case OFPUTIL_OFPT_ECHO_REPLY:
|
|
|
|
|
ofp_print_echo(string, oh, verbosity);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_FEATURES_REQUEST:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_FEATURES_REPLY:
|
|
|
|
|
ofp_print_switch_features(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_GET_CONFIG_REPLY:
|
|
|
|
|
case OFPUTIL_OFPT_SET_CONFIG:
|
|
|
|
|
ofp_print_switch_config(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_PACKET_IN:
|
2011-12-09 15:48:26 -08:00
|
|
|
|
case OFPUTIL_NXT_PACKET_IN:
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_packet_in(string, msg, verbosity);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_FLOW_REMOVED:
|
2010-12-09 10:31:49 -08:00
|
|
|
|
case OFPUTIL_NXT_FLOW_REMOVED:
|
|
|
|
|
ofp_print_flow_removed(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_PORT_STATUS:
|
|
|
|
|
ofp_print_port_status(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_PACKET_OUT:
|
|
|
|
|
ofp_print_packet_out(string, msg, verbosity);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_FLOW_MOD:
|
2012-02-07 14:47:27 -08:00
|
|
|
|
case OFPUTIL_NXT_FLOW_MOD:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ofp_print_flow_mod(string, msg, code, verbosity);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_PORT_MOD:
|
|
|
|
|
ofp_print_port_mod(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_BARRIER_REQUEST:
|
|
|
|
|
case OFPUTIL_OFPT_BARRIER_REPLY:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
|
|
|
|
|
case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
|
|
|
|
|
/* XXX */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_DESC_REQUEST:
|
|
|
|
|
ofp_print_stats_request(string, oh);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_FLOW_REQUEST:
|
2010-12-07 14:52:26 -08:00
|
|
|
|
case OFPUTIL_NXST_FLOW_REQUEST:
|
2010-12-06 10:20:20 -08:00
|
|
|
|
case OFPUTIL_OFPST_AGGREGATE_REQUEST:
|
2010-12-07 14:52:26 -08:00
|
|
|
|
case OFPUTIL_NXST_AGGREGATE_REQUEST:
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_stats_request(string, oh);
|
2011-05-26 16:02:56 -07:00
|
|
|
|
ofp_print_flow_stats_request(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_TABLE_REQUEST:
|
|
|
|
|
ofp_print_stats_request(string, oh);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_PORT_REQUEST:
|
|
|
|
|
ofp_print_stats_request(string, oh);
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_port_request(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_QUEUE_REQUEST:
|
|
|
|
|
ofp_print_stats_request(string, oh);
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_queue_request(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_DESC_REPLY:
|
|
|
|
|
ofp_print_stats_reply(string, oh);
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_desc_reply(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_FLOW_REPLY:
|
2011-03-10 15:02:05 -08:00
|
|
|
|
case OFPUTIL_NXST_FLOW_REPLY:
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ofp_print_stats_reply(string, oh);
|
2011-03-10 15:02:05 -08:00
|
|
|
|
ofp_print_flow_stats_reply(string, oh);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_QUEUE_REPLY:
|
|
|
|
|
ofp_print_stats_reply(string, oh);
|
|
|
|
|
ofp_print_ofpst_queue_reply(string, oh, verbosity);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_PORT_REPLY:
|
|
|
|
|
ofp_print_stats_reply(string, oh);
|
|
|
|
|
ofp_print_ofpst_port_reply(string, oh, verbosity);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_TABLE_REPLY:
|
|
|
|
|
ofp_print_stats_reply(string, oh);
|
|
|
|
|
ofp_print_ofpst_table_reply(string, oh, verbosity);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OFPUTIL_OFPST_AGGREGATE_REPLY:
|
|
|
|
|
ofp_print_stats_reply(string, oh);
|
2011-05-31 16:49:06 -07:00
|
|
|
|
ofp_print_ofpst_aggregate_reply(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
case OFPUTIL_NXT_ROLE_REQUEST:
|
|
|
|
|
case OFPUTIL_NXT_ROLE_REPLY:
|
2010-12-07 14:36:18 -08:00
|
|
|
|
ofp_print_nxt_role_message(string, msg);
|
2010-12-07 13:22:46 -08:00
|
|
|
|
break;
|
|
|
|
|
|
2011-05-12 09:58:01 -07:00
|
|
|
|
case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
|
|
|
|
|
ofp_print_nxt_flow_mod_table_id(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
case OFPUTIL_NXT_SET_FLOW_FORMAT:
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ofp_print_nxt_set_flow_format(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
2011-12-09 15:48:26 -08:00
|
|
|
|
case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
|
|
|
|
|
ofp_print_nxt_set_packet_in_format(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
2012-02-07 10:13:52 -08:00
|
|
|
|
case OFPUTIL_NXT_FLOW_AGE:
|
|
|
|
|
break;
|
|
|
|
|
|
2012-02-09 14:17:33 -08:00
|
|
|
|
case OFPUTIL_NXT_SET_CONTROLLER_ID:
|
|
|
|
|
ofp_print_nxt_set_controller_id(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
2012-02-09 14:06:35 -08:00
|
|
|
|
case OFPUTIL_NXT_SET_ASYNC_CONFIG:
|
|
|
|
|
ofp_print_nxt_set_async_config(string, msg);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-06 10:20:20 -08:00
|
|
|
|
case OFPUTIL_NXST_AGGREGATE_REPLY:
|
2010-12-07 15:07:54 -08:00
|
|
|
|
ofp_print_stats_reply(string, oh);
|
2010-12-09 10:31:49 -08:00
|
|
|
|
ofp_print_nxst_aggregate_reply(string, msg);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
break;
|
2009-11-13 12:41:57 -08:00
|
|
|
|
}
|
2010-12-06 10:20:20 -08:00
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
|
|
|
|
/* Composes and returns a string representing the OpenFlow packet of 'len'
|
|
|
|
|
* bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
|
|
|
|
|
* verbosity and higher numbers increase verbosity. The caller is responsible
|
|
|
|
|
* for freeing the string. */
|
|
|
|
|
char *
|
|
|
|
|
ofp_to_string(const void *oh_, size_t len, int verbosity)
|
|
|
|
|
{
|
|
|
|
|
struct ds string = DS_EMPTY_INITIALIZER;
|
|
|
|
|
const struct ofp_header *oh = oh_;
|
|
|
|
|
|
2010-12-13 16:27:20 -08:00
|
|
|
|
if (!len) {
|
|
|
|
|
ds_put_cstr(&string, "OpenFlow message is empty\n");
|
|
|
|
|
} else if (len < sizeof(struct ofp_header)) {
|
|
|
|
|
ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
|
|
|
|
|
len);
|
2010-12-06 10:20:20 -08:00
|
|
|
|
} else if (ntohs(oh->length) > len) {
|
|
|
|
|
ds_put_format(&string,
|
2010-12-13 16:27:20 -08:00
|
|
|
|
"(***truncated to %zu bytes from %"PRIu16"***)\n",
|
2010-12-06 10:20:20 -08:00
|
|
|
|
len, ntohs(oh->length));
|
|
|
|
|
} else if (ntohs(oh->length) < len) {
|
|
|
|
|
ds_put_format(&string,
|
|
|
|
|
"(***only uses %"PRIu16" bytes out of %zu***)\n",
|
|
|
|
|
ntohs(oh->length), len);
|
|
|
|
|
} else {
|
|
|
|
|
const struct ofputil_msg_type *type;
|
2012-01-12 15:48:19 -08:00
|
|
|
|
enum ofperr error;
|
2010-12-06 10:20:20 -08:00
|
|
|
|
|
|
|
|
|
error = ofputil_decode_msg_type(oh, &type);
|
|
|
|
|
if (!error) {
|
|
|
|
|
ofp_to_string__(oh, type, &string, verbosity);
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (verbosity >= 5) {
|
|
|
|
|
if (ds_last(&string) != '\n') {
|
|
|
|
|
ds_put_char(&string, '\n');
|
|
|
|
|
}
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ds_put_hex_dump(&string, oh, len, 0, true);
|
|
|
|
|
}
|
2010-12-07 13:22:46 -08:00
|
|
|
|
if (ds_last(&string) != '\n') {
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ds_put_char(&string, '\n');
|
|
|
|
|
}
|
|
|
|
|
return ds_steal_cstr(&string);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 13:22:46 -08:00
|
|
|
|
ofp_print_error(&string, error);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
2010-12-06 10:20:20 -08:00
|
|
|
|
ds_put_hex_dump(&string, oh, len, 0, true);
|
|
|
|
|
return ds_steal_cstr(&string);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-08-30 00:24:53 -07:00
|
|
|
|
print_and_free(FILE *stream, char *string)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
|
|
|
|
fputs(string, stream);
|
|
|
|
|
free(string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the
|
|
|
|
|
* given 'verbosity' level. 0 is a minimal amount of verbosity and higher
|
|
|
|
|
* numbers increase verbosity. */
|
|
|
|
|
void
|
|
|
|
|
ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
|
|
|
|
|
{
|
|
|
|
|
print_and_free(stream, ofp_to_string(oh, len, verbosity));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
|
2011-12-21 12:59:28 -08:00
|
|
|
|
* 'data' to 'stream'. */
|
2009-07-08 13:19:16 -07:00
|
|
|
|
void
|
2011-12-22 17:47:15 -08:00
|
|
|
|
ofp_print_packet(FILE *stream, const void *data, size_t len)
|
2009-07-08 13:19:16 -07:00
|
|
|
|
{
|
2011-12-22 17:47:15 -08:00
|
|
|
|
print_and_free(stream, ofp_packet_to_string(data, len));
|
2009-07-08 13:19:16 -07:00
|
|
|
|
}
|