- 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;
- }