+
+ return pids;
+}
+
+/* Given the port number 'port_idx', extracts the pids of netlink sockets
+ * associated to the port and assigns it to 'upcall_pids'. */
+static bool
+vport_get_pids(struct dpif_linux *dpif, uint32_t port_idx,
+ uint32_t **upcall_pids)
+{
+ uint32_t *pids;
+ size_t i;
+
+ /* Since the nl_sock can only be assigned in either all
+ * or none "dpif->handlers" channels, the following check
+ * would suffice. */
+ if (!dpif->handlers[0].channels[port_idx].sock) {
+ return false;
+ }
+
+ pids = xzalloc(dpif->n_handlers * sizeof *pids);
+
+ for (i = 0; i < dpif->n_handlers; i++) {
+ pids[i] = nl_sock_pid(dpif->handlers[i].channels[port_idx].sock);
+ }
+
+ *upcall_pids = pids;
+
+ return true;
+}
+
+static int
+vport_add_channels(struct dpif_linux *dpif, odp_port_t port_no,
+ struct nl_sock **socksp)
+{
+ struct epoll_event event;
+ uint32_t port_idx = odp_to_u32(port_no);
+ size_t i, j;
+ int error;
+
+ if (dpif->handlers == NULL) {
+ return 0;
+ }
+
+ /* We assume that the datapath densely chooses port numbers, which can
+ * therefore be used as an index into 'channels' and 'epoll_events' of
+ * 'dpif->handler'. */
+ if (port_idx >= dpif->uc_array_size) {
+ uint32_t new_size = port_idx + 1;
+
+ if (new_size > MAX_PORTS) {
+ VLOG_WARN_RL(&error_rl, "%s: datapath port %"PRIu32" too big",
+ dpif_name(&dpif->dpif), port_no);
+ return EFBIG;
+ }
+
+ for (i = 0; i < dpif->n_handlers; i++) {
+ struct dpif_handler *handler = &dpif->handlers[i];
+
+ handler->channels = xrealloc(handler->channels,
+ new_size * sizeof *handler->channels);
+
+ for (j = dpif->uc_array_size; j < new_size; j++) {
+ handler->channels[j].sock = NULL;
+ }
+
+ handler->epoll_events = xrealloc(handler->epoll_events,
+ new_size * sizeof *handler->epoll_events);
+
+ }
+ dpif->uc_array_size = new_size;
+ }
+
+ memset(&event, 0, sizeof event);
+ event.events = EPOLLIN;
+ event.data.u32 = port_idx;
+
+ for (i = 0; i < dpif->n_handlers; i++) {
+ struct dpif_handler *handler = &dpif->handlers[i];
+
+ if (epoll_ctl(handler->epoll_fd, EPOLL_CTL_ADD, nl_sock_fd(socksp[i]),
+ &event) < 0) {
+ error = errno;
+ goto error;
+ }
+ dpif->handlers[i].channels[port_idx].sock = socksp[i];
+ dpif->handlers[i].channels[port_idx].last_poll = LLONG_MIN;
+ }
+
+ return 0;
+
+error:
+ for (j = 0; j < i; j++) {
+ epoll_ctl(dpif->handlers[j].epoll_fd, EPOLL_CTL_DEL,
+ nl_sock_fd(socksp[j]), NULL);
+ dpif->handlers[j].channels[port_idx].sock = NULL;
+ }
+
+ return error;
+}
+
+static void
+vport_del_channels(struct dpif_linux *dpif, odp_port_t port_no)
+{
+ uint32_t port_idx = odp_to_u32(port_no);
+ size_t i;
+
+ if (!dpif->handlers || port_idx >= dpif->uc_array_size) {
+ return;
+ }
+
+ /* Since the sock can only be assigned in either all or none
+ * of "dpif->handlers" channels, the following check would
+ * suffice. */
+ if (!dpif->handlers[0].channels[port_idx].sock) {
+ return;
+ }
+
+ for (i = 0; i < dpif->n_handlers; i++) {
+ struct dpif_handler *handler = &dpif->handlers[i];
+
+ epoll_ctl(handler->epoll_fd, EPOLL_CTL_DEL,
+ nl_sock_fd(handler->channels[port_idx].sock), NULL);
+ nl_sock_destroy(handler->channels[port_idx].sock);
+ handler->channels[port_idx].sock = NULL;
+ handler->event_offset = handler->n_events = 0;