- LIST_FOR_EACH (port, node, &dp->port_list) {
- netdev_recv_wait(port->netdev);
- }
-}
-
-static void
-dp_netdev_set_dl(struct ofpbuf *packet, const struct ovs_key_ethernet *eth_key)
-{
- struct eth_header *eh = packet->l2;
-
- memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src);
- memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst);
-}
-
-static void
-dp_netdev_set_ip_addr(struct ofpbuf *packet, ovs_be32 *addr, ovs_be32 new_addr)
-{
- struct ip_header *nh = packet->l3;
-
- if (nh->ip_proto == IPPROTO_TCP && packet->l7) {
- struct tcp_header *th = packet->l4;
- th->tcp_csum = recalc_csum32(th->tcp_csum, *addr, new_addr);
- } else if (nh->ip_proto == IPPROTO_UDP && packet->l7) {
- struct udp_header *uh = packet->l4;
- if (uh->udp_csum) {
- uh->udp_csum = recalc_csum32(uh->udp_csum, *addr, new_addr);
- if (!uh->udp_csum) {
- uh->udp_csum = htons(0xffff);
- }
- }
- }
- nh->ip_csum = recalc_csum32(nh->ip_csum, *addr, new_addr);
- *addr = new_addr;
-}
-
-static void
-dp_netdev_set_ip_tos(struct ip_header *nh, uint8_t new_tos)
-{
- uint8_t *field = &nh->ip_tos;
-
- nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
- htons((uint16_t) new_tos));
- *field = new_tos;
-}
-
-static void
-dp_netdev_set_ip_ttl(struct ip_header *nh, uint8_t new_ttl)
-{
- uint8_t *field = &nh->ip_ttl;
-
- nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8),
- htons(new_ttl << 8));
- *field = new_ttl;
-}
-
-static void
-dp_netdev_set_ipv4(struct ofpbuf *packet, const struct ovs_key_ipv4 *ipv4_key)
-{
- struct ip_header *nh = packet->l3;
-
- if (nh->ip_src != ipv4_key->ipv4_src) {
- dp_netdev_set_ip_addr(packet, &nh->ip_src, ipv4_key->ipv4_src);
- }
- if (nh->ip_dst != ipv4_key->ipv4_dst) {
- dp_netdev_set_ip_addr(packet, &nh->ip_dst, ipv4_key->ipv4_dst);
- }
- if (nh->ip_tos != ipv4_key->ipv4_tos) {
- dp_netdev_set_ip_tos(nh, ipv4_key->ipv4_tos);
- }
- if (nh->ip_ttl != ipv4_key->ipv4_ttl) {
- dp_netdev_set_ip_ttl(nh, ipv4_key->ipv4_ttl);
- }
-}
-
-static void
-dp_netdev_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum)
-{
- *csum = recalc_csum16(*csum, *port, new_port);
- *port = new_port;
-}
-
-static void
-dp_netdev_set_tcp_port(struct ofpbuf *packet, const struct ovs_key_tcp *tcp_key)
-{
- struct tcp_header *th = packet->l4;
-
- if (th->tcp_src != tcp_key->tcp_src) {
- dp_netdev_set_port(&th->tcp_src, tcp_key->tcp_src, &th->tcp_csum);
- }
- if (th->tcp_dst != tcp_key->tcp_dst) {
- dp_netdev_set_port(&th->tcp_dst, tcp_key->tcp_dst, &th->tcp_csum);
- }
-}
-
-static void
-dp_netdev_set_udp_port(struct ofpbuf *packet, const struct ovs_key_udp *udp_key)
-{
- struct udp_header *uh = packet->l4;
-
- if (uh->udp_csum) {
- if (uh->udp_src != udp_key->udp_src) {
- dp_netdev_set_port(&uh->udp_src, udp_key->udp_src, &uh->udp_csum);
- }
-
- if (uh->udp_dst != udp_key->udp_dst) {
- dp_netdev_set_port(&uh->udp_dst, udp_key->udp_dst, &uh->udp_csum);
+ /* There is a race here, if thread A calls dpif_netdev_wait(dpif) and
+ * thread B calls dpif_port_add(dpif) or dpif_port_remove(dpif) before
+ * A makes it to poll_block().
+ *
+ * But I think it doesn't matter:
+ *
+ * - In the dpif_port_add() case, A will not wake up when a packet
+ * arrives on the new port, but this would also happen if the
+ * ordering were reversed.
+ *
+ * - In the dpif_port_remove() case, A might wake up spuriously, but
+ * that is harmless. */
+
+ ovs_mutex_lock(&dp_netdev_mutex);
+ LIST_FOR_EACH (port, node, &get_dp_netdev(dpif)->port_list) {
+ if (port->rx) {
+ netdev_rx_wait(port->rx);