Tap devices can have two FDs that allow transmit and receive from
different perspectives. We previously would always share one of
the FDs among all openers. However, this is confusing to some
users (primarily the DHCP client) which expect tap devices to behave
like any other device. Now we give the tap FD to the first opener,
which knows that it has opened a tap device, and a normal system FD
to everyone else for consistency.
struct tap_state {
int fd;
+ bool opened;
};
struct netdev_dev_linux {
goto error;
}
- if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap")) {
+ if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") &&
+ !netdev_dev->state.tap.opened) {
+
+ /* We assume that the first user of the tap device is the primary user
+ * and give them the tap FD. Subsequent users probably just expect
+ * this to be a system device so open it normally to avoid send/receive
+ * directions appearing to be reversed. */
netdev->fd = netdev_dev->state.tap.fd;
+ netdev_dev->state.tap.opened = true;
} else if (ethertype != NETDEV_ETH_TYPE_NONE) {
struct sockaddr_ll sll;
int protocol;