/* Schedules 'msg' to be sent on 'rpc' and returns 'rpc''s status (as with * jsonrpc_get_status()). * * If 'msg' cannot be sent immediately, it is appended to a buffer. The caller * is responsible for ensuring that the amount of buffered data is somehow * limited. (jsonrpc_get_backlog() returns the amount of data currently * buffered in 'rpc'.) * * Always takes ownership of 'msg', regardless of success. */ int jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg) { struct ofpbuf *buf; struct json *json; size_t length; char *s; if (rpc->status) { jsonrpc_msg_destroy(msg); return rpc->status; } jsonrpc_log_msg(rpc, "send", msg); json = jsonrpc_msg_to_json(msg); s = json_to_string(json, 0); length = strlen(s); json_destroy(json); buf = xmalloc(sizeof *buf); ofpbuf_use(buf, s, length); buf->size = length; list_push_back(&rpc->output, &buf->list_node); rpc->backlog += length; if (rpc->backlog == length) { jsonrpc_run(rpc); } return rpc->status; }
/* 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; }
/* Schedules 'msg' to be sent on 'rpc' and returns 'rpc''s status (as with * jsonrpc_get_status()). * * If 'msg' cannot be sent immediately, it is appended to a buffer. The caller * is responsible for ensuring that the amount of buffered data is somehow * limited. (jsonrpc_get_backlog() returns the amount of data currently * buffered in 'rpc'.) * * Always takes ownership of 'msg', regardless of success. */ int jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg) { struct ofpbuf *buf; struct json *json; size_t length; char *s; if (rpc->status) { jsonrpc_msg_destroy(msg); return rpc->status; } jsonrpc_log_msg(rpc, "send", msg); json = jsonrpc_msg_to_json(msg); s = json_to_string(json, 0); length = strlen(s); json_destroy(json); buf = xmalloc(sizeof *buf); ofpbuf_use(buf, s, length); buf->size = length; list_push_back(&rpc->output, &buf->list_node); rpc->output_count++; rpc->backlog += length; if (rpc->output_count >= 50) { VLOG_INFO_RL(&rl, "excessive sending backlog, jsonrpc: %s, num of" " msgs: %"PRIuSIZE", backlog: %"PRIuSIZE".", rpc->name, rpc->output_count, rpc->backlog); } if (rpc->backlog == length) { jsonrpc_run(rpc); } return rpc->status; }
/* Initializes 'b' as an empty ofpbuf with an initial capacity of 'size' * bytes. */ void ofpbuf_init(struct ofpbuf *b, size_t size) { ofpbuf_use(b, size ? xmalloc(size) : NULL, size); }