X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-print.c;h=38e228c9de78f4481342b75ca3233cd9112e0e69;hb=9620f50ccce53b75c45949f3984029fa67241afe;hp=c8d7f95a158a5cbf7c2d3fed09971d9c5e0a6475;hpb=03fbdf8d9c80a5c2d517faecfa025c8b2ee505d3;p=sliver-openvswitch.git diff --git a/lib/ofp-print.c b/lib/ofp-print.c index c8d7f95a1..38e228c9d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,25 +62,24 @@ ofp_packet_to_string(const void *data, size_t len) const struct pkt_metadata md = PKT_METADATA_INITIALIZER(0); struct ofpbuf buf; struct flow flow; + size_t l4_size; ofpbuf_use_const(&buf, data, len); flow_extract(&buf, &md, &flow); flow_format(&ds, &flow); - 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)); - } else if (flow.nw_proto == IPPROTO_SCTP) { - struct sctp_header *sh = buf.l4; - ds_put_format(&ds, " sctp_csum:%"PRIx32, - ntohl(sh->sctp_csum)); - } + l4_size = ofpbuf_l4_size(&buf); + + if (flow.nw_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) { + struct tcp_header *th = ofpbuf_l4(&buf); + ds_put_format(&ds, " tcp_csum:%"PRIx16, ntohs(th->tcp_csum)); + } else if (flow.nw_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) { + struct udp_header *uh = ofpbuf_l4(&buf); + ds_put_format(&ds, " udp_csum:%"PRIx16, ntohs(uh->udp_csum)); + } else if (flow.nw_proto == IPPROTO_SCTP && l4_size >= SCTP_HEADER_LEN) { + struct sctp_header *sh = ofpbuf_l4(&buf); + ds_put_format(&ds, " sctp_csum:%"PRIx32, + ntohl(get_16aligned_be32(&sh->sctp_csum))); } ds_put_char(&ds, '\n'); @@ -540,6 +539,7 @@ ofp_print_switch_features(struct ds *string, const struct ofp_header *oh) case OFP12_VERSION: break; case OFP13_VERSION: + case OFP14_VERSION: return; /* no ports in ofp13_switch_features */ default: OVS_NOT_REACHED(); @@ -743,6 +743,12 @@ ofp_print_flow_flags(struct ds *s, enum ofputil_flow_mod_flags flags) if (flags & OFPUTIL_FF_NO_BYT_COUNTS) { ds_put_cstr(s, "no_byte_counts "); } + if (flags & OFPUTIL_FF_HIDDEN_FIELDS) { + ds_put_cstr(s, "allow_hidden_fields "); + } + if (flags & OFPUTIL_FF_NO_READONLY) { + ds_put_cstr(s, "no_readonly_table "); + } } static void @@ -1362,12 +1368,13 @@ ofp_print_error_msg(struct ds *string, const struct ofp_header *oh) ds_put_format(string, " %s\n", ofperr_get_name(error)); if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) { - ds_put_printable(string, payload.data, payload.size); + ds_put_printable(string, ofpbuf_data(&payload), ofpbuf_size(&payload)); } else { - s = ofp_to_string(payload.data, payload.size, 1); + s = ofp_to_string(ofpbuf_data(&payload), ofpbuf_size(&payload), 1); ds_put_cstr(string, s); free(s); } + ofpbuf_uninit(&payload); } static void @@ -1664,7 +1671,7 @@ ofp_print_ofpst_table_reply13(struct ds *string, const struct ofp_header *oh, ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - n = b.size / sizeof *ts; + n = ofpbuf_size(&b) / sizeof *ts; ds_put_format(string, " %"PRIuSIZE" tables\n", n); if (verbosity < 1) { return; @@ -1694,7 +1701,7 @@ ofp_print_ofpst_table_reply12(struct ds *string, const struct ofp_header *oh, ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - n = b.size / sizeof *ts; + n = ofpbuf_size(&b) / sizeof *ts; ds_put_format(string, " %"PRIuSIZE" tables\n", n); if (verbosity < 1) { return; @@ -1721,7 +1728,7 @@ ofp_print_ofpst_table_reply11(struct ds *string, const struct ofp_header *oh, ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - n = b.size / sizeof *ts; + n = ofpbuf_size(&b) / sizeof *ts; ds_put_format(string, " %"PRIuSIZE" tables\n", n); if (verbosity < 1) { return; @@ -1761,7 +1768,7 @@ ofp_print_ofpst_table_reply10(struct ds *string, const struct ofp_header *oh, ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - n = b.size / sizeof *ts; + n = ofpbuf_size(&b) / sizeof *ts; ds_put_format(string, " %"PRIuSIZE" tables\n", n); if (verbosity < 1) { return; @@ -1790,6 +1797,7 @@ ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh, int verbosity) { switch ((enum ofp_version)oh->version) { + case OFP14_VERSION: case OFP13_VERSION: ofp_print_ofpst_table_reply13(string, oh, verbosity); break; @@ -2287,6 +2295,9 @@ ofp_print_version(const struct ofp_header *oh, case OFP13_VERSION: ds_put_cstr(string, " (OF1.3)"); break; + case OFP14_VERSION: + ds_put_cstr(string, " (OF1.4)"); + break; default: ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version); break; @@ -2302,12 +2313,6 @@ ofp_header_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_version(oh, string); } -static void -ofp_print_not_implemented(struct ds *string) -{ - ds_put_cstr(string, "NOT IMPLEMENTED YET!\n"); -} - static void ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, struct list *p_buckets) @@ -2503,6 +2508,166 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) ofp_print_group(s, gm.group_id, gm.type, &gm.buckets); } +static const char * +ofp13_action_to_string(uint32_t bit) +{ + switch (bit) { +#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ + case 1u << ENUM: return NAME; +#include "ofp-util.def" + } + return NULL; +} + +static void +print_table_action_features(struct ds *s, + const struct ofputil_table_action_features *taf) +{ + ds_put_cstr(s, " actions: "); + ofp_print_bit_names(s, taf->actions, ofp13_action_to_string, ','); + ds_put_char(s, '\n'); + + ds_put_cstr(s, " supported on Set-Field: "); + if (taf->set_fields) { + int i; + + for (i = 0; i < MFF_N_IDS; i++) { + uint64_t bit = UINT64_C(1) << i; + + if (taf->set_fields & bit) { + ds_put_format(s, "%s,", mf_from_id(i)->name); + } + } + ds_chomp(s, ','); + } else { + ds_put_cstr(s, "none"); + } + ds_put_char(s, '\n'); +} + +static bool +table_action_features_equal(const struct ofputil_table_action_features *a, + const struct ofputil_table_action_features *b) +{ + return a->actions == b->actions && a->set_fields == b->set_fields; +} + +static void +print_table_instruction_features( + struct ds *s, const struct ofputil_table_instruction_features *tif) +{ + int start, end; + + ds_put_cstr(s, " next tables: "); + for (start = bitmap_scan(tif->next, 1, 0, 255); start < 255; + start = bitmap_scan(tif->next, 1, end, 255)) { + end = bitmap_scan(tif->next, 0, start + 1, 255); + if (end == start + 1) { + ds_put_format(s, "%d,", start); + } else { + ds_put_format(s, "%d-%d,", start, end - 1); + } + } + ds_chomp(s, ','); + if (ds_last(s) == ' ') { + ds_put_cstr(s, "none"); + } + ds_put_char(s, '\n'); + + ds_put_cstr(s, " instructions: "); + if (tif->instructions) { + int i; + + for (i = 0; i < 32; i++) { + if (tif->instructions & (1u << i)) { + ds_put_format(s, "%s,", ovs_instruction_name_from_type(i)); + } + } + ds_chomp(s, ','); + } else { + ds_put_cstr(s, "none"); + } + ds_put_char(s, '\n'); + + if (table_action_features_equal(&tif->write, &tif->apply)) { + ds_put_cstr(s, " Write-Actions and Apply-Actions features:\n"); + print_table_action_features(s, &tif->write); + } else { + ds_put_cstr(s, " Write-Actions features:\n"); + print_table_action_features(s, &tif->write); + ds_put_cstr(s, " Apply-Actions features:\n"); + print_table_action_features(s, &tif->apply); + } +} + +static bool +table_instruction_features_equal( + const struct ofputil_table_instruction_features *a, + const struct ofputil_table_instruction_features *b) +{ + return (bitmap_equal(a->next, b->next, 255) + && a->instructions == b->instructions + && table_action_features_equal(&a->write, &b->write) + && table_action_features_equal(&a->apply, &b->apply)); +} + +static void +ofp_print_table_features(struct ds *s, const struct ofp_header *oh) +{ + struct ofpbuf b; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + + for (;;) { + struct ofputil_table_features tf; + int retval; + int i; + + retval = ofputil_decode_table_features(&b, &tf, true); + if (retval) { + if (retval != EOF) { + ofp_print_error(s, retval); + } + return; + } + + ds_put_format(s, "\n table %"PRIu8":\n", tf.table_id); + ds_put_format(s, " name=\"%s\"\n", tf.name); + ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n", + ntohll(tf.metadata_match), ntohll(tf.metadata_write)); + + ds_put_cstr(s, " config="); + ofp_print_table_miss_config(s, tf.config); + + ds_put_format(s, " max_entries=%"PRIu32"\n", tf.max_entries); + + if (table_instruction_features_equal(&tf.nonmiss, &tf.miss)) { + ds_put_cstr(s, " instructions (table miss and others):\n"); + print_table_instruction_features(s, &tf.nonmiss); + } else { + ds_put_cstr(s, " instructions (other than table miss):\n"); + print_table_instruction_features(s, &tf.nonmiss); + ds_put_cstr(s, " instructions (table miss):\n"); + print_table_instruction_features(s, &tf.miss); + } + + ds_put_cstr(s, " matching:\n"); + for (i = 0; i < MFF_N_IDS; i++) { + uint64_t bit = UINT64_C(1) << i; + + if (tf.match & bit) { + const struct mf_field *f = mf_from_id(i); + + ds_put_format(s, " %s: %s\n", + f->name, + (tf.mask ? "arbitrary mask" + : tf.wildcard ? "exact match or wildcard" + : "must exact match")); + } + } + } +} + static void ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, struct ds *string, int verbosity) @@ -2543,7 +2708,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: - ofp_print_not_implemented(string); + ofp_print_table_features(string, oh); break; case OFPTYPE_HELLO: