+
+ free(socksp);
+}
+
+/* Creates an array of netlink sockets. Returns an array of the
+ * corresponding pointers. Records the error in 'error'. */
+static struct nl_sock **
+vport_create_socksp(uint32_t n_socks, int *error)
+{
+ struct nl_sock **socksp = xzalloc(n_socks * sizeof *socksp);
+ size_t i;
+
+ for (i = 0; i < n_socks; i++) {
+ *error = nl_sock_create(NETLINK_GENERIC, &socksp[i]);
+ if (*error) {
+ goto error;
+ }
+ }
+
+ return socksp;
+
+error:
+ vport_del_socksp(socksp, n_socks);
+
+ return NULL;
+}
+
+/* Given the array of pointers to netlink sockets 'socksp', returns
+ * the array of corresponding pids. If the 'socksp' is NULL, returns
+ * a single-element array of value 0. */
+static uint32_t *
+vport_socksp_to_pids(struct nl_sock **socksp, uint32_t n_socks)
+{
+ uint32_t *pids;
+
+ if (!socksp) {
+ pids = xzalloc(sizeof *pids);
+ } else {
+ size_t i;
+
+ pids = xzalloc(n_socks * sizeof *pids);
+ for (i = 0; i < n_socks; i++) {
+ pids[i] = nl_sock_pid(socksp[i]);
+ }
+ }
+
+ 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;
+ }
+