+ nl_msg_put_genlmsghdr(buf, 0, ovs_packet_family, NLM_F_REQUEST,
+ OVS_PACKET_CMD_EXECUTE, OVS_PACKET_VERSION);
+
+ execute = ofpbuf_put_uninit(buf, sizeof *execute);
+ execute->dp_ifindex = dp_ifindex;
+
+ nl_msg_put_unspec(buf, OVS_PACKET_ATTR_PACKET, packet->data, packet->size);
+ nl_msg_put_unspec(buf, OVS_PACKET_ATTR_KEY, key, key_len);
+ nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS, actions, actions_len);
+
+ return buf;
+}
+
+static int
+dpif_linux_execute__(int dp_ifindex, const struct nlattr *key, size_t key_len,
+ const struct nlattr *actions, size_t actions_len,
+ const struct ofpbuf *packet)
+{
+ struct ofpbuf *request;
+ int error;
+
+ request = dpif_linux_encode_execute(dp_ifindex,
+ key, key_len, actions, actions_len,
+ packet);
+ error = nl_sock_transact(genl_sock, request, NULL);
+ ofpbuf_delete(request);
+
+ return error;
+}
+
+static int
+dpif_linux_execute(struct dpif *dpif_,
+ const struct nlattr *key, size_t key_len,
+ const struct nlattr *actions, size_t actions_len,
+ const struct ofpbuf *packet)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+
+ return dpif_linux_execute__(dpif->dp_ifindex, key, key_len,
+ actions, actions_len, packet);
+}
+
+static void
+dpif_linux_operate(struct dpif *dpif_, union dpif_op **ops, size_t n_ops)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+ struct nl_transaction **txnsp;
+ struct nl_transaction *txns;
+ size_t i;
+
+ txns = xmalloc(n_ops * sizeof *txns);
+ for (i = 0; i < n_ops; i++) {
+ struct nl_transaction *txn = &txns[i];
+ union dpif_op *op = ops[i];
+
+ if (op->type == DPIF_OP_FLOW_PUT) {
+ struct dpif_flow_put *put = &op->flow_put;
+ struct dpif_linux_flow request;
+
+ dpif_linux_init_flow_put(dpif_, put->flags, put->key, put->key_len,
+ put->actions, put->actions_len,
+ &request);
+ if (put->stats) {
+ request.nlmsg_flags |= NLM_F_ECHO;
+ }
+ txn->request = ofpbuf_new(1024);
+ dpif_linux_flow_to_ofpbuf(&request, txn->request);
+ } else if (op->type == DPIF_OP_EXECUTE) {
+ struct dpif_execute *execute = &op->execute;
+
+ txn->request = dpif_linux_encode_execute(
+ dpif->dp_ifindex, execute->key, execute->key_len,
+ execute->actions, execute->actions_len, execute->packet);
+ } else {
+ NOT_REACHED();
+ }
+ }
+
+ txnsp = xmalloc(n_ops * sizeof *txnsp);
+ for (i = 0; i < n_ops; i++) {
+ txnsp[i] = &txns[i];
+ }
+
+ nl_sock_transact_multiple(genl_sock, txnsp, n_ops);
+
+ free(txnsp);
+
+ for (i = 0; i < n_ops; i++) {
+ struct nl_transaction *txn = &txns[i];
+ union dpif_op *op = ops[i];
+
+ if (op->type == DPIF_OP_FLOW_PUT) {
+ struct dpif_flow_put *put = &op->flow_put;
+ int error = txn->error;
+
+ if (!error && put->stats) {
+ struct dpif_linux_flow reply;
+
+ error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
+ if (!error) {
+ dpif_linux_flow_get_stats(&reply, put->stats);
+ }
+ }
+ put->error = error;
+ } else if (op->type == DPIF_OP_EXECUTE) {
+ struct dpif_execute *execute = &op->execute;
+
+ execute->error = txn->error;
+ } else {
+ NOT_REACHED();
+ }
+
+ ofpbuf_delete(txn->request);
+ ofpbuf_delete(txn->reply);
+ }
+ free(txns);
+}
+
+static int
+dpif_linux_recv_get_mask(const struct dpif *dpif_, int *listen_mask)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+ *listen_mask = dpif->listen_mask;
+ return 0;
+}
+
+static void
+set_upcall_pids(struct dpif *dpif_)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+ struct dpif_port_dump port_dump;
+ struct dpif_port port;
+ int error;
+
+ DPIF_PORT_FOR_EACH (&port, &port_dump, &dpif->dpif) {
+ uint32_t upcall_pid = dpif_linux_port_get_pid__(dpif_, port.port_no,
+ DPIF_UC_MISS);
+ struct dpif_linux_vport vport_request;
+
+ dpif_linux_vport_init(&vport_request);
+ vport_request.cmd = OVS_VPORT_CMD_SET;
+ vport_request.dp_ifindex = dpif->dp_ifindex;
+ vport_request.port_no = port.port_no;
+ vport_request.upcall_pid = &upcall_pid;
+ error = dpif_linux_vport_transact(&vport_request, NULL, NULL);
+ if (!error) {
+ VLOG_DBG("%s: assigning port %"PRIu32" to netlink pid %"PRIu32,
+ dpif_name(&dpif->dpif), vport_request.port_no,
+ upcall_pid);
+ } else {
+ VLOG_WARN_RL(&error_rl, "%s: failed to set upcall pid on port: %s",
+ dpif_name(&dpif->dpif), strerror(error));
+ }
+ }
+}
+
+static int
+dpif_linux_recv_set_mask(struct dpif *dpif_, int listen_mask)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+
+ if (listen_mask == dpif->listen_mask) {
+ return 0;
+ }
+
+ if (!listen_mask) {
+ destroy_upcall_socks(dpif);
+ } else if (!dpif->listen_mask) {
+ int i;
+ int error;
+
+ for (i = 0; i < N_UPCALL_SOCKS; i++) {
+ error = nl_sock_create(NETLINK_GENERIC, &dpif->upcall_socks[i]);
+ if (error) {
+ destroy_upcall_socks(dpif);
+ return error;
+ }