diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 2a7d5ec..77b9bc5 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -532,17 +532,19 @@ static int enter_netns(struct netns_knob *netns_knob, const char *netns);
 static void exit_netns(struct netns_knob *netns_knob);
 static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *,
                                    int cmd, const char *cmd_name);
-static int get_flags(const struct netdev *, unsigned int *flags);
-static int set_flags(const char *, unsigned int flags);
+static int get_flags(const struct netdev *, unsigned int *flags,
+                     bool is_tap_in_netns);
+static int set_flags(const char *, unsigned int flags, bool is_tap_in_netns);
 static int update_flags(struct netdev_linux *netdev, enum netdev_flags off,
-                        enum netdev_flags on, enum netdev_flags *old_flagsp)
+                        enum netdev_flags on, enum netdev_flags *old_flagsp,
+                        bool is_tap_in_netns)
     OVS_REQUIRES(netdev->mutex);
 static int get_ifindex(const struct netdev *, int *ifindexp);
 static int do_set_addr(struct netdev *netdev,
                        int ioctl_nr, const char *ioctl_name,
-                       struct in_addr addr);
-static int get_etheraddr(const char *netdev_name, struct eth_addr *ea);
-static int set_etheraddr(const char *netdev_name, const struct eth_addr);
+                       struct in_addr addr, bool is_tap_in_netns);
+static int get_etheraddr(const struct netdev *netdev_, struct eth_addr *ea);
+static int set_etheraddr(const struct netdev *netdev_, const struct eth_addr);
 static int af_packet_sock(void);
 static bool netdev_linux_miimon_enabled(void);
 static void netdev_linux_miimon_run(void);
@@ -791,13 +793,24 @@ netdev_linux_run(const struct netdev_class *netdev_class OVS_UNUSED)
                 struct netdev *netdev_ = node->data;
                 struct netdev_linux *netdev = netdev_linux_cast(netdev_);
                 unsigned int flags;
+                struct netns_knob netns_knob;
+                bool is_tap_in_netns = false;
+
+                if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+                    is_tap_in_netns = true;
+                    enter_netns(&netns_knob, netdev->netns);
+                }
 
                 ovs_mutex_lock(&netdev->mutex);
-                get_flags(netdev_, &flags);
+                get_flags(netdev_, &flags, is_tap_in_netns);
                 netdev_linux_changed(netdev, flags, 0);
                 ovs_mutex_unlock(&netdev->mutex);
 
                 netdev_close(netdev_);
+
+                if (is_tap_in_netns) {
+                    exit_netns(&netns_knob);
+                }
             }
             shash_destroy(&device_shash);
         } else if (error != EAGAIN) {
@@ -952,7 +965,7 @@ netdev_linux_construct(struct netdev *netdev_)
         return error;
     }
 
