X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Ftap%2Frte_eth_tap.c;h=6567bba75b475d51ee15afb8508f0b596d4496d6;hb=191447ce23765dc22a21b5cfe02c7d1a7a776258;hp=61e5ffcdd06035439c0e597bd1c03925355b262a;hpb=0781f5762cfe0a7bbada05da4380f2efecfe79ff;p=dpdk.git diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c index 61e5ffcdd0..6567bba75b 100644 --- a/drivers/net/tap/rte_eth_tap.c +++ b/drivers/net/tap/rte_eth_tap.c @@ -61,6 +61,7 @@ #include #include +#include #include /* Linux based path to the TUN device */ @@ -69,6 +70,7 @@ #define ETH_TAP_IFACE_ARG "iface" #define ETH_TAP_SPEED_ARG "speed" +#define ETH_TAP_REMOTE_ARG "remote" #ifdef IFF_MULTI_QUEUE #define RTE_PMD_TAP_MAX_QUEUES 16 @@ -84,6 +86,7 @@ static struct rte_vdev_driver pmd_tap_drv; static const char *valid_arguments[] = { ETH_TAP_IFACE_ARG, ETH_TAP_SPEED_ARG, + ETH_TAP_REMOTE_ARG, NULL }; @@ -109,6 +112,8 @@ static int tap_ioctl(struct pmd_internals *pmd, unsigned long request, struct ifreq *ifr, int set); +static int tap_intr_handle_set(struct rte_eth_dev *dev, int set); + /* Tun/Tap allocation routine * * name is the number of the interface to use, unless NULL to take the host @@ -243,10 +248,43 @@ tun_alloc(struct pmd_internals *pmd, uint16_t qid) pmd->name); return fd; } + if (pmd->remote_if_index) { + /* + * Flush usually returns negative value because it tries + * to delete every QDISC (and on a running device, one + * QDISC at least is needed). Ignore negative return + * value. + */ + qdisc_flush(pmd->nlsk_fd, pmd->remote_if_index); + if (qdisc_create_ingress(pmd->nlsk_fd, + pmd->remote_if_index) < 0) + goto remote_fail; + LIST_INIT(&pmd->implicit_flows); + if (tap_flow_implicit_create( + pmd, TAP_REMOTE_LOCAL_MAC) < 0) + goto remote_fail; + if (tap_flow_implicit_create( + pmd, TAP_REMOTE_BROADCAST) < 0) + goto remote_fail; + if (tap_flow_implicit_create( + pmd, TAP_REMOTE_BROADCASTV6) < 0) + goto remote_fail; + if (tap_flow_implicit_create( + pmd, TAP_REMOTE_TX) < 0) + goto remote_fail; + } } return fd; +remote_fail: + RTE_LOG(ERR, PMD, + "Could not set up remote flow rules for %s: remote disabled.\n", + pmd->name); + pmd->remote_if_index = 0; + tap_flow_implicit_flush(pmd, NULL); + return fd; + error: if (fd > 0) close(fd); @@ -402,8 +440,25 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request, struct ifreq *ifr, int set) { short req_flags = ifr->ifr_flags; + int remote = !!pmd->remote_if_index; - snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->name); + /* + * If there is a remote netdevice, apply ioctl on it, then apply it on + * the tap netdevice. + */ + if (request == SIOCGIFFLAGS && !set) { + /* + * Special case for getting flags. If set is given, + * then return the flags from the remote netdevice only. + * Otherwise return the flags from the tap netdevice. + */ + remote = 0; + } +apply: + if (remote) + snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->remote_iface); + else + snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->name); switch (request) { case SIOCSIFFLAGS: /* fetch current flags to leave other flags untouched */ @@ -414,7 +469,17 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request, else ifr->ifr_flags &= ~req_flags; break; + case SIOCGIFFLAGS: + if (remote && set) + remote = 0; /* don't loop */ + break; case SIOCGIFHWADDR: + /* Set remote MAC on the tap netdevice */ + if (!remote && pmd->remote_if_index) { + request = SIOCSIFHWADDR; + goto apply; + } + break; case SIOCSIFHWADDR: case SIOCSIFMTU: break; @@ -425,6 +490,8 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request, } if (ioctl(pmd->ioctl_sock, request, ifr) < 0) goto error; + if (remote--) + goto apply; return 0; error: @@ -456,6 +523,11 @@ tap_link_set_up(struct rte_eth_dev *dev) static int tap_dev_start(struct rte_eth_dev *dev) { + int err; + + err = tap_intr_handle_set(dev, 1); + if (err) + return err; return tap_link_set_up(dev); } @@ -464,6 +536,7 @@ tap_dev_start(struct rte_eth_dev *dev) static void tap_dev_stop(struct rte_eth_dev *dev) { + tap_intr_handle_set(dev, 0); tap_link_set_down(dev); } @@ -585,6 +658,7 @@ tap_dev_close(struct rte_eth_dev *dev __rte_unused) tap_link_set_down(dev); tap_flow_flush(dev, NULL); + tap_flow_implicit_flush(internals, NULL); for (i = 0; i < internals->nb_queues; i++) { if (internals->rxq[i].fd != -1) @@ -621,9 +695,25 @@ tap_tx_queue_release(void *queue) } static int -tap_link_update(struct rte_eth_dev *dev __rte_unused, - int wait_to_complete __rte_unused) +tap_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused) { + struct rte_eth_link *dev_link = &dev->data->dev_link; + struct pmd_internals *pmd = dev->data->dev_private; + struct ifreq ifr = { .ifr_flags = 0 }; + + if (pmd->remote_if_index) { + tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 1); + if (!(ifr.ifr_flags & IFF_UP) || + !(ifr.ifr_flags & IFF_RUNNING)) { + dev_link->link_status = ETH_LINK_DOWN; + return 0; + } + } + tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0); + dev_link->link_status = + ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING) ? + ETH_LINK_UP : + ETH_LINK_DOWN); return 0; } @@ -635,6 +725,8 @@ tap_promisc_enable(struct rte_eth_dev *dev) dev->data->promiscuous = 1; tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1); + if (pmd->remote_if_index) + tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC); } static void @@ -645,6 +737,8 @@ tap_promisc_disable(struct rte_eth_dev *dev) dev->data->promiscuous = 0; tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0); + if (pmd->remote_if_index) + tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC); } static void @@ -655,6 +749,8 @@ tap_allmulti_enable(struct rte_eth_dev *dev) dev->data->all_multicast = 1; tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1); + if (pmd->remote_if_index) + tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI); } static void @@ -665,6 +761,8 @@ tap_allmulti_disable(struct rte_eth_dev *dev) dev->data->all_multicast = 0; tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0); + if (pmd->remote_if_index) + tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI); } @@ -887,6 +985,55 @@ tap_set_mc_addr_list(struct rte_eth_dev *dev __rte_unused, return 0; } +static int +tap_nl_msg_handler(struct nlmsghdr *nh, void *arg) +{ + struct rte_eth_dev *dev = arg; + struct pmd_internals *pmd = dev->data->dev_private; + struct ifinfomsg *info = NLMSG_DATA(nh); + + if (nh->nlmsg_type != RTM_NEWLINK || + (info->ifi_index != pmd->if_index && + info->ifi_index != pmd->remote_if_index)) + return 0; + return tap_link_update(dev, 0); +} + +static void +tap_dev_intr_handler(struct rte_intr_handle *intr_handle __rte_unused, + void *cb_arg) +{ + struct rte_eth_dev *dev = cb_arg; + struct pmd_internals *pmd = dev->data->dev_private; + + nl_recv(pmd->intr_handle.fd, tap_nl_msg_handler, dev); +} + +static int +tap_intr_handle_set(struct rte_eth_dev *dev, int set) +{ + struct pmd_internals *pmd = dev->data->dev_private; + + /* In any case, disable interrupt if the conf is no longer there. */ + if (!dev->data->dev_conf.intr_conf.lsc) { + if (pmd->intr_handle.fd != -1) + nl_final(pmd->intr_handle.fd); + rte_intr_callback_unregister( + &pmd->intr_handle, tap_dev_intr_handler, dev); + return 0; + } + if (set) { + pmd->intr_handle.fd = nl_init(RTMGRP_LINK); + if (unlikely(pmd->intr_handle.fd == -1)) + return -EBADF; + return rte_intr_callback_register( + &pmd->intr_handle, tap_dev_intr_handler, dev); + } + nl_final(pmd->intr_handle.fd); + return rte_intr_callback_unregister(&pmd->intr_handle, + tap_dev_intr_handler, dev); +} + static const uint32_t* tap_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused) { @@ -982,7 +1129,7 @@ tap_kernel_support(struct pmd_internals *pmd) } static int -eth_dev_tap_create(const char *name, char *tap_name) +eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface) { int numa_node = rte_socket_id(); struct rte_eth_dev *dev = NULL; @@ -1028,7 +1175,7 @@ eth_dev_tap_create(const char *name, char *tap_name) data->dev_private = pmd; data->port_id = dev->data->port_id; data->mtu = dev->data->mtu; - data->dev_flags = RTE_ETH_DEV_DETACHABLE; + data->dev_flags = RTE_ETH_DEV_DETACHABLE | RTE_ETH_DEV_INTR_LSC; data->kdrv = RTE_KDRV_NONE; data->drv_name = pmd_tap_drv.driver.name; data->numa_node = numa_node; @@ -1044,6 +1191,9 @@ eth_dev_tap_create(const char *name, char *tap_name) dev->rx_pkt_burst = pmd_rx_burst; dev->tx_pkt_burst = pmd_tx_burst; + pmd->intr_handle.type = RTE_INTR_HANDLE_EXT; + pmd->intr_handle.fd = -1; + /* Presetup the fds to -1 as being not valid */ for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) { pmd->rxq[i].fd = -1; @@ -1058,7 +1208,16 @@ eth_dev_tap_create(const char *name, char *tap_name) * If no netlink socket can be created, then it will fail when * creating/destroying flow rules. */ - pmd->nlsk_fd = nl_init(); + pmd->nlsk_fd = nl_init(0); + if (strlen(remote_iface)) { + pmd->remote_if_index = if_nametoindex(remote_iface); + snprintf(pmd->remote_iface, RTE_ETH_NAME_MAX_LEN, + "%s", remote_iface); + if (!pmd->remote_if_index) + RTE_LOG(ERR, PMD, "Could not find %s ifindex: " + "remote interface will remain unconfigured\n", + remote_iface); + } return 0; @@ -1099,6 +1258,19 @@ set_interface_speed(const char *key __rte_unused, return 0; } +static int +set_remote_iface(const char *key __rte_unused, + const char *value, + void *extra_args) +{ + char *name = (char *)extra_args; + + if (value) + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s", value); + + return 0; +} + /* Open a TAP interface device. */ static int @@ -1108,10 +1280,12 @@ rte_pmd_tap_probe(const char *name, const char *params) struct rte_kvargs *kvlist = NULL; int speed; char tap_name[RTE_ETH_NAME_MAX_LEN]; + char remote_iface[RTE_ETH_NAME_MAX_LEN]; speed = ETH_SPEED_NUM_10G; snprintf(tap_name, sizeof(tap_name), "%s%d", DEFAULT_TAP_NAME, tap_unit++); + memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN); if (params && (params[0] != '\0')) { RTE_LOG(DEBUG, PMD, "paramaters (%s)\n", params); @@ -1135,6 +1309,15 @@ rte_pmd_tap_probe(const char *name, const char *params) if (ret == -1) goto leave; } + + if (rte_kvargs_count(kvlist, ETH_TAP_REMOTE_ARG) == 1) { + ret = rte_kvargs_process(kvlist, + ETH_TAP_REMOTE_ARG, + &set_remote_iface, + remote_iface); + if (ret == -1) + goto leave; + } } } pmd_link.link_speed = speed; @@ -1142,7 +1325,7 @@ rte_pmd_tap_probe(const char *name, const char *params) RTE_LOG(NOTICE, PMD, "Initializing pmd_tap for %s as %s\n", name, tap_name); - ret = eth_dev_tap_create(name, tap_name); + ret = eth_dev_tap_create(name, tap_name, remote_iface); leave: if (ret == -1) { @@ -1175,6 +1358,7 @@ rte_pmd_tap_remove(const char *name) internals = eth_dev->data->dev_private; if (internals->flower_support && internals->nlsk_fd) { tap_flow_flush(eth_dev, NULL); + tap_flow_implicit_flush(internals, NULL); nl_final(internals->nlsk_fd); } for (i = 0; i < internals->nb_queues; i++)