/* Appends a description of 'mp' to 's', in the format that ovs-ofctl(8) * describes. */ void multipath_format(const struct ofpact_multipath *mp, struct ds *s) { const char *fields, *algorithm; fields = flow_hash_fields_to_str(mp->fields); switch (mp->algorithm) { case NX_MP_ALG_MODULO_N: algorithm = "modulo_n"; break; case NX_MP_ALG_HASH_THRESHOLD: algorithm = "hash_threshold"; break; case NX_MP_ALG_HRW: algorithm = "hrw"; break; case NX_MP_ALG_ITER_HASH: algorithm = "iter_hash"; break; default: algorithm = "<unknown>"; } ds_put_format(s, "%smultipath(%s%s,%"PRIu16",%s,%d,%"PRIu32",", colors.paren, colors.end, fields, mp->basis, algorithm, mp->max_link + 1, mp->arg); mf_format_subfield(&mp->dst, s); ds_put_format(s, "%s)%s", colors.paren, colors.end); }
/* Appends a human-readable representation of 'nab' to 's'. */ void bundle_format(const struct ofpact_bundle *bundle, struct ds *s) { const char *action, *fields, *algorithm; size_t i; fields = flow_hash_fields_to_str(bundle->fields); switch (bundle->algorithm) { case NX_BD_ALG_HRW: algorithm = "hrw"; break; case NX_BD_ALG_ACTIVE_BACKUP: algorithm = "active_backup"; break; default: algorithm = "<unknown>"; } action = bundle->dst.field ? "bundle_load" : "bundle"; ds_put_format(s, "%s(%s,%"PRIu16",%s,%s,", action, fields, bundle->basis, algorithm, "ofport"); if (bundle->dst.field) { mf_format_subfield(&bundle->dst, s); ds_put_cstr(s, ","); } ds_put_cstr(s, "slaves:"); for (i = 0; i < bundle->n_slaves; i++) { if (i) { ds_put_cstr(s, ","); } ofputil_format_port(bundle->slaves[i], s); } ds_put_cstr(s, ")"); }
void multipath_format(const struct nx_action_multipath *mp, struct ds *s) { const char *fields, *algorithm; uint16_t mp_fields = ntohs(mp->fields); uint16_t mp_algorithm = ntohs(mp->algorithm); struct mf_subfield dst; fields = flow_hash_fields_to_str(mp_fields); switch ((enum nx_mp_algorithm) mp_algorithm) { case NX_MP_ALG_MODULO_N: algorithm = "modulo_n"; break; case NX_MP_ALG_HASH_THRESHOLD: algorithm = "hash_threshold"; break; case NX_MP_ALG_HRW: algorithm = "hrw"; break; case NX_MP_ALG_ITER_HASH: algorithm = "iter_hash"; break; default: algorithm = "<unknown>"; } ds_put_format(s, "multipath(%s,%"PRIu16",%s,%d,%"PRIu16",", fields, ntohs(mp->basis), algorithm, ntohs(mp->max_link) + 1, ntohl(mp->arg)); nxm_decode(&dst, mp->dst, mp->ofs_nbits); mf_format_subfield(&dst, s); ds_put_char(s, ')'); }
/* Appends a description of 'learn' to 's', in the format that ovs-ofctl(8) * describes. */ void learn_format(const struct ofpact_learn *learn, struct ds *s) { const struct ofpact_learn_spec *spec; struct match match; match_init_catchall(&match); ds_put_format(s, "learn(table=%"PRIu8, learn->table_id); if (learn->idle_timeout != OFP_FLOW_PERMANENT) { ds_put_format(s, ",idle_timeout=%"PRIu16, learn->idle_timeout); } if (learn->hard_timeout != OFP_FLOW_PERMANENT) { ds_put_format(s, ",hard_timeout=%"PRIu16, learn->hard_timeout); } if (learn->fin_idle_timeout) { ds_put_format(s, ",fin_idle_timeout=%"PRIu16, learn->fin_idle_timeout); } if (learn->fin_hard_timeout) { ds_put_format(s, ",fin_hard_timeout=%"PRIu16, learn->fin_hard_timeout); } if (learn->priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, ",priority=%"PRIu16, learn->priority); } if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) { ds_put_cstr(s, ",send_flow_rem"); } if (learn->flags & NX_LEARN_F_DELETE_LEARNED) { ds_put_cstr(s, ",delete_learned"); } if (learn->cookie != 0) { ds_put_format(s, ",cookie=%#"PRIx64, ntohll(learn->cookie)); } for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { ds_put_char(s, ','); switch (spec->src_type | spec->dst_type) { case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH: if (spec->dst.ofs == 0 && spec->dst.n_bits == spec->dst.field->n_bits) { union mf_value value; memset(&value, 0, sizeof value); bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0, &value, spec->dst.field->n_bytes, 0, spec->dst.field->n_bits); ds_put_format(s, "%s=", spec->dst.field->name); mf_format(spec->dst.field, &value, NULL, s); } else { mf_format_subfield(&spec->dst, s); ds_put_char(s, '='); mf_format_subvalue(&spec->src_imm, s); } break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH: mf_format_subfield(&spec->dst, s); if (spec->src.field != spec->dst.field || spec->src.ofs != spec->dst.ofs) { ds_put_char(s, '='); mf_format_subfield(&spec->src, s); } break; case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD: ds_put_format(s, "load:"); mf_format_subvalue(&spec->src_imm, s); ds_put_cstr(s, "->"); mf_format_subfield(&spec->dst, s); break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_LOAD: ds_put_cstr(s, "load:"); mf_format_subfield(&spec->src, s); ds_put_cstr(s, "->"); mf_format_subfield(&spec->dst, s); break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_OUTPUT: ds_put_cstr(s, "output:"); mf_format_subfield(&spec->src, s); break; } } ds_put_char(s, ')'); }
void learn_format(const struct nx_action_learn *learn, struct ds *s) { struct cls_rule rule; const void *p, *end; cls_rule_init_catchall(&rule, 0); ds_put_format(s, "learn(table=%"PRIu8, learn->table_id); if (learn->idle_timeout != htons(OFP_FLOW_PERMANENT)) { ds_put_format(s, ",idle_timeout=%"PRIu16, ntohs(learn->idle_timeout)); } if (learn->hard_timeout != htons(OFP_FLOW_PERMANENT)) { ds_put_format(s, ",hard_timeout=%"PRIu16, ntohs(learn->hard_timeout)); } if (learn->fin_idle_timeout) { ds_put_format(s, ",fin_idle_timeout=%"PRIu16, ntohs(learn->fin_idle_timeout)); } if (learn->fin_hard_timeout) { ds_put_format(s, ",fin_hard_timeout=%"PRIu16, ntohs(learn->fin_hard_timeout)); } if (learn->priority != htons(OFP_DEFAULT_PRIORITY)) { ds_put_format(s, ",priority=%"PRIu16, ntohs(learn->priority)); } if (learn->flags & htons(OFPFF_SEND_FLOW_REM)) { ds_put_cstr(s, ",OFPFF_SEND_FLOW_REM"); } if (learn->flags & htons(~OFPFF_SEND_FLOW_REM)) { ds_put_format(s, ",***flags=%"PRIu16"***", ntohs(learn->flags) & ~OFPFF_SEND_FLOW_REM); } if (learn->cookie != htonll(0)) { ds_put_format(s, ",cookie=0x%"PRIx64, ntohll(learn->cookie)); } if (learn->pad != 0) { ds_put_cstr(s, ",***nonzero pad***"); } end = (char *) learn + ntohs(learn->len); for (p = learn + 1; p != end; ) { uint16_t header = ntohs(get_be16(&p)); int n_bits = header & NX_LEARN_N_BITS_MASK; int src_type = header & NX_LEARN_SRC_MASK; struct mf_subfield src; const uint8_t *src_value; int src_value_bytes; int dst_type = header & NX_LEARN_DST_MASK; struct mf_subfield dst; enum ofperr error; int i; if (!header) { break; } error = learn_check_header(header, (char *) end - (char *) p); if (error == OFPERR_OFPBAC_BAD_ARGUMENT) { ds_put_format(s, ",***bad flow_mod_spec header %"PRIx16"***)", header); return; } else if (error == OFPERR_OFPBAC_BAD_LEN) { ds_put_format(s, ",***flow_mod_spec at offset %td is %u bytes " "long but only %td bytes are left***)", (char *) p - (char *) (learn + 1) - 2, learn_min_len(header) + 2, (char *) end - (char *) p + 2); return; } assert(!error); /* Get the source. */ if (src_type == NX_LEARN_SRC_FIELD) { get_subfield(n_bits, &p, &src); src_value_bytes = 0; src_value = NULL; } else { src.field = NULL; src.ofs = 0; src.n_bits = 0; src_value_bytes = 2 * DIV_ROUND_UP(n_bits, 16); src_value = p; p = (const void *) ((const uint8_t *) p + src_value_bytes); } /* Get the destination. */ if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) { get_subfield(n_bits, &p, &dst); } else { dst.field = NULL; dst.ofs = 0; dst.n_bits = 0; } ds_put_char(s, ','); switch (src_type | dst_type) { case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH: if (dst.field && dst.ofs == 0 && n_bits == dst.field->n_bits) { union mf_value value; uint8_t *bytes = (uint8_t *) &value; if (src_value_bytes > dst.field->n_bytes) { /* The destination field is an odd number of bytes, which * got rounded up to a multiple of 2 to be put into the * learning action. Skip over the leading byte, which * should be zero anyway. Otherwise the memcpy() below * will overrun the start of 'value'. */ int diff = src_value_bytes - dst.field->n_bytes; src_value += diff; src_value_bytes -= diff; } memset(&value, 0, sizeof value); memcpy(&bytes[dst.field->n_bytes - src_value_bytes], src_value, src_value_bytes); ds_put_format(s, "%s=", dst.field->name); mf_format(dst.field, &value, NULL, s); } else { mf_format_subfield(&dst, s); ds_put_cstr(s, "=0x"); for (i = 0; i < src_value_bytes; i++) { ds_put_format(s, "%02"PRIx8, src_value[i]); } } break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH: mf_format_subfield(&dst, s); if (src.field != dst.field || src.ofs != dst.ofs) { ds_put_char(s, '='); mf_format_subfield(&src, s); } break; case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD: ds_put_cstr(s, "load:0x"); for (i = 0; i < src_value_bytes; i++) { ds_put_format(s, "%02"PRIx8, src_value[i]); } ds_put_cstr(s, "->"); mf_format_subfield(&dst, s); break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_LOAD: ds_put_cstr(s, "load:"); mf_format_subfield(&src, s); ds_put_cstr(s, "->"); mf_format_subfield(&dst, s); break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_OUTPUT: ds_put_cstr(s, "output:"); mf_format_subfield(&src, s); break; } } if (!is_all_zeros(p, (char *) end - (char *) p)) { ds_put_cstr(s, ",***nonzero trailer***"); } ds_put_char(s, ')'); }
/* Appends a description of 'learn' to 's', in the format that ovs-ofctl(8) * describes. */ void learn_format(const struct ofpact_learn *learn, const struct ofputil_port_map *port_map, struct ds *s) { const struct ofpact_learn_spec *spec; struct match match; match_init_catchall(&match); ds_put_format(s, "%slearn(%s%stable=%s%"PRIu8, colors.learn, colors.end, colors.special, colors.end, learn->table_id); if (learn->idle_timeout != OFP_FLOW_PERMANENT) { ds_put_format(s, ",%sidle_timeout=%s%"PRIu16, colors.param, colors.end, learn->idle_timeout); } if (learn->hard_timeout != OFP_FLOW_PERMANENT) { ds_put_format(s, ",%shard_timeout=%s%"PRIu16, colors.param, colors.end, learn->hard_timeout); } if (learn->fin_idle_timeout) { ds_put_format(s, ",%sfin_idle_timeout=%s%"PRIu16, colors.param, colors.end, learn->fin_idle_timeout); } if (learn->fin_hard_timeout) { ds_put_format(s, "%s,fin_hard_timeout=%s%"PRIu16, colors.param, colors.end, learn->fin_hard_timeout); } if (learn->priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, "%s,priority=%s%"PRIu16, colors.special, colors.end, learn->priority); } if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) { ds_put_format(s, ",%ssend_flow_rem%s", colors.value, colors.end); } if (learn->flags & NX_LEARN_F_DELETE_LEARNED) { ds_put_format(s, ",%sdelete_learned%s", colors.value, colors.end); } if (learn->cookie != 0) { ds_put_format(s, ",%scookie=%s%#"PRIx64, colors.param, colors.end, ntohll(learn->cookie)); } if (learn->limit != 0) { ds_put_format(s, ",%slimit=%s%"PRIu32, colors.param, colors.end, learn->limit); } if (learn->flags & NX_LEARN_F_WRITE_RESULT) { ds_put_format(s, ",%sresult_dst=%s", colors.param, colors.end); mf_format_subfield(&learn->result_dst, s); } OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { unsigned int n_bytes = DIV_ROUND_UP(spec->n_bits, 8); ds_put_char(s, ','); switch (spec->src_type | spec->dst_type) { case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH: { if (spec->dst.ofs == 0 && spec->dst.n_bits == spec->dst.field->n_bits) { union mf_value value; memset(&value, 0, sizeof value); memcpy(&value.b[spec->dst.field->n_bytes - n_bytes], ofpact_learn_spec_imm(spec), n_bytes); ds_put_format(s, "%s%s=%s", colors.param, spec->dst.field->name, colors.end); mf_format(spec->dst.field, &value, NULL, port_map, s); } else { ds_put_format(s, "%s", colors.param); mf_format_subfield(&spec->dst, s); ds_put_format(s, "=%s", colors.end); ds_put_hex(s, ofpact_learn_spec_imm(spec), n_bytes); } break; } case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH: ds_put_format(s, "%s", colors.param); mf_format_subfield(&spec->dst, s); ds_put_format(s, "%s", colors.end); if (spec->src.field != spec->dst.field || spec->src.ofs != spec->dst.ofs) { ds_put_format(s, "%s=%s", colors.param, colors.end); mf_format_subfield(&spec->src, s); } break; case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD: ds_put_format(s, "%sload:%s", colors.special, colors.end); ds_put_hex(s, ofpact_learn_spec_imm(spec), n_bytes); ds_put_format(s, "%s->%s", colors.special, colors.end); mf_format_subfield(&spec->dst, s); break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_LOAD: ds_put_format(s, "%sload:%s", colors.special, colors.end); mf_format_subfield(&spec->src, s); ds_put_format(s, "%s->%s", colors.special, colors.end); mf_format_subfield(&spec->dst, s); break; case NX_LEARN_SRC_FIELD | NX_LEARN_DST_OUTPUT: ds_put_format(s, "%soutput:%s", colors.special, colors.end); mf_format_subfield(&spec->src, s); break; } }