-    error = get_flags(&netdev->up, &netdev->ifi_flags);
+    error = get_flags(&netdev->up, &netdev->ifi_flags, false);
     if (error == ENODEV) {
         if (netdev->up.netdev_class != &netdev_internal_class) {
             /* The device does not exist, so don't allow it to be opened. */
@@ -996,7 +1009,7 @@ netdev_linux_construct_tap(struct netdev *netdev_)
     }
 
     /* Create tap device. */
-    get_flags(&netdev->up, &netdev->ifi_flags);
+    get_flags(&netdev->up, &netdev->ifi_flags, false);
     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
     if (userspace_tso_enabled()) {
         ifr.ifr_flags |= IFF_VNET_HDR;
@@ -1528,10 +1541,30 @@ static int
 netdev_linux_rxq_drain(struct netdev_rxq *rxq_)
 {
     struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
+    struct netdev *netdev_ = netdev_rxq_get_netdev(&rx->up);
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        enter_netns(&netns_knob, netdev->netns);
+    }
+
     if (rx->is_tap) {
         struct ifreq ifr;
-        int error = af_inet_ifreq_ioctl(netdev_rxq_get_name(rxq_), &ifr,
+        int error;
+        if (is_tap_in_netns) {
+            error = af_inet_ifreq_ioctl_netns(netdev_rxq_get_name(rxq_),
+                                              &ifr,
+                                              SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
+        } else {
+            error = af_inet_ifreq_ioctl(netdev_rxq_get_name(rxq_), &ifr,
                                         SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
+        }
+        if (is_tap_in_netns) {
+            exit_netns(&netns_knob);
+        }
         if (error) {
             return error;
         }
@@ -1790,6 +1823,13 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     enum netdev_flags old_flags = 0;
     int error;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     if (netdev_linux_netnsid_is_remote(netdev)) {
@@ -1807,9 +1847,9 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
 
     /* Tap devices must be brought down before setting the address. */
     if (is_tap_netdev(netdev_)) {
-        update_flags(netdev, NETDEV_UP, 0, &old_flags);
+        update_flags(netdev, NETDEV_UP, 0, &old_flags, is_tap_in_netns);
     }
-    error = set_etheraddr(netdev_get_name(netdev_), mac);
+    error = set_etheraddr(netdev_, mac);
     if (!error || error == ENODEV) {
         netdev->ether_addr_error = error;
         netdev->cache_valid |= VALID_ETHERADDR;
@@ -1819,11 +1859,16 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
     }
 
     if (is_tap_netdev(netdev_) && old_flags & NETDEV_UP) {
-        update_flags(netdev, 0, NETDEV_UP, &old_flags);
+        update_flags(netdev, 0, NETDEV_UP, &old_flags, is_tap_in_netns);
     }
 
 exit:
     ovs_mutex_unlock(&netdev->mutex);
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
@@ -1833,6 +1878,13 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     int error;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     if (!(netdev->cache_valid & VALID_ETHERADDR)) {
@@ -1841,17 +1893,23 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
 
     if (!(netdev->cache_valid & VALID_ETHERADDR)) {
         /* Fall back to ioctl if netlink fails */
-        netdev->ether_addr_error = get_etheraddr(netdev_get_name(netdev_),
-                                                 &netdev->etheraddr);
-        netdev->cache_valid |= VALID_ETHERADDR;
+        netdev->ether_addr_error = get_etheraddr(netdev_, &netdev->etheraddr);
+        if (!netdev->ether_addr_error) {
+            netdev->cache_valid |= VALID_ETHERADDR;
+        }
     }
 
     error = netdev->ether_addr_error;
+
     if (!error) {
         *mac = netdev->etheraddr;
     }
     ovs_mutex_unlock(&netdev->mutex);
 
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
@@ -1859,6 +1917,11 @@ static int
 netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup)
 {
     int error;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(&netdev->up) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+    }
 
     if (!(netdev->cache_valid & VALID_MTU)) {
         netdev_linux_update_via_netlink(netdev);
@@ -1868,8 +1931,13 @@ netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup)
         /* Fall back to ioctl if netlink fails */
         struct ifreq ifr;
 
-        netdev->netdev_mtu_error = af_inet_ifreq_ioctl(
-            netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU");
+        if (is_tap_in_netns) {
+            netdev->netdev_mtu_error = af_inet_ifreq_ioctl_netns(
+                netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU");
+        } else {
+            netdev->netdev_mtu_error = af_inet_ifreq_ioctl(
+                netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU");
+        }
         netdev->mtu = ifr.ifr_mtu;
         netdev->cache_valid |= VALID_MTU;
     }
@@ -1890,11 +1958,22 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     int error;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     error = netdev_linux_get_mtu__(netdev, mtup);
     ovs_mutex_unlock(&netdev->mutex);
 
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
@@ -1907,6 +1986,13 @@ netdev_linux_set_mtu(struct netdev *netdev_, int mtu)
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     struct ifreq ifr;
     int error;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     if (netdev_linux_netnsid_is_remote(netdev)) {
@@ -1931,8 +2017,13 @@ netdev_linux_set_mtu(struct netdev *netdev_, int mtu)
         netdev->cache_valid &= ~VALID_MTU;
     }
     ifr.ifr_mtu = mtu;
-    error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
-                                SIOCSIFMTU, "SIOCSIFMTU");
+    if (is_tap_in_netns) {
+        error = af_inet_ifreq_ioctl_netns(netdev_get_name(netdev_), &ifr,
+                                          SIOCSIFMTU, "SIOCSIFMTU");
+    } else {
+        error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
+                                    SIOCSIFMTU, "SIOCSIFMTU");
+    }
     if (!error || error == ENODEV) {
         netdev->netdev_mtu_error = error;
         netdev->mtu = ifr.ifr_mtu;
@@ -1940,6 +2031,11 @@ netdev_linux_set_mtu(struct netdev *netdev_, int mtu)
     }
 exit:
     ovs_mutex_unlock(&netdev->mutex);
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
@@ -1994,39 +2090,58 @@ netdev_linux_get_carrier_resets(const struct netdev *netdev_)
 
 static int
 netdev_linux_do_miimon(const char *name, int cmd, const char *cmd_name,
-                       struct mii_ioctl_data *data)
+                       struct mii_ioctl_data *data, bool is_tap_in_netns)
 {
     struct ifreq ifr;
     int error;
 
     memset(&ifr, 0, sizeof ifr);
     memcpy(&ifr.ifr_data, data, sizeof *data);
-    error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name);
+    if (is_tap_in_netns) {
+        error = af_inet_ifreq_ioctl_netns(name, &ifr, cmd, cmd_name);
+    } else {
+        error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name);
+    }
     memcpy(data, &ifr.ifr_data, sizeof *data);
 
     return error;
 }
 
 static int
-netdev_linux_get_miimon(const char *name, bool *miimon)
+netdev_linux_get_miimon(const struct netdev *netdev_, bool *miimon)
 {
     struct mii_ioctl_data data;
     int error;
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+    const char *name = netdev_get_name(netdev_);
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
 
     *miimon = false;
 
     memset(&data, 0, sizeof data);
-    error = netdev_linux_do_miimon(name, SIOCGMIIPHY, "SIOCGMIIPHY", &data);
+    error = netdev_linux_do_miimon(name, SIOCGMIIPHY, "SIOCGMIIPHY", &data,
+                                   is_tap_in_netns);
     if (!error) {
         /* data.phy_id is filled out by previous SIOCGMIIPHY miimon call. */
         data.reg_num = MII_BMSR;
         error = netdev_linux_do_miimon(name, SIOCGMIIREG, "SIOCGMIIREG",
-                                       &data);
+                                       &data, is_tap_in_netns);
 
         if (!error) {
             *miimon = !!(data.val_out & BMSR_LSTATUS);
         }
     }
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     if (error) {
         struct ethtool_cmd ecmd;
 
@@ -2088,7 +2203,7 @@ netdev_linux_miimon_run(void)
 
         ovs_mutex_lock(&dev->mutex);
         if (dev->miimon_interval > 0 && timer_expired(&dev->miimon_timer)) {
-            netdev_linux_get_miimon(dev->up.name, &miimon);
+            netdev_linux_get_miimon(netdev, &miimon);
             if (miimon != dev->miimon) {
                 dev->miimon = miimon;
                 netdev_linux_changed(dev, dev->ifi_flags, 0);
@@ -2515,7 +2630,9 @@ netdev_linux_read_features(struct netdev_linux *netdev)
     }
 
 out:
-    netdev->cache_valid |= VALID_FEATURES;
+    if (!error) {
+        netdev->cache_valid |= VALID_FEATURES;
+    }
     netdev->get_features_error = error;
 }
 
@@ -3243,6 +3360,13 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     int error;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     if (netdev_linux_netnsid_is_remote(netdev)) {
@@ -3250,16 +3374,22 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
         goto exit;
     }
 
-    error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address);
+    error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address,
+                        is_tap_in_netns);
     if (!error) {
         if (address.s_addr != INADDR_ANY) {
             error = do_set_addr(netdev_, SIOCSIFNETMASK,
-                                "SIOCSIFNETMASK", netmask);
+                                "SIOCSIFNETMASK", netmask, is_tap_in_netns);
         }
     }
 
 exit:
     ovs_mutex_unlock(&netdev->mutex);
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
@@ -3301,13 +3431,19 @@ make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr)
 
 static int
 do_set_addr(struct netdev *netdev,
-            int ioctl_nr, const char *ioctl_name, struct in_addr addr)
+            int ioctl_nr, const char *ioctl_name, struct in_addr addr,
+            bool is_tap_in_netns)
 {
     struct ifreq ifr;
 
     make_in4_sockaddr(&ifr.ifr_addr, addr);
-    return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr,
-                               ioctl_name);
+    if (is_tap_in_netns) {
+        return af_inet_ifreq_ioctl_netns(netdev_get_name(netdev), &ifr,
+                                         ioctl_nr, ioctl_name);
+    } else {
+        return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr,
+                                   ioctl_name);
+    }
 }
 
 /* Adds 'router' as a default IP gateway. */
