+
+ for (i = 0; i < n_handlers; i++) {
+ struct dpif_handler *handler = &dpif->handlers[i];
+
+ handler->event_offset = handler->n_events = 0;
+ }
+
+ keep_channels_nbits = dpif->uc_array_size;
+ keep_channels = bitmap_allocate(keep_channels_nbits);
+
+ ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub);
+ dpif_linux_port_dump_start__(dpif, &dump);
+ while (!dpif_linux_port_dump_next__(dpif, &dump, &vport, &buf)) {
+ uint32_t port_no = odp_to_u32(vport.port_no);
+ uint32_t *upcall_pids = NULL;
+ int error;
+
+ if (port_no >= dpif->uc_array_size
+ || !vport_get_pids(dpif, port_no, &upcall_pids)) {
+ struct nl_sock **socksp = vport_create_socksp(dpif->n_handlers,
+ &error);
+
+ if (!socksp) {
+ goto error;
+ }
+
+ error = vport_add_channels(dpif, vport.port_no, socksp);
+ if (error) {
+ VLOG_INFO("%s: could not add channels for port %s",
+ dpif_name(&dpif->dpif), vport.name);
+ vport_del_socksp(socksp, dpif->n_handlers);
+ retval = error;
+ goto error;
+ }
+ upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
+ free(socksp);
+ }
+
+ /* Configure the vport to deliver misses to 'sock'. */
+ if (vport.upcall_pids[0] == 0
+ || vport.n_upcall_pids != dpif->n_handlers
+ || memcmp(upcall_pids, vport.upcall_pids, n_handlers * sizeof
+ *upcall_pids)) {
+ 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 = vport.port_no;
+ vport_request.n_upcall_pids = dpif->n_handlers;
+ vport_request.upcall_pids = upcall_pids;
+ error = dpif_linux_vport_transact(&vport_request, NULL, NULL);
+ if (error) {
+ VLOG_WARN_RL(&error_rl,
+ "%s: failed to set upcall pid on port: %s",
+ dpif_name(&dpif->dpif), ovs_strerror(error));
+
+ if (error != ENODEV && error != ENOENT) {
+ retval = error;
+ } else {
+ /* The vport isn't really there, even though the dump says
+ * it is. Probably we just hit a race after a port
+ * disappeared. */
+ }
+ goto error;
+ }
+ }
+
+ if (port_no < keep_channels_nbits) {
+ bitmap_set1(keep_channels, port_no);
+ }
+ free(upcall_pids);
+ continue;
+
+ error:
+ free(upcall_pids);
+ vport_del_channels(dpif, vport.port_no);
+ }
+ nl_dump_done(&dump);
+ ofpbuf_uninit(&buf);
+
+ /* Discard any saved channels that we didn't reuse. */
+ for (i = 0; i < keep_channels_nbits; i++) {
+ if (!bitmap_is_set(keep_channels, i)) {
+ vport_del_channels(dpif, u32_to_odp(i));
+ }
+ }
+ free(keep_channels);
+
+ return retval;