/* Updates the 'len' field of the instruction header in 'buffer' to * "what it should be"(tm). */ void update_instruction_length(struct ofpbuf *buffer, size_t oia_offset) { struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); struct ofp_instruction *ih = ofpbuf_at_assert(buffer, oia_offset, sizeof *ih); ih->len = htons(buffer->size - oia_offset); }
void clear_xid(struct ofpbuf *buf) { /* * some of libofproto message encoding routines automatically * allocate XID for the message. e.g. ofputil_encode_flow_mod * zero-out the XID so that test_parser can perform a simple * bit-wise comparison. */ struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof(*oh)); oh->xid = htonl(0); }
/* Converts 'learn' into a "struct nx_action_learn" and appends that action to * 'ofpacts'. */ void learn_to_nxast(const struct ofpact_learn *learn, struct ofpbuf *openflow) { const struct ofpact_learn_spec *spec; struct nx_action_learn *nal; size_t start_ofs; start_ofs = openflow->size; nal = ofputil_put_NXAST_LEARN(openflow); nal->idle_timeout = htons(learn->idle_timeout); nal->hard_timeout = htons(learn->hard_timeout); nal->fin_idle_timeout = htons(learn->fin_idle_timeout); nal->fin_hard_timeout = htons(learn->fin_hard_timeout); nal->priority = htons(learn->priority); nal->cookie = htonll(learn->cookie); nal->flags = htons(learn->flags); nal->table_id = learn->table_id; for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { put_u16(openflow, spec->n_bits | spec->dst_type | spec->src_type); if (spec->src_type == NX_LEARN_SRC_FIELD) { put_u32(openflow, spec->src.field->nxm_header); put_u16(openflow, spec->src.ofs); } else { size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); uint8_t *bits = ofpbuf_put_zeros(openflow, n_dst_bytes); bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0, bits, n_dst_bytes, 0, spec->n_bits); } if (spec->dst_type == NX_LEARN_DST_MATCH || spec->dst_type == NX_LEARN_DST_LOAD) { put_u32(openflow, spec->dst.field->nxm_header); put_u16(openflow, spec->dst.ofs); } } if ((openflow->size - start_ofs) % 8) { ofpbuf_put_zeros(openflow, 8 - (openflow->size - start_ofs) % 8); } nal = ofpbuf_at_assert(openflow, start_ofs, sizeof *nal); nal->len = htons(openflow->size - start_ofs); }
/* Encapsulates 'msg', which must contain an OpenFlow message, in a Netlink * message, and sends it to the OpenFlow local datapath numbered 'dp_idx' via * 'sock'. * * Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN * if the 'sock' send buffer is full. * * If the send is successful, then the kernel module will receive it, but there * is no guarantee that any reply will not be dropped (see nl_sock_transact() * for details). */ int dpif_send_openflow(struct dpif *dp, int dp_idx, struct ofpbuf *buffer) { struct ofp_header *oh; unsigned int dump_flag; struct ofpbuf hdr; struct nlattr *nla; uint32_t fixed_buffer[64 / 4]; struct iovec iov[3]; int pad_bytes; int n_iov; int retval; /* The reply to OFPT_STATS_REQUEST may be multiple segments long, so we * need to specify NLM_F_DUMP in the request. */ oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); dump_flag = oh->type == OFPT_STATS_REQUEST ? NLM_F_DUMP : 0; ofpbuf_use(&hdr, fixed_buffer, sizeof fixed_buffer); nl_msg_put_genlmsghdr(&hdr, dp->sock, 32, openflow_family, NLM_F_REQUEST | dump_flag, DP_GENL_C_OPENFLOW, 1); nl_msg_put_u32(&hdr, DP_GENL_A_DP_IDX, dp_idx); nla = ofpbuf_put_uninit(&hdr, sizeof *nla); nla->nla_len = sizeof *nla + buffer->size; nla->nla_type = DP_GENL_A_OPENFLOW; pad_bytes = NLA_ALIGN(nla->nla_len) - nla->nla_len; nl_msg_nlmsghdr(&hdr)->nlmsg_len = hdr.size + buffer->size + pad_bytes; n_iov = 2; iov[0].iov_base = hdr.data; iov[0].iov_len = hdr.size; iov[1].iov_base = buffer->data; iov[1].iov_len = buffer->size; if (pad_bytes) { static char zeros[NLA_ALIGNTO]; n_iov++; iov[2].iov_base = zeros; iov[2].iov_len = pad_bytes; } retval = nl_sock_sendv(dp->sock, iov, n_iov, false); if (retval && retval != EAGAIN) { VLOG_WARN_RL(&rl, "dpif_send_openflow: %s", strerror(retval)); } return retval; }
/* Parses 'arg' as a set of arguments to the "learn" action and appends a * matching NXAST_LEARN action to 'b'. The format parsed is described in * ovs-ofctl(8). * * Prints an error on stderr and aborts the program if 'arg' syntax is invalid. * * If 'flow' is nonnull, then it should be the flow from a cls_rule that is * the matching rule for the learning action. This helps to better validate * the action's arguments. * * Modifies 'arg'. */ void learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow) { char *orig = xstrdup(arg); char *name, *value; enum ofperr error; size_t learn_ofs; size_t len; struct nx_action_learn *learn; struct cls_rule rule; learn_ofs = b->size; learn = ofputil_put_NXAST_LEARN(b); learn->idle_timeout = htons(OFP_FLOW_PERMANENT); learn->hard_timeout = htons(OFP_FLOW_PERMANENT); learn->priority = htons(OFP_DEFAULT_PRIORITY); learn->cookie = htonll(0); learn->flags = htons(0); learn->table_id = 1; cls_rule_init_catchall(&rule, 0); while (ofputil_parse_key_value(&arg, &name, &value)) { learn = ofpbuf_at_assert(b, learn_ofs, sizeof *learn); if (!strcmp(name, "table")) { learn->table_id = atoi(value); if (learn->table_id == 255) { ovs_fatal(0, "%s: table id 255 not valid for `learn' action", orig); } } else if (!strcmp(name, "priority")) { learn->priority = htons(atoi(value)); } else if (!strcmp(name, "idle_timeout")) { learn->idle_timeout = htons(atoi(value)); } else if (!strcmp(name, "hard_timeout")) { learn->hard_timeout = htons(atoi(value)); } else if (!strcmp(name, "fin_idle_timeout")) { learn->fin_idle_timeout = htons(atoi(value)); } else if (!strcmp(name, "fin_hard_timeout")) { learn->fin_hard_timeout = htons(atoi(value)); } else if (!strcmp(name, "cookie")) { learn->cookie = htonll(strtoull(value, NULL, 0)); } else { struct learn_spec spec; learn_parse_spec(orig, name, value, &spec); /* Check prerequisites. */ if (spec.src_type == NX_LEARN_SRC_FIELD && flow && !mf_are_prereqs_ok(spec.src.field, flow)) { ovs_fatal(0, "%s: cannot specify source field %s because " "prerequisites are not satisfied", orig, spec.src.field->name); } if ((spec.dst_type == NX_LEARN_DST_MATCH || spec.dst_type == NX_LEARN_DST_LOAD) && !mf_are_prereqs_ok(spec.dst.field, &rule.flow)) { ovs_fatal(0, "%s: cannot specify destination field %s because " "prerequisites are not satisfied", orig, spec.dst.field->name); } /* Update 'rule' to allow for satisfying destination * prerequisites. */ if (spec.src_type == NX_LEARN_SRC_IMMEDIATE && spec.dst_type == NX_LEARN_DST_MATCH) { mf_write_subfield(&spec.dst, &spec.src_imm, &rule); } /* Output the flow_mod_spec. */ put_u16(b, spec.n_bits | spec.src_type | spec.dst_type); if (spec.src_type == NX_LEARN_SRC_IMMEDIATE) { int n_bytes = DIV_ROUND_UP(spec.n_bits, 16) * 2; int ofs = sizeof spec.src_imm - n_bytes; ofpbuf_put(b, &spec.src_imm.u8[ofs], n_bytes); } else { put_u32(b, spec.src.field->nxm_header); put_u16(b, spec.src.ofs); } if (spec.dst_type == NX_LEARN_DST_MATCH || spec.dst_type == NX_LEARN_DST_LOAD) { put_u32(b, spec.dst.field->nxm_header); put_u16(b, spec.dst.ofs); } else { assert(spec.dst_type == NX_LEARN_DST_OUTPUT); } } } put_u16(b, 0); len = b->size - learn_ofs; if (len % 8) { ofpbuf_put_zeros(b, 8 - len % 8); } learn = ofpbuf_at_assert(b, learn_ofs, sizeof *learn); learn->len = htons(b->size - learn_ofs); /* In theory the above should have caught any errors, but... */ if (flow) { error = learn_check(learn, flow); if (error) { ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error)); } } free(orig); }
/* Updates the 'length' field of the OpenFlow message in 'buffer' to * 'buffer->size'. */ void update_openflow_length(struct ofpbuf *buffer) { struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); oh->length = htons(buffer->size); }
static int ofputil_pull_queue_get_config_reply10(struct ofpbuf *msg, struct ofputil_queue_config *queue) { const struct ofp_header *oh = msg->header; unsigned int opq_len; /* Length of protocol-specific queue header. */ unsigned int len; /* Total length of queue + properties. */ /* Obtain the port number from the message header. */ if (oh->version == OFP10_VERSION) { const struct ofp10_queue_get_config_reply *oqgcr10 = msg->msg; queue->port = u16_to_ofp(ntohs(oqgcr10->port)); } else { const struct ofp11_queue_get_config_reply *oqgcr11 = msg->msg; enum ofperr error = ofputil_port_from_ofp11(oqgcr11->port, &queue->port); if (error) { return error; } } /* Pull off the queue header and get the queue number and length. */ if (oh->version < OFP12_VERSION) { const struct ofp10_packet_queue *opq10; opq10 = ofpbuf_try_pull(msg, sizeof *opq10); if (!opq10) { return OFPERR_OFPBRC_BAD_LEN; } queue->queue = ntohl(opq10->queue_id); len = ntohs(opq10->len); opq_len = sizeof *opq10; } else { const struct ofp12_packet_queue *opq12; opq12 = ofpbuf_try_pull(msg, sizeof *opq12); if (!opq12) { return OFPERR_OFPBRC_BAD_LEN; } queue->queue = ntohl(opq12->queue_id); len = ntohs(opq12->len); opq_len = sizeof *opq12; } /* Length check. */ if (len < opq_len || len > msg->size + opq_len || len % 8) { return OFPERR_OFPBRC_BAD_LEN; } len -= opq_len; /* Pull properties. The format of these properties differs from used in * OF1.4+ so we can't use the common property functions. */ while (len > 0) { const struct ofp10_queue_prop_header *hdr; unsigned int property; unsigned int prop_len; enum ofperr error = 0; hdr = ofpbuf_at_assert(msg, 0, sizeof *hdr); prop_len = ntohs(hdr->len); if (prop_len < sizeof *hdr || prop_len > len || prop_len % 8) { return OFPERR_OFPBRC_BAD_LEN; } property = ntohs(hdr->property); switch (property) { case OFPQT10_MIN_RATE: error = parse_ofp10_queue_rate(hdr, &queue->min_rate); break; case OFPQT11_MAX_RATE: error = parse_ofp10_queue_rate(hdr, &queue->max_rate); break; default: VLOG_INFO_RL(&rl, "unknown queue property %u", property); break; } if (error) { return error; } ofpbuf_pull(msg, prop_len); len -= prop_len; } return 0; }