@@ -3434,6 +3570,13 @@ netdev_linux_get_block_id(struct netdev *netdev_)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     uint32_t block_id = 0;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     /* Ensure the linux netdev has had its fields populated. */
@@ -3447,6 +3590,10 @@ netdev_linux_get_block_id(struct netdev *netdev_)
     }
     ovs_mutex_unlock(&netdev->mutex);
 
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return block_id;
 }
 
@@ -3517,7 +3664,8 @@ iff_to_nd_flags(unsigned int iff)
 
 static int
 update_flags(struct netdev_linux *netdev, enum netdev_flags off,
-             enum netdev_flags on, enum netdev_flags *old_flagsp)
+             enum netdev_flags on, enum netdev_flags *old_flagsp,
+             bool is_tap_in_netns)
     OVS_REQUIRES(netdev->mutex)
 {
     unsigned int old_flags, new_flags;
@@ -3527,8 +3675,9 @@ update_flags(struct netdev_linux *netdev, enum netdev_flags off,
     *old_flagsp = iff_to_nd_flags(old_flags);
     new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
     if (new_flags != old_flags) {
-        error = set_flags(netdev_get_name(&netdev->up), new_flags);
-        get_flags(&netdev->up, &netdev->ifi_flags);
+        error = set_flags(netdev_get_name(&netdev->up), new_flags,
+                          is_tap_in_netns);
+        get_flags(&netdev->up, &netdev->ifi_flags, is_tap_in_netns);
     }
 
     return error;
@@ -3540,6 +3689,13 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     int error = 0;
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
 
     ovs_mutex_lock(&netdev->mutex);
     if (on || off) {
@@ -3548,18 +3704,23 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
             error = EOPNOTSUPP;
             goto exit;
         }
-        error = update_flags(netdev, off, on, old_flagsp);
+        error = update_flags(netdev, off, on, old_flagsp, is_tap_in_netns);
     } else {
         /* Try reading flags over netlink, or fall back to ioctl. */
         if (!netdev_linux_update_via_netlink(netdev)) {
             *old_flagsp = iff_to_nd_flags(netdev->ifi_flags);
         } else {
-            error = update_flags(netdev, off, on, old_flagsp);
+            error = update_flags(netdev, off, on, old_flagsp, is_tap_in_netns);
         }
     }
 
 exit:
     ovs_mutex_unlock(&netdev->mutex);
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
@@ -6346,13 +6507,19 @@ get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats)
 }
 
 static int
