X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fofp-print.c;h=1f22dd75332f0481e14b4b3ba843093bb9c147b7;hb=de7d3c0761a34232613ac60792c0f6cf75fdca8e;hp=d773dca4faefc860c70ac13bdf8f10d72ee99c51;hpb=7ac27a044457b560836f6dc9c11443ba7e02045d;p=cascardo%2Fovs.git diff --git a/lib/ofp-print.c b/lib/ofp-print.c index d773dca4f..1f22dd753 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -52,9 +52,6 @@ static void ofp_print_queue_name(struct ds *string, uint32_t port); static void ofp_print_error(struct ds *, enum ofperr); -static void ofp_print_table_features(struct ds *, - const struct ofputil_table_features *, - const struct ofputil_table_stats *); /* Returns a string that represents the contents of the Ethernet frame in the * 'len' bytes starting at 'data'. The caller must free the returned string.*/ @@ -104,7 +101,6 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE]; struct ofputil_packet_in pin; int error; - int i; error = ofputil_decode_packet_in(&pin, oh); if (error) { @@ -120,43 +116,9 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie)); } - ds_put_format(string, " total_len=%"PRIuSIZE" in_port=", pin.total_len); - ofputil_format_port(pin.fmd.in_port, string); - - if (pin.fmd.tun_id != htonll(0)) { - ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id)); - } - - if (pin.fmd.tun_src != htonl(0)) { - ds_put_format(string, " tun_src="IP_FMT, IP_ARGS(pin.fmd.tun_src)); - } + ds_put_format(string, " total_len=%"PRIuSIZE" ", pin.total_len); - if (pin.fmd.tun_dst != htonl(0)) { - ds_put_format(string, " tun_dst="IP_FMT, IP_ARGS(pin.fmd.tun_dst)); - } - - if (pin.fmd.gbp_id != htons(0)) { - ds_put_format(string, " gbp_id=%"PRIu16, - ntohs(pin.fmd.gbp_id)); - } - - if (pin.fmd.gbp_flags) { - ds_put_format(string, " gbp_flags=0x%02"PRIx8, pin.fmd.gbp_flags); - } - - if (pin.fmd.metadata != htonll(0)) { - ds_put_format(string, " metadata=0x%"PRIx64, ntohll(pin.fmd.metadata)); - } - - for (i = 0; i < FLOW_N_REGS; i++) { - if (pin.fmd.regs[i]) { - ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.fmd.regs[i]); - } - } - - if (pin.fmd.pkt_mark != 0) { - ds_put_format(string, " pkt_mark=0x%"PRIx32, pin.fmd.pkt_mark); - } + match_format(&pin.flow_metadata, string, OFP_DEFAULT_PRIORITY); ds_put_format(string, " (via %s)", ofputil_packet_in_reason_to_string(pin.reason, reasonbuf, @@ -900,6 +862,7 @@ ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason, return "eviction"; case OFPRR_METER_DELETE: return "meter_delete"; + case OVS_OFPRR_NONE: default: snprintf(reasonbuf, bufsize, "%d", (int) reason); return reasonbuf; @@ -976,26 +939,69 @@ ofp_print_port_mod(struct ds *string, const struct ofp_header *oh) } } -static void -ofp_print_table_miss_config(struct ds *string, enum ofputil_table_miss miss) +static const char * +ofputil_table_miss_to_string(enum ofputil_table_miss miss) { switch (miss) { - case OFPUTIL_TABLE_MISS_CONTROLLER: - ds_put_cstr(string, "controller\n"); - break; - case OFPUTIL_TABLE_MISS_CONTINUE: - ds_put_cstr(string, "continue\n"); - break; - case OFPUTIL_TABLE_MISS_DROP: - ds_put_cstr(string, "drop\n"); - break; - case OFPUTIL_TABLE_MISS_DEFAULT: - default: - ds_put_format(string, "Unknown (%d)\n", miss); - break; + case OFPUTIL_TABLE_MISS_DEFAULT: return "default"; + case OFPUTIL_TABLE_MISS_CONTROLLER: return "controller"; + case OFPUTIL_TABLE_MISS_CONTINUE: return "continue"; + case OFPUTIL_TABLE_MISS_DROP: return "drop"; + default: return "***error***"; + } +} + +static const char * +ofputil_table_eviction_to_string(enum ofputil_table_eviction eviction) +{ + switch (eviction) { + case OFPUTIL_TABLE_EVICTION_DEFAULT: return "default"; + case OFPUTIL_TABLE_EVICTION_ON: return "on"; + case OFPUTIL_TABLE_EVICTION_OFF: return "off"; + default: return "***error***"; + } + +} + +static const char * +ofputil_eviction_flag_to_string(uint32_t bit) +{ + enum ofp14_table_mod_prop_eviction_flag eviction_flag = bit; + + switch (eviction_flag) { + case OFPTMPEF14_OTHER: return "OTHER"; + case OFPTMPEF14_IMPORTANCE: return "IMPORTANCE"; + case OFPTMPEF14_LIFETIME: return "LIFETIME"; + } + + return NULL; +} + +/* Appends to 'string' a description of the bitmap of OFPTMPEF14_* values in + * 'eviction_flags'. */ +static void +ofputil_put_eviction_flags(struct ds *string, uint32_t eviction_flags) +{ + if (eviction_flags != UINT32_MAX) { + ofp_print_bit_names(string, eviction_flags, + ofputil_eviction_flag_to_string, '|'); + } else { + ds_put_cstr(string, "(default)"); } } +static const char * +ofputil_table_vacancy_to_string(enum ofputil_table_vacancy vacancy) +{ + switch (vacancy) { + case OFPUTIL_TABLE_VACANCY_DEFAULT: return "default"; + case OFPUTIL_TABLE_VACANCY_ON: return "on"; + case OFPUTIL_TABLE_VACANCY_OFF: return "off"; + default: return "***error***"; + } + +} + static void ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) { @@ -1014,10 +1020,39 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) ds_put_format(string, " table_id=%"PRIu8, pm.table_id); } - if (pm.miss_config != OFPUTIL_TABLE_MISS_DEFAULT) { - ds_put_cstr(string, ", flow_miss_config="); - ofp_print_table_miss_config(string, pm.miss_config); + if (pm.miss != OFPUTIL_TABLE_MISS_DEFAULT) { + ds_put_format(string, ", flow_miss_config=%s", + ofputil_table_miss_to_string(pm.miss)); + } + if (pm.eviction != OFPUTIL_TABLE_EVICTION_DEFAULT) { + ds_put_format(string, ", eviction=%s", + ofputil_table_eviction_to_string(pm.eviction)); + } + if (pm.eviction_flags != UINT32_MAX) { + ds_put_cstr(string, "eviction_flags="); + ofputil_put_eviction_flags(string, pm.eviction_flags); } + if (pm.vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) { + ds_put_format(string, ", vacancy=%s", + ofputil_table_vacancy_to_string(pm.vacancy)); + if (pm.vacancy == OFPUTIL_TABLE_VACANCY_ON) { + ds_put_format(string, " vacancy:%"PRIu8"" + ",%"PRIu8"", pm.table_vacancy.vacancy_down, + pm.table_vacancy.vacancy_up); + } + } +} + +/* This function will print the Table description properties. */ +static void +ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc *td) +{ + ds_put_format(string, "\n table %"PRIu8, td->table_id); + ds_put_cstr(string, ":\n"); + ds_put_format(string, " eviction=%s eviction_flags=", + ofputil_table_eviction_to_string(td->eviction)); + ofputil_put_eviction_flags(string, td->eviction_flags); + ds_put_char(string, '\n'); } static void @@ -1171,21 +1206,9 @@ ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc) } static void -ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) +ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm) { - struct ofputil_meter_mod mm; - struct ofpbuf bands; - enum ofperr error; - - ofpbuf_init(&bands, 64); - error = ofputil_decode_meter_mod(oh, &mm, &bands); - if (error) { - ofpbuf_uninit(&bands); - ofp_print_error(s, error); - return; - } - - switch (mm.command) { + switch (mm->command) { case OFPMC13_ADD: ds_put_cstr(s, " ADD "); break; @@ -1196,10 +1219,26 @@ ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) ds_put_cstr(s, " DEL "); break; default: - ds_put_format(s, " cmd:%d ", mm.command); + ds_put_format(s, " cmd:%d ", mm->command); } - ofp_print_meter_config(s, &mm.meter); + ofp_print_meter_config(s, &mm->meter); +} + +static void +ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) +{ + struct ofputil_meter_mod mm; + struct ofpbuf bands; + enum ofperr error; + + ofpbuf_init(&bands, 64); + error = ofputil_decode_meter_mod(oh, &mm, &bands); + if (error) { + ofp_print_error(s, error); + } else { + ofp_print_meter_mod__(s, &mm); + } ofpbuf_uninit(&bands); } @@ -1604,7 +1643,9 @@ ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh) ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); - for (;;) { + struct ofputil_table_features prev_features; + struct ofputil_table_stats prev_stats; + for (int i = 0;; i++) { struct ofputil_table_features features; struct ofputil_table_stats stats; int retval; @@ -1617,7 +1658,12 @@ ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh) return; } - ofp_print_table_features(string, &features, &stats); + ds_put_char(string, '\n'); + ofp_print_table_features(string, + &features, i ? &prev_features : NULL, + &stats, i ? &prev_stats : NULL); + prev_features = features; + prev_stats = stats; } } @@ -1886,64 +1932,220 @@ ofp_port_reason_to_string(enum ofp_port_reason reason, } } +/* Returns a string form of 'reason'. The return value is either a statically + * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. + * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */ +static const char* +ofp_role_reason_to_string(enum ofp14_controller_role_reason reason, + char *reasonbuf, size_t bufsize) +{ + switch (reason) { + case OFPCRR_MASTER_REQUEST: + return "master_request"; + + case OFPCRR_CONFIG: + return "configuration_changed"; + + case OFPCRR_EXPERIMENTER: + return "experimenter_data_changed"; + + default: + snprintf(reasonbuf, bufsize, "%d", (int) reason); + return reasonbuf; + } +} + +/* Returns a string form of 'reason'. The return value is either a statically + * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. + * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */ +static const char* +ofp_table_reason_to_string(enum ofp14_table_reason reason, + char *reasonbuf, size_t bufsize) +{ + switch (reason) { + case OFPTR_VACANCY_DOWN: + return "vacancy_down"; + + case OFPTR_VACANCY_UP: + return "vacancy_up"; + + default: + snprintf(reasonbuf, bufsize, "%d", (int) reason); + return reasonbuf; + } +} + +/* Returns a string form of 'reason'. The return value is either a statically + * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. + * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */ +static const char* +ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason, + char *reasonbuf, size_t bufsize) +{ + switch (reason) { + case OFPRFR_GROUP_MOD: + return "group_mod_request"; + + case OFPRFR_METER_MOD: + return "meter_mod_request"; + + default: + snprintf(reasonbuf, bufsize, "%d", (int) reason); + return reasonbuf; + } +} + +static const char * +ofp_async_config_reason_to_string(uint32_t reason, + enum ofputil_async_msg_type type, + char *reasonbuf, size_t bufsize) +{ + switch (type) { + case OAM_PACKET_IN: + return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize); + + case OAM_PORT_STATUS: + return ofp_port_reason_to_string(reason, reasonbuf, bufsize); + + case OAM_FLOW_REMOVED: + return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize); + + case OAM_ROLE_STATUS: + return ofp_role_reason_to_string(reason, reasonbuf, bufsize); + + case OAM_TABLE_STATUS: + return ofp_table_reason_to_string(reason, reasonbuf, bufsize); + + case OAM_REQUESTFORWARD: + return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize); + + case OAM_N_TYPES: + default: + return "Unknown asynchronous configuration message type"; + } +} + + +#define OFP_ASYNC_CONFIG_REASON_BUFSIZE (INT_STRLEN(int) + 1) static void ofp_print_nxt_set_async_config(struct ds *string, - const struct nx_async_config *nac) + const struct ofp_header *oh) { - int i; + int i, j; + enum ofpraw raw; + + ofpraw_decode(&raw, oh); - for (i = 0; i < 2; i++) { - int j; + if (raw == OFPRAW_OFPT13_SET_ASYNC || + raw == OFPRAW_NXT_SET_ASYNC_CONFIG || + raw == OFPRAW_OFPT13_GET_ASYNC_REPLY) { + const struct nx_async_config *nac = ofpmsg_body(oh); - ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave"); + for (i = 0; i < 2; i++) { - ds_put_cstr(string, " PACKET_IN:"); - for (j = 0; j < 32; j++) { - if (nac->packet_in_mask[i] & htonl(1u << j)) { - char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE]; - const char *reason; + ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave"); - reason = ofputil_packet_in_reason_to_string(j, reasonbuf, + ds_put_cstr(string, " PACKET_IN:"); + for (j = 0; j < 32; j++) { + if (nac->packet_in_mask[i] & htonl(1u << j)) { + char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE]; + const char *reason; + + reason = ofputil_packet_in_reason_to_string(j, reasonbuf, sizeof reasonbuf); - ds_put_format(string, " %s", reason); + ds_put_format(string, " %s", reason); + } } - } - if (!nac->packet_in_mask[i]) { - ds_put_cstr(string, " (off)"); - } - ds_put_char(string, '\n'); + 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)) { - char reasonbuf[OFP_PORT_REASON_BUFSIZE]; - const char *reason; + ds_put_cstr(string, " PORT_STATUS:"); + for (j = 0; j < 32; j++) { + if (nac->port_status_mask[i] & htonl(1u << j)) { + char reasonbuf[OFP_PORT_REASON_BUFSIZE]; + const char *reason; - reason = ofp_port_reason_to_string(j, reasonbuf, - sizeof reasonbuf); - ds_put_format(string, " %s", reason); + reason = ofp_port_reason_to_string(j, reasonbuf, + sizeof reasonbuf); + ds_put_format(string, " %s", reason); + } } - } - if (!nac->port_status_mask[i]) { - ds_put_cstr(string, " (off)"); - } - ds_put_char(string, '\n'); + 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)) { - char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE]; - const char *reason; + ds_put_cstr(string, " FLOW_REMOVED:"); + for (j = 0; j < 32; j++) { + if (nac->flow_removed_mask[i] & htonl(1u << j)) { + char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE]; + const char *reason; - reason = ofp_flow_removed_reason_to_string(j, reasonbuf, + reason = ofp_flow_removed_reason_to_string(j, reasonbuf, sizeof reasonbuf); - ds_put_format(string, " %s", reason); + ds_put_format(string, " %s", reason); + } + } + if (!nac->flow_removed_mask[i]) { + ds_put_cstr(string, " (off)"); } + ds_put_char(string, '\n'); } - if (!nac->flow_removed_mask[i]) { - ds_put_cstr(string, " (off)"); + } else if (raw == OFPRAW_OFPT14_SET_ASYNC || + raw == OFPRAW_OFPT14_GET_ASYNC_REPLY) { + uint32_t role[2][OAM_N_TYPES] = {{0}}; + uint32_t type; + + ofputil_decode_set_async_config(oh, role[0], role[1], true); + for (i = 0; i < 2; i++) { + + ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave"); + for (type = 0; type < OAM_N_TYPES; type++) { + switch (type) { + case OAM_PACKET_IN: + ds_put_cstr(string, " PACKET_IN:"); + break; + + case OAM_PORT_STATUS: + ds_put_cstr(string, " PORT_STATUS:"); + break; + + case OAM_FLOW_REMOVED: + ds_put_cstr(string, " FLOW_REMOVED:"); + break; + + case OAM_ROLE_STATUS: + ds_put_cstr(string, " ROLE_STATUS:"); + break; + + case OAM_TABLE_STATUS: + ds_put_cstr(string, " TABLE_STATUS:"); + break; + + case OAM_REQUESTFORWARD: + ds_put_cstr(string, " REQUESTFORWARD:"); + break; + } + + for (j = 0; j < 32; j++) { + if (role[i][type] & (1u << j)) { + char reasonbuf[OFP_ASYNC_CONFIG_REASON_BUFSIZE]; + const char *reason; + + reason = ofp_async_config_reason_to_string(j, type, + reasonbuf, + sizeof reasonbuf); + ds_put_format(string, " %s", reason); + } + } + if (!role[i][type]) { + ds_put_cstr(string, " (off)"); + } + ds_put_char(string, '\n'); + } } - ds_put_char(string, '\n'); } } @@ -2156,7 +2358,8 @@ ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id, static void ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, - struct ovs_list *p_buckets, struct ofputil_group_props *props, + const struct ovs_list *p_buckets, + const struct ofputil_group_props *props, enum ofp_version ofp_version, bool suppress_type) { struct ofputil_bucket *bucket; @@ -2170,22 +2373,20 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, } if (props->selection_method[0]) { - size_t mark, start; - - ds_put_format(s, ",selection_method=%s,", props->selection_method); + ds_put_format(s, ",selection_method=%s", props->selection_method); if (props->selection_method_param) { - ds_put_format(s, "selection_method_param=%"PRIu64",", + ds_put_format(s, ",selection_method_param=%"PRIu64, props->selection_method_param); } - /* Allow rewinding to immediately before the trailing ',' */ - mark = s->length - 1; - - ds_put_cstr(s, "fields="); - start = s->length; - oxm_format_field_array(s, &props->fields); - if (s->length == start) { - ds_truncate(s, mark); + size_t n = bitmap_count1(props->fields.used.bm, MFF_N_IDS); + if (n == 1) { + ds_put_cstr(s, ",fields="); + oxm_format_field_array(s, &props->fields); + } else if (n > 1) { + ds_put_cstr(s, ",fields("); + oxm_format_field_array(s, &props->fields); + ds_put_char(s, ')'); } } @@ -2199,13 +2400,13 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, ds_put_cstr(s, "bucket="); ofp_print_bucket_id(s, "bucket_id:", bucket->bucket_id, ofp_version); - if (bucket->weight != 1) { + if (bucket->weight != (type == OFPGT11_SELECT ? 1 : 0)) { ds_put_format(s, "weight:%"PRIu16",", bucket->weight); } if (bucket->watch_port != OFPP_NONE) { ds_put_format(s, "watch_port:%"PRIu32",", bucket->watch_port); } - if (bucket->watch_group != OFPG11_ANY) { + if (bucket->watch_group != OFPG_ANY) { ds_put_format(s, "watch_group:%"PRIu32",", bucket->watch_group); } @@ -2352,22 +2553,15 @@ ofp_print_group_features(struct ds *string, const struct ofp_header *oh) } static void -ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) +ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version, + const struct ofputil_group_mod *gm) { - struct ofputil_group_mod gm; - int error; bool bucket_command = false; - error = ofputil_decode_group_mod(oh, &gm); - if (error) { - ofp_print_error(s, error); - return; - } - ds_put_char(s, '\n'); ds_put_char(s, ' '); - switch (gm.command) { + switch (gm->command) { case OFPGC11_ADD: ds_put_cstr(s, "ADD"); break; @@ -2391,17 +2585,31 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) break; default: - ds_put_format(s, "cmd:%"PRIu16"", gm.command); + ds_put_format(s, "cmd:%"PRIu16"", gm->command); } ds_put_char(s, ' '); if (bucket_command) { ofp_print_bucket_id(s, "command_bucket_id:", - gm.command_bucket_id, oh->version); + gm->command_bucket_id, ofp_version); } - ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props, - oh->version, bucket_command); + ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props, + ofp_version, bucket_command); +} + +static void +ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) +{ + struct ofputil_group_mod gm; + int error; + + error = ofputil_decode_group_mod(oh, &gm); + if (error) { + ofp_print_error(s, error); + return; + } + ofp_print_group_mod__(s, oh->version, &gm); ofputil_bucket_list_destroy(&gm.buckets); } @@ -2442,7 +2650,9 @@ table_action_features_empty(const struct ofputil_table_action_features *taf) static void print_table_instruction_features( - struct ds *s, const struct ofputil_table_instruction_features *tif) + struct ds *s, + const struct ofputil_table_instruction_features *tif, + const struct ofputil_table_instruction_features *prev_tif) { int start, end; @@ -2465,19 +2675,28 @@ print_table_instruction_features( } if (tif->instructions) { - ds_put_cstr(s, " instructions: "); - int i; + if (prev_tif && tif->instructions == prev_tif->instructions) { + ds_put_cstr(s, " (same instructions)\n"); + } else { + ds_put_cstr(s, " 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)); + 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, ','); + ds_put_char(s, '\n'); } - ds_chomp(s, ','); - ds_put_char(s, '\n'); } - if (!table_action_features_equal(&tif->write, &tif->apply)) { + if (prev_tif + && table_action_features_equal(&tif->write, &prev_tif->write) + && table_action_features_equal(&tif->apply, &prev_tif->apply) + && !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) { + ds_put_cstr(s, " (same actions)\n"); + } else if (!table_action_features_equal(&tif->write, &tif->apply)) { ds_put_cstr(s, " Write-Actions features:\n"); print_table_action_features(s, &tif->write); ds_put_cstr(s, " Apply-Actions features:\n"); @@ -2510,61 +2729,143 @@ table_instruction_features_empty( && table_action_features_empty(&tif->apply)); } -static void +static bool +table_features_equal(const struct ofputil_table_features *a, + const struct ofputil_table_features *b) +{ + return (a->metadata_match == b->metadata_match + && a->metadata_write == b->metadata_write + && a->miss_config == b->miss_config + && a->supports_eviction == b->supports_eviction + && a->supports_vacancy_events == b->supports_vacancy_events + && a->max_entries == b->max_entries + && table_instruction_features_equal(&a->nonmiss, &b->nonmiss) + && table_instruction_features_equal(&a->miss, &b->miss) + && bitmap_equal(a->match.bm, b->match.bm, MFF_N_IDS)); +} + +static bool +table_features_empty(const struct ofputil_table_features *tf) +{ + return (!tf->metadata_match + && !tf->metadata_write + && tf->miss_config == OFPUTIL_TABLE_MISS_DEFAULT + && tf->supports_eviction < 0 + && tf->supports_vacancy_events < 0 + && !tf->max_entries + && table_instruction_features_empty(&tf->nonmiss) + && table_instruction_features_empty(&tf->miss) + && bitmap_is_all_zeros(tf->match.bm, MFF_N_IDS)); +} + +static bool +table_stats_equal(const struct ofputil_table_stats *a, + const struct ofputil_table_stats *b) +{ + return (a->active_count == b->active_count + && a->lookup_count == b->lookup_count + && a->matched_count == b->matched_count); +} + +void ofp_print_table_features(struct ds *s, const struct ofputil_table_features *features, - const struct ofputil_table_stats *stats) + const struct ofputil_table_features *prev_features, + const struct ofputil_table_stats *stats, + const struct ofputil_table_stats *prev_stats) { int i; - ds_put_format(s, "\n table %"PRIu8, features->table_id); + ds_put_format(s, " table %"PRIu8, features->table_id); if (features->name[0]) { ds_put_format(s, " (\"%s\")", features->name); } - ds_put_cstr(s, ":\n"); + ds_put_char(s, ':'); + + bool same_stats = prev_stats && table_stats_equal(stats, prev_stats); + bool same_features = prev_features && table_features_equal(features, + prev_features); + if ((!stats || same_stats) && same_features) { + ds_put_cstr(s, " ditto"); + return; + } + ds_put_char(s, '\n'); if (stats) { ds_put_format(s, " active=%"PRIu32", ", stats->active_count); ds_put_format(s, "lookup=%"PRIu64", ", stats->lookup_count); ds_put_format(s, "matched=%"PRIu64"\n", stats->matched_count); } - if (features->metadata_match || features->metadata_match) { + if (same_features) { + if (!table_features_empty(features)) { + ds_put_cstr(s, " (same features)\n"); + } + return; + } + if (features->metadata_match || features->metadata_write) { ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n", ntohll(features->metadata_match), ntohll(features->metadata_write)); } if (features->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) { - ds_put_cstr(s, " config="); - ofp_print_table_miss_config(s, features->miss_config); + ds_put_format(s, " config=%s\n", + ofputil_table_miss_to_string(features->miss_config)); + } + + if (features->supports_eviction >= 0) { + ds_put_format(s, " eviction: %ssupported\n", + features->supports_eviction ? "" : "not "); + + } + if (features->supports_vacancy_events >= 0) { + ds_put_format(s, " vacancy events: %ssupported\n", + features->supports_vacancy_events ? "" : "not "); + } if (features->max_entries) { ds_put_format(s, " max_entries=%"PRIu32"\n", features->max_entries); } - if (!table_instruction_features_equal(&features->nonmiss, - &features->miss)) { + const struct ofputil_table_instruction_features *prev_nonmiss + = prev_features ? &prev_features->nonmiss : NULL; + const struct ofputil_table_instruction_features *prev_miss + = prev_features ? &prev_features->miss : NULL; + if (prev_features + && table_instruction_features_equal(&features->nonmiss, prev_nonmiss) + && table_instruction_features_equal(&features->miss, prev_miss)) { + if (!table_instruction_features_empty(&features->nonmiss)) { + ds_put_cstr(s, " (same instructions)\n"); + } + } else if (!table_instruction_features_equal(&features->nonmiss, + &features->miss)) { ds_put_cstr(s, " instructions (other than table miss):\n"); - print_table_instruction_features(s, &features->nonmiss); + print_table_instruction_features(s, &features->nonmiss, prev_nonmiss); ds_put_cstr(s, " instructions (table miss):\n"); - print_table_instruction_features(s, &features->miss); + print_table_instruction_features(s, &features->miss, prev_miss); } else if (!table_instruction_features_empty(&features->nonmiss)) { ds_put_cstr(s, " instructions (table miss and others):\n"); - print_table_instruction_features(s, &features->nonmiss); + print_table_instruction_features(s, &features->nonmiss, prev_nonmiss); } - if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)){ - ds_put_cstr(s, " matching:\n"); - BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) { - const struct mf_field *f = mf_from_id(i); - bool mask = bitmap_is_set(features->mask.bm, i); - bool wildcard = bitmap_is_set(features->wildcard.bm, i); - - ds_put_format(s, " %s: %s\n", - f->name, - (mask ? "arbitrary mask" - : wildcard ? "exact match or wildcard" - : "must exact match")); + if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)) { + if (prev_features + && bitmap_equal(features->match.bm, prev_features->match.bm, + MFF_N_IDS)) { + ds_put_cstr(s, " (same matching)\n"); + } else { + ds_put_cstr(s, " matching:\n"); + BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) { + const struct mf_field *f = mf_from_id(i); + bool mask = bitmap_is_set(features->mask.bm, i); + bool wildcard = bitmap_is_set(features->wildcard.bm, i); + + ds_put_format(s, " %s: %s\n", + f->name, + (mask ? "arbitrary mask" + : wildcard ? "exact match or wildcard" + : "must exact match")); + } } } } @@ -2576,7 +2877,8 @@ ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh) ofpbuf_use_const(&b, oh, ntohs(oh->length)); - for (;;) { + struct ofputil_table_features prev; + for (int i = 0; ; i++) { struct ofputil_table_features tf; int retval; @@ -2587,7 +2889,32 @@ ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh) } return; } - ofp_print_table_features(s, &tf, NULL); + + ds_put_char(s, '\n'); + ofp_print_table_features(s, &tf, i ? &prev : NULL, NULL, NULL); + prev = tf; + } +} + +static void +ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh) +{ + struct ofpbuf b; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + + for (;;) { + struct ofputil_table_desc td; + int retval; + + retval = ofputil_decode_table_desc(&b, &td, oh->version); + if (retval) { + if (retval != EOF) { + ofp_print_error(s, retval); + } + return; + } + ofp_print_table_desc(s, &td); } } @@ -2675,6 +3002,115 @@ ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, int verbosity) } } +static void +print_geneve_table(struct ds *s, struct ovs_list *mappings) +{ + struct ofputil_geneve_map *map; + + ds_put_cstr(s, " mapping table:\n"); + ds_put_cstr(s, " class\ttype\tlength\tmatch field\n"); + ds_put_cstr(s, " -----\t----\t------\t-----------"); + + LIST_FOR_EACH (map, list_node, mappings) { + ds_put_char(s, '\n'); + ds_put_format(s, " 0x%"PRIx16"\t0x%"PRIx8"\t%"PRIu8"\ttun_metadata%"PRIu16, + map->option_class, map->option_type, map->option_len, + map->index); + } +} + +static void +ofp_print_geneve_table_mod(struct ds *s, const struct ofp_header *oh) +{ + int error; + struct ofputil_geneve_table_mod gtm; + + error = ofputil_decode_geneve_table_mod(oh, >m); + if (error) { + ofp_print_error(s, error); + return; + } + + ds_put_cstr(s, "\n "); + + switch (gtm.command) { + case NXGTMC_ADD: + ds_put_cstr(s, "ADD"); + break; + case NXGTMC_DELETE: + ds_put_cstr(s, "DEL"); + break; + case NXGTMC_CLEAR: + ds_put_cstr(s, "CLEAR"); + break; + } + + if (gtm.command != NXGTMC_CLEAR) { + print_geneve_table(s, >m.mappings); + } + + ofputil_uninit_geneve_table(>m.mappings); +} + +static void +ofp_print_geneve_table_reply(struct ds *s, const struct ofp_header *oh) +{ + int error; + struct ofputil_geneve_table_reply gtr; + struct ofputil_geneve_map *map; + int allocated_space = 0; + + error = ofputil_decode_geneve_table_reply(oh, >r); + if (error) { + ofp_print_error(s, error); + return; + } + + ds_put_char(s, '\n'); + + LIST_FOR_EACH (map, list_node, >r.mappings) { + allocated_space += map->option_len; + } + + ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n", + gtr.max_option_space, gtr.max_fields); + ds_put_format(s, " allocated option space=%d\n", allocated_space); + ds_put_char(s, '\n'); + print_geneve_table(s, >r.mappings); + + ofputil_uninit_geneve_table(>r.mappings); +} + +/* This function will print the request forward message. The reason for + * request forward is taken from rf.request.type */ +static void +ofp_print_requestforward(struct ds *string, const struct ofp_header *oh) +{ + struct ofputil_requestforward rf; + enum ofperr error; + + error = ofputil_decode_requestforward(oh, &rf); + if (error) { + ofp_print_error(string, error); + return; + } + + ds_put_cstr(string, " reason="); + + switch (rf.reason) { + case OFPRFR_GROUP_MOD: + ds_put_cstr(string, "group_mod"); + ofp_print_group_mod__(string, oh->version, rf.group_mod); + break; + + case OFPRFR_METER_MOD: + ds_put_cstr(string, "meter_mod"); + ofp_print_meter_mod__(string, rf.meter_mod); + break; + } + ofputil_destroy_requestforward(&rf); +} + static void ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, struct ds *string, int verbosity) @@ -2719,6 +3155,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_table_features_reply(string, oh); break; + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: + ofp_print_table_desc_reply(string, oh); + break; + case OFPTYPE_HELLO: ofp_print_hello(string, oh); break; @@ -2799,6 +3240,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_role_status_message(string, oh); break; + case OFPTYPE_REQUESTFORWARD: + ofp_print_requestforward(string, oh); + break; + case OFPTYPE_METER_STATS_REQUEST: case OFPTYPE_METER_CONFIG_STATS_REQUEST: ofp_print_stats(string, oh); @@ -2906,7 +3351,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, case OFPTYPE_GET_ASYNC_REPLY: case OFPTYPE_SET_ASYNC_CONFIG: - ofp_print_nxt_set_async_config(string, ofpmsg_body(oh)); + ofp_print_nxt_set_async_config(string, oh); break; case OFPTYPE_GET_ASYNC_REQUEST: break; @@ -2933,6 +3378,18 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, case OFPTYPE_BUNDLE_ADD_MESSAGE: ofp_print_bundle_add(string, msg, verbosity); break; + + case OFPTYPE_NXT_GENEVE_TABLE_MOD: + ofp_print_geneve_table_mod(string, msg); + break; + + case OFPTYPE_NXT_GENEVE_TABLE_REQUEST: + break; + + case OFPTYPE_NXT_GENEVE_TABLE_REPLY: + ofp_print_geneve_table_reply(string, msg); + break; + } }