+static uint32_t
+get_upcall_pid_port__(struct dpif_linux *dpif, uint32_t port)
+{
+ int idx = port & (N_UPCALL_SOCKS - 1);
+ return nl_sock_pid(dpif->upcall_socks[idx]);
+}
+
+static uint32_t
+get_upcall_pid_port(struct dpif_linux *dpif, uint32_t port)
+{
+ if (!(dpif->listen_mask & (1u << DPIF_UC_MISS))) {
+ return 0;
+ }
+
+ return get_upcall_pid_port__(dpif, port);
+}
+
+static uint32_t
+get_upcall_pid_flow(struct dpif_linux *dpif,
+ const struct nlattr *key, size_t key_len)
+{
+ const struct nlattr *nla;
+ uint32_t port;
+
+ if (!(dpif->listen_mask &
+ ((1u << DPIF_UC_ACTION) | (1u << DPIF_UC_SAMPLE)))) {
+ return 0;
+ }
+
+ nla = nl_attr_find__(key, key_len, OVS_KEY_ATTR_IN_PORT);
+ if (nla) {
+ port = nl_attr_get_u32(nla);
+ } else {
+ port = random_uint32();
+ }
+
+ return get_upcall_pid_port__(dpif, port);
+}
+
+static void
+set_upcall_pids(struct dpif_linux *dpif)
+{
+ struct dpif_port port;
+ struct dpif_port_dump port_dump;
+ struct dpif_flow_dump flow_dump;
+ const struct nlattr *key;
+ size_t key_len;
+ int error;
+
+ DPIF_PORT_FOR_EACH (&port, &port_dump, &dpif->dpif) {
+ 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 = get_upcall_pid_port(dpif,
+ vport_request.port_no);
+ 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,
+ vport_request.upcall_pid);
+ } else {
+ VLOG_WARN_RL(&error_rl, "%s: failed to set upcall pid on port: %s",
+ dpif_name(&dpif->dpif), strerror(error));
+ }
+ }
+
+ dpif_flow_dump_start(&flow_dump, &dpif->dpif);
+ while (dpif_flow_dump_next(&flow_dump, &key, &key_len,
+ NULL, NULL, NULL)) {
+ struct dpif_linux_flow flow_request;
+
+ dpif_linux_flow_init(&flow_request);
+ flow_request.cmd = OVS_FLOW_CMD_SET;
+ flow_request.dp_ifindex = dpif->dp_ifindex;
+ flow_request.key = key;
+ flow_request.key_len = key_len;
+ flow_request.upcall_pid = get_upcall_pid_flow(dpif, key, key_len);
+ error = dpif_linux_flow_transact(&flow_request, NULL, NULL);
+ if (error) {
+ VLOG_WARN_RL(&error_rl, "%s: failed to set upcall pid on flow: %s",
+ dpif_name(&dpif->dpif), strerror(error));
+ }
+ }
+ dpif_flow_dump_done(&flow_dump);
+}
+