-get_flags(const struct netdev *dev, unsigned int *flags)
+get_flags(const struct netdev *dev, unsigned int *flags, bool is_tap_in_netns)
 {
     struct ifreq ifr;
     int error;
 
     *flags = 0;
-    error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS");
+    if (is_tap_in_netns) {
+        error = af_inet_ifreq_ioctl_netns(dev->name, &ifr, SIOCGIFFLAGS,
+                                          "SIOCGIFFLAGS");
+    } else {
+        error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS,
+                                    "SIOCGIFFLAGS");
+    }
     if (!error) {
         *flags = ifr.ifr_flags;
     }
@@ -6360,12 +6527,17 @@ get_flags(const struct netdev *dev, unsigned int *flags)
 }
 
 static int
-set_flags(const char *name, unsigned int flags)
+set_flags(const char *name, unsigned int flags, bool is_tap_in_netns)
 {
     struct ifreq ifr;
 
     ifr.ifr_flags = flags;
-    return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
+    if (is_tap_in_netns) {
+        return af_inet_ifreq_ioctl_netns(name, &ifr, SIOCSIFFLAGS,
+                                         "SIOCSIFFLAGS");
+    } else {
+        return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS");
+    }
 }
 
 int
@@ -6394,6 +6566,13 @@ static int
 get_ifindex(const struct netdev *netdev_, int *ifindexp)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        enter_netns(&netns_knob, netdev->netns);
+    }
 
     if (!(netdev->cache_valid & VALID_IFINDEX)) {
         netdev_linux_update_via_netlink(netdev);
@@ -6414,6 +6593,11 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp)
     }
 
     *ifindexp = netdev->ifindex;
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return netdev->get_ifindex_error;
 }
 
@@ -6425,6 +6609,11 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev)
     struct rtnetlink_change chg;
     struct rtnetlink_change *change = &chg;
     int error;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(&netdev->up) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+    }
 
     ofpbuf_init(&request, 0);
     nl_msg_put_nlmsghdr(&request,
@@ -6439,7 +6628,11 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev)
     if (netdev_linux_netnsid_is_remote(netdev)) {
         nl_msg_put_u32(&request, IFLA_IF_NETNSID, netdev->netnsid);
     }
-    error = nl_transact(NETLINK_ROUTE, &request, &reply);
+    if (is_tap_in_netns) {
+        error = nl_transact_nopool(NETLINK_ROUTE, &request, &reply);
+    } else {
+        error = nl_transact(NETLINK_ROUTE, &request, &reply);
+    }
     ofpbuf_uninit(&request);
     if (error) {
         ofpbuf_delete(reply);
@@ -6494,16 +6687,27 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev)
 }
 
 static int
-get_etheraddr(const char *netdev_name, struct eth_addr *ea)
+get_etheraddr(const struct netdev *netdev_, struct eth_addr *ea)
 {
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    const char *netdev_name = netdev_get_name(netdev_);
     struct ifreq ifr;
     int hwaddr_family;
     int error;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+    }
 
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     COVERAGE_INC(netdev_get_hwaddr);
-    error = af_inet_ioctl(SIOCGIFHWADDR, &ifr);
+    if (is_tap_in_netns) {
+        error = af_inet_ioctl_netns(SIOCGIFHWADDR, &ifr);
+    } else {
+        error = af_inet_ioctl(SIOCGIFHWADDR, &ifr);
+    }
     if (error) {
         /* ENODEV probably means that a vif disappeared asynchronously and
          * hasn't been removed from the database yet, so reduce the log level
@@ -6525,17 +6729,28 @@ get_etheraddr(const char *netdev_name, struct eth_addr *ea)
 }
 
 static int
-set_etheraddr(const char *netdev_name, const struct eth_addr mac)
+set_etheraddr(const struct netdev *netdev_, const struct eth_addr mac)
 {
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    const char *netdev_name = netdev_get_name(netdev_);
     struct ifreq ifr;
     int error;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+    }
 
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
     memcpy(ifr.ifr_hwaddr.sa_data, &mac, ETH_ADDR_LEN);
     COVERAGE_INC(netdev_set_hwaddr);
-    error = af_inet_ioctl(SIOCSIFHWADDR, &ifr);
+    if (is_tap_in_netns) {
+        error = af_inet_ioctl_netns(SIOCSIFHWADDR, &ifr);
+    } else {
+        error = af_inet_ioctl(SIOCSIFHWADDR, &ifr);
+    }
     if (error) {
         VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s",
                  netdev_name, ovs_strerror(error));
@@ -6549,13 +6764,27 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd,
 {
     struct ifreq ifr;
     int error;
+    struct netdev *netdev_ = netdev_from_name(name);
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    struct netns_knob netns_knob;
+    bool is_tap_in_netns = false;
+
+    if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) {
+        is_tap_in_netns = true;
+        error = enter_netns(&netns_knob, netdev->netns);
+    }
+    netdev_close(netdev_);
 
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
     ifr.ifr_data = (caddr_t) ecmd;
 
     ecmd->cmd = cmd;
-    error = af_inet_ioctl(SIOCETHTOOL, &ifr);
+    if (is_tap_in_netns) {
+        error = af_inet_ioctl_netns(SIOCETHTOOL, &ifr);
+    } else {
+        error = af_inet_ioctl(SIOCETHTOOL, &ifr);
+    }
     if (error) {
         if (error != EOPNOTSUPP) {
             VLOG_WARN_RL(&rl, "ethtool command %s on network device %s "
@@ -6565,6 +6794,11 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd,
              * common, so there's no point in logging anything. */
         }
     }
+
+    if (is_tap_in_netns) {
+        exit_netns(&netns_knob);
+    }
+
     return error;
 }
 
diff --git a/lib/socket-util-unix.c b/lib/socket-util-unix.c
index 59f63fc..4923461 100644
--- a/lib/socket-util-unix.c
+++ b/lib/socket-util-unix.c
@@ -419,6 +419,27 @@ af_inet_ioctl(unsigned long int command, const void *arg)
 }
 
 int
+af_inet_ioctl_netns(unsigned long int command, const void *arg)
+{
+    int sock;
+    int error = 0;
+
+    sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        error = -sock_errno();
+        VLOG_ERR("failed to create inet socket: %s", sock_strerror(error));
+    }
+
+    if (sock >= 0) {
+        if (ioctl(sock, command, arg) == -1) {
+            error = errno;
+        }
+        close(sock);
+    }
+    return error;
+}
+
+int
 af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd,
                     const char *cmd_name)
 {
@@ -433,3 +454,19 @@ af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd,
     }
     return error;
 }
+
+int
+af_inet_ifreq_ioctl_netns(const char *name, struct ifreq *ifr,
+                          unsigned long int cmd, const char *cmd_name)
+{
+    int error;
+
+    ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name);
+    error = af_inet_ioctl_netns(cmd, ifr);
+    if (error) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
+        VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name,
+                    ovs_strerror(error));
+    }
+    return error;
+}
diff --git a/lib/socket-util.h b/lib/socket-util.h
index 9ccb7d4..d92e4c4 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -140,6 +140,9 @@ struct ifreq;
 int af_inet_ioctl(unsigned long int command, const void *arg);
 int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
                         unsigned long int cmd, const char *cmd_name);
+int af_inet_ioctl_netns(unsigned long int command, const void *arg);
+int af_inet_ifreq_ioctl_netns(const char *name, struct ifreq *,
+                              unsigned long int cmd, const char *cmd_name);
 
 #define closesocket close
 #endif
