/* * Network-device interface management. * * Copyright (c) 2004-2005, Keir Fraser * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation; or, when distributed * separately from the Linux kernel or incorporated into other * software packages, subject to the following license: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this source file (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "common.h" #include <linux/kthread.h>#include <linux/sched/task.h>#include <linux/ethtool.h>#include <linux/rtnetlink.h>#include <linux/if_vlan.h>#include <linux/vmalloc.h> #include <xen/events.h>#include <asm/xen/hypercall.h>#include <xen/balloon.h> /* Number of bytes allowed on the internal guest Rx queue. */#define XENVIF_RX_QUEUE_BYTES (XEN_NETIF_RX_RING_SIZE/2 * PAGE_SIZE) /* This function is used to set SKBFL_ZEROCOPY_ENABLE as well as * increasing the inflight counter. We need to increase the inflight * counter because core driver calls into xenvif_zerocopy_callback * which calls xenvif_skb_zerocopy_complete. */void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue, struct sk_buff *skb){ skb_shinfo(skb)->flags |= SKBFL_ZEROCOPY_ENABLE; atomic_inc(&queue->inflight_packets);} void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue){ atomic_dec(&queue->inflight_packets); /* Wake the dealloc thread _after_ decrementing inflight_packets so * that if kthread_stop() has already been called, the dealloc thread * does not wait forever with nothing to wake it. */ wake_up(&queue->dealloc_wq);} static int xenvif_schedulable(struct xenvif *vif){ return netif_running(vif->dev) && test_bit(VIF_STATUS_CONNECTED, &vif->status) && !vif->disabled;} static bool xenvif_handle_tx_interrupt(struct xenvif_queue *queue){ bool rc; rc = RING_HAS_UNCONSUMED_REQUESTS(&queue->tx); if (rc) napi_schedule(&queue->napi); return rc;} static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id){ struct xenvif_queue *queue = dev_id; int old; old = atomic_fetch_or(NETBK_TX_EOI, &queue->eoi_pending); WARN(old & NETBK_TX_EOI, "Interrupt while EOI pending\n"); if (!xenvif_handle_tx_interrupt(queue)) { atomic_andnot(NETBK_TX_EOI, &queue->eoi_pending); xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); } return IRQ_HANDLED;} static int xenvif_poll(struct napi_struct *napi, int budget){ struct xenvif_queue *queue = container_of(napi, struct xenvif_queue, napi); int work_done; /* This vif is rogue, we pretend we've there is nothing to do * for this vif to deschedule it from NAPI. But this interface * will be turned off in thread context later. */ if (unlikely(queue->vif->disabled)) { napi_complete(napi); return 0; } work_done = xenvif_tx_action(queue, budget); if (work_done < budget) { napi_complete_done(napi, work_done); /* If the queue is rate-limited, it shall be * rescheduled in the timer callback. */ if (likely(!queue->rate_limited)) xenvif_napi_schedule_or_enable_events(queue); } return work_done;} static bool xenvif_handle_rx_interrupt(struct xenvif_queue *queue){ bool rc; rc = xenvif_have_rx_work(queue, false); if (rc) xenvif_kick_thread(queue); return rc;} static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id){ struct xenvif_queue *queue = dev_id; int old; old = atomic_fetch_or(NETBK_RX_EOI, &queue->eoi_pending); WARN(old & NETBK_RX_EOI, "Interrupt while EOI pending\n"); if (!xenvif_handle_rx_interrupt(queue)) { atomic_andnot(NETBK_RX_EOI, &queue->eoi_pending); xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); } return IRQ_HANDLED;} irqreturn_t xenvif_interrupt(int irq, void *dev_id){ struct xenvif_queue *queue = dev_id; int old; bool has_rx, has_tx; old = atomic_fetch_or(NETBK_COMMON_EOI, &queue->eoi_pending); WARN(old, "Interrupt while EOI pending\n"); has_tx = xenvif_handle_tx_interrupt(queue); has_rx = xenvif_handle_rx_interrupt(queue); if (!has_rx && !has_tx) { atomic_andnot(NETBK_COMMON_EOI, &queue->eoi_pending); xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); } return IRQ_HANDLED;} static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev){ struct xenvif *vif = netdev_priv(dev); unsigned int size = vif->hash.size; unsigned int num_queues; /* If queues are not set up internally - always return 0 * as the packet going to be dropped anyway */ num_queues = READ_ONCE(vif->num_queues); if (num_queues < 1) return 0; if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE) return netdev_pick_tx(dev, skb, NULL) % dev->real_num_tx_queues; xenvif_set_skb_hash(vif, skb); if (size == 0) return skb_get_hash_raw(skb) % dev->real_num_tx_queues; return vif->hash.mapping[vif->hash.mapping_sel] [skb_get_hash_raw(skb) % size];} static netdev_tx_txenvif_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; unsigned int num_queues; u16 index; struct xenvif_rx_cb *cb; BUG_ON(skb->dev != dev); /* Drop the packet if queues are not set up. * This handler should be called inside an RCU read section * so we don't need to enter it here explicitly. */ num_queues = READ_ONCE(vif->num_queues); if (num_queues < 1) goto drop; /* Obtain the queue to be used to transmit this packet */ index = skb_get_queue_mapping(skb); if (index >= num_queues) { pr_warn_ratelimited("Invalid queue %hu for packet on interface %s\n", index, vif->dev->name); index %= num_queues; } queue = &vif->queues[index]; /* Drop the packet if queue is not ready */ if (queue->task == NULL || queue->dealloc_task == NULL || !xenvif_schedulable(vif)) goto drop; if (vif->multicast_control && skb->pkt_type == PACKET_MULTICAST) { struct ethhdr *eth = (struct ethhdr *)skb->data; if (!xenvif_mcast_match(vif, eth->h_dest)) goto drop; } cb = XENVIF_RX_CB(skb); cb->expires = jiffies + vif->drain_timeout; /* If there is no hash algorithm configured then make sure there * is no hash information in the socket buffer otherwise it * would be incorrectly forwarded to the frontend. */ if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE) skb_clear_hash(skb); /* timestamp packet in software */ skb_tx_timestamp(skb); if (!xenvif_rx_queue_tail(queue, skb)) goto drop; xenvif_kick_thread(queue); return NETDEV_TX_OK; drop: vif->dev->stats.tx_dropped++; dev_kfree_skb_any(skb); return NETDEV_TX_OK;} static struct net_device_stats *xenvif_get_stats(struct net_device *dev){ struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; unsigned int num_queues; u64 rx_bytes = 0; u64 rx_packets = 0; u64 tx_bytes = 0; u64 tx_packets = 0; unsigned int index; rcu_read_lock(); num_queues = READ_ONCE(vif->num_queues); /* Aggregate tx and rx stats from each queue */ for (index = 0; index < num_queues; ++index) { queue = &vif->queues[index]; rx_bytes += queue->stats.rx_bytes; rx_packets += queue->stats.rx_packets; tx_bytes += queue->stats.tx_bytes; tx_packets += queue->stats.tx_packets; } rcu_read_unlock(); vif->dev->stats.rx_bytes = rx_bytes; vif->dev->stats.rx_packets = rx_packets; vif->dev->stats.tx_bytes = tx_bytes; vif->dev->stats.tx_packets = tx_packets; return &vif->dev->stats;} static void xenvif_up(struct xenvif *vif){ struct xenvif_queue *queue = NULL; unsigned int num_queues = vif->num_queues; unsigned int queue_index; for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; napi_enable(&queue->napi); enable_irq(queue->tx_irq); if (queue->tx_irq != queue->rx_irq) enable_irq(queue->rx_irq); xenvif_napi_schedule_or_enable_events(queue); }} static void xenvif_down(struct xenvif *vif){ struct xenvif_queue *queue = NULL; unsigned int num_queues = vif->num_queues; unsigned int queue_index; for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; disable_irq(queue->tx_irq); if (queue->tx_irq != queue->rx_irq) disable_irq(queue->rx_irq); napi_disable(&queue->napi); timer_delete_sync(&queue->credit_timeout); }} static int xenvif_open(struct net_device *dev){ struct xenvif *vif = netdev_priv(dev); if (test_bit(VIF_STATUS_CONNECTED, &vif->status)) xenvif_up(vif); netif_tx_start_all_queues(dev); return 0;} static int xenvif_close(struct net_device *dev){ struct xenvif *vif = netdev_priv(dev); if (test_bit(VIF_STATUS_CONNECTED, &vif->status)) xenvif_down(vif); netif_tx_stop_all_queues(dev); return 0;} static int xenvif_change_mtu(struct net_device *dev, int mtu){ struct xenvif *vif = netdev_priv(dev); int max = vif->can_sg ? ETH_MAX_MTU - VLAN_ETH_HLEN : ETH_DATA_LEN; if (mtu > max) return -EINVAL; WRITE_ONCE(dev->mtu, mtu); return 0;} static netdev_features_t xenvif_fix_features(struct net_device *dev, netdev_features_t features){ struct xenvif *vif = netdev_priv(dev); if (!vif->can_sg) features &= ~NETIF_F_SG; if (~(vif->gso_mask) & GSO_BIT(TCPV4)) features &= ~NETIF_F_TSO; if (~(vif->gso_mask) & GSO_BIT(TCPV6)) features &= ~NETIF_F_TSO6; if (!vif->ip_csum) features &= ~NETIF_F_IP_CSUM; if (!vif->ipv6_csum) features &= ~NETIF_F_IPV6_CSUM; return features;} static const struct xenvif_stat { char name[ETH_GSTRING_LEN]; u16 offset;} xenvif_stats[] = { { "rx_gso_checksum_fixup", offsetof(struct xenvif_stats, rx_gso_checksum_fixup) }, /* If (sent != success + fail), there are probably packets never * freed up properly! */ { "tx_zerocopy_sent", offsetof(struct xenvif_stats, tx_zerocopy_sent), }, { "tx_zerocopy_success", offsetof(struct xenvif_stats, tx_zerocopy_success), }, { "tx_zerocopy_fail", offsetof(struct xenvif_stats, tx_zerocopy_fail) }, /* Number of packets exceeding MAX_SKB_FRAG slots. You should use * a guest with the same MAX_SKB_FRAG */ { "tx_frag_overflow", offsetof(struct xenvif_stats, tx_frag_overflow) },}; static int xenvif_get_sset_count(struct net_device *dev, int string_set){ switch (string_set) { case ETH_SS_STATS: return ARRAY_SIZE(xenvif_stats); default: return -EINVAL; }} static void xenvif_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data){ struct xenvif *vif = netdev_priv(dev); unsigned int num_queues; int i; unsigned int queue_index; rcu_read_lock(); num_queues = READ_ONCE(vif->num_queues); for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) { unsigned long accum = 0; for (queue_index = 0; queue_index < num_queues; ++queue_index) { void *vif_stats = &vif->queues[queue_index].stats; accum += *(unsigned long *)(vif_stats + xenvif_stats[i].offset); } data[i] = accum; } rcu_read_unlock();} static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data){ int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) memcpy(data + i * ETH_GSTRING_LEN, xenvif_stats[i].name, ETH_GSTRING_LEN); break; }} static const struct ethtool_ops xenvif_ethtool_ops = { .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, .get_sset_count = xenvif_get_sset_count, .get_ethtool_stats = xenvif_get_ethtool_stats, .get_strings = xenvif_get_strings,}; static const struct net_device_ops xenvif_netdev_ops = { .ndo_select_queue = xenvif_select_queue, .ndo_start_xmit = xenvif_start_xmit, .ndo_get_stats = xenvif_get_stats, .ndo_open = xenvif_open, .ndo_stop = xenvif_close, .ndo_change_mtu = xenvif_change_mtu, .ndo_fix_features = xenvif_fix_features, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr,}; struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, unsigned int handle){ static const u8 dummy_addr[ETH_ALEN] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, }; int err; struct net_device *dev; struct xenvif *vif; char name[IFNAMSIZ] = {}; snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); /* Allocate a netdev with the max. supported number of queues. * When the guest selects the desired number, it will be updated * via netif_set_real_num_*_queues(). */ dev = alloc_netdev_mq(sizeof(struct xenvif), name, NET_NAME_UNKNOWN, ether_setup, xenvif_max_queues); if (dev == NULL) {Lines 1–500 of 857. Load more
/* * Network-device interface management. * * Copyright (c) 2004-2005, Keir Fraser * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation; or, when distributed * separately from the Linux kernel or incorporated into other * software packages, subject to the following license: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this source file (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "common.h" #include <linux/kthread.h> #include <linux/sched/task.h> #include <linux/ethtool.h> #include <linux/rtnetlink.h> #include <linux/if_vlan.h> #include <linux/vmalloc.h> #include <xen/events.h> #include <asm/xen/hypercall.h> #include <xen/balloon.h> /* Number of bytes allowed on the internal guest Rx queue. */ #define XENVIF_RX_QUEUE_BYTES (XEN_NETIF_RX_RING_SIZE/2 * PAGE_SIZE) /* This function is used to set SKBFL_ZEROCOPY_ENABLE as well as * increasing the inflight counter. We need to increase the inflight * counter because core driver calls into xenvif_zerocopy_callback * which calls xenvif_skb_zerocopy_complete. */ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue, struct sk_buff *skb) { skb_shinfo(skb)->flags |= SKBFL_ZEROCOPY_ENABLE; atomic_inc(&queue->inflight_packets); } void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue) { atomic_dec(&queue->inflight_packets); /* Wake the dealloc thread _after_ decrementing inflight_packets so * that if kthread_stop() has already been called, the dealloc thread * does not wait forever with nothing to wake it. */ wake_up(&queue->dealloc_wq); } static int xenvif_schedulable(struct xenvif *vif) { return netif_running(vif->dev) && test_bit(VIF_STATUS_CONNECTED, &vif->status) && !vif->disabled; } static bool xenvif_handle_tx_interrupt(struct xenvif_queue *queue) { bool rc; rc = RING_HAS_UNCONSUMED_REQUESTS(&queue->tx); if (rc) napi_schedule(&queue->napi); return rc; } static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) { struct xenvif_queue *queue = dev_id; int old; old = atomic_fetch_or(NETBK_TX_EOI, &queue->eoi_pending); WARN(old & NETBK_TX_EOI, "Interrupt while EOI pending\n"); if (!xenvif_handle_tx_interrupt(queue)) { atomic_andnot(NETBK_TX_EOI, &queue->eoi_pending); xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); } return IRQ_HANDLED; } static int xenvif_poll(struct napi_struct *napi, int budget) { struct xenvif_queue *queue = container_of(napi, struct xenvif_queue, napi); int work_done; /* This vif is rogue, we pretend we've there is nothing to do * for this vif to deschedule it from NAPI. But this interface * will be turned off in thread context later. */ if (unlikely(queue->vif->disabled)) { napi_complete(napi); return 0; } work_done = xenvif_tx_action(queue, budget); if (work_done < budget) { napi_complete_done(napi, work_done); /* If the queue is rate-limited, it shall be * rescheduled in the timer callback. */ if (likely(!queue->rate_limited)) xenvif_napi_schedule_or_enable_events(queue); } return work_done; } static bool xenvif_handle_rx_interrupt(struct xenvif_queue *queue) { bool rc; rc = xenvif_have_rx_work(queue, false); if (rc) xenvif_kick_thread(queue); return rc; } static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) { struct xenvif_queue *queue = dev_id; int old; old = atomic_fetch_or(NETBK_RX_EOI, &queue->eoi_pending); WARN(old & NETBK_RX_EOI, "Interrupt while EOI pending\n"); if (!xenvif_handle_rx_interrupt(queue)) { atomic_andnot(NETBK_RX_EOI, &queue->eoi_pending); xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); } return IRQ_HANDLED; } irqreturn_t xenvif_interrupt(int irq, void *dev_id) { struct xenvif_queue *queue = dev_id; int old; bool has_rx, has_tx; old = atomic_fetch_or(NETBK_COMMON_EOI, &queue->eoi_pending); WARN(old, "Interrupt while EOI pending\n"); has_tx = xenvif_handle_tx_interrupt(queue); has_rx = xenvif_handle_rx_interrupt(queue); if (!has_rx && !has_tx) { atomic_andnot(NETBK_COMMON_EOI, &queue->eoi_pending); xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); } return IRQ_HANDLED; } static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) { struct xenvif *vif = netdev_priv(dev); unsigned int size = vif->hash.size; unsigned int num_queues; /* If queues are not set up internally - always return 0 * as the packet going to be dropped anyway */ num_queues = READ_ONCE(vif->num_queues); if (num_queues < 1) return 0; if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE) return netdev_pick_tx(dev, skb, NULL) % dev->real_num_tx_queues; xenvif_set_skb_hash(vif, skb); if (size == 0) return skb_get_hash_raw(skb) % dev->real_num_tx_queues; return vif->hash.mapping[vif->hash.mapping_sel] [skb_get_hash_raw(skb) % size]; } static netdev_tx_t xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; unsigned int num_queues; u16 index; struct xenvif_rx_cb *cb; BUG_ON(skb->dev != dev); /* Drop the packet if queues are not set up. * This handler should be called inside an RCU read section * so we don't need to enter it here explicitly. */ num_queues = READ_ONCE(vif->num_queues); if (num_queues < 1) goto drop; /* Obtain the queue to be used to transmit this packet */ index = skb_get_queue_mapping(skb); if (index >= num_queues) { pr_warn_ratelimited("Invalid queue %hu for packet on interface %s\n", index, vif->dev->name); index %= num_queues; } queue = &vif->queues[index]; /* Drop the packet if queue is not ready */ if (queue->task == NULL || queue->dealloc_task == NULL || !xenvif_schedulable(vif)) goto drop; if (vif->multicast_control && skb->pkt_type == PACKET_MULTICAST) { struct ethhdr *eth = (struct ethhdr *)skb->data; if (!xenvif_mcast_match(vif, eth->h_dest)) goto drop; } cb = XENVIF_RX_CB(skb); cb->expires = jiffies + vif->drain_timeout; /* If there is no hash algorithm configured then make sure there * is no hash information in the socket buffer otherwise it * would be incorrectly forwarded to the frontend. */ if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE) skb_clear_hash(skb); /* timestamp packet in software */ skb_tx_timestamp(skb); if (!xenvif_rx_queue_tail(queue, skb)) goto drop; xenvif_kick_thread(queue); return NETDEV_TX_OK; drop: vif->dev->stats.tx_dropped++; dev_kfree_skb_any(skb); return NETDEV_TX_OK; } static struct net_device_stats *xenvif_get_stats(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; unsigned int num_queues; u64 rx_bytes = 0; u64 rx_packets = 0; u64 tx_bytes = 0; u64 tx_packets = 0; unsigned int index; rcu_read_lock(); num_queues = READ_ONCE(vif->num_queues); /* Aggregate tx and rx stats from each queue */ for (index = 0; index < num_queues; ++index) { queue = &vif->queues[index]; rx_bytes += queue->stats.rx_bytes; rx_packets += queue->stats.rx_packets; tx_bytes += queue->stats.tx_bytes; tx_packets += queue->stats.tx_packets; } rcu_read_unlock(); vif->dev->stats.rx_bytes = rx_bytes; vif->dev->stats.rx_packets = rx_packets; vif->dev->stats.tx_bytes = tx_bytes; vif->dev->stats.tx_packets = tx_packets; return &vif->dev->stats; } static void xenvif_up(struct xenvif *vif) { struct xenvif_queue *queue = NULL; unsigned int num_queues = vif->num_queues; unsigned int queue_index; for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; napi_enable(&queue->napi); enable_irq(queue->tx_irq); if (queue->tx_irq != queue->rx_irq) enable_irq(queue->rx_irq); xenvif_napi_schedule_or_enable_events(queue); } } static void xenvif_down(struct xenvif *vif) { struct xenvif_queue *queue = NULL; unsigned int num_queues = vif->num_queues; unsigned int queue_index; for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; disable_irq(queue->tx_irq); if (queue->tx_irq != queue->rx_irq) disable_irq(queue->rx_irq); napi_disable(&queue->napi); timer_delete_sync(&queue->credit_timeout); } } static int xenvif_open(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); if (test_bit(VIF_STATUS_CONNECTED, &vif->status)) xenvif_up(vif); netif_tx_start_all_queues(dev); return 0; } static int xenvif_close(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); if (test_bit(VIF_STATUS_CONNECTED, &vif->status)) xenvif_down(vif); netif_tx_stop_all_queues(dev); return 0; } static int xenvif_change_mtu(struct net_device *dev, int mtu) { struct xenvif *vif = netdev_priv(dev); int max = vif->can_sg ? ETH_MAX_MTU - VLAN_ETH_HLEN : ETH_DATA_LEN; if (mtu > max) return -EINVAL; WRITE_ONCE(dev->mtu, mtu); return 0; } static netdev_features_t xenvif_fix_features(struct net_device *dev, netdev_features_t features) { struct xenvif *vif = netdev_priv(dev); if (!vif->can_sg) features &= ~NETIF_F_SG; if (~(vif->gso_mask) & GSO_BIT(TCPV4)) features &= ~NETIF_F_TSO; if (~(vif->gso_mask) & GSO_BIT(TCPV6)) features &= ~NETIF_F_TSO6; if (!vif->ip_csum) features &= ~NETIF_F_IP_CSUM; if (!vif->ipv6_csum) features &= ~NETIF_F_IPV6_CSUM; return features; } static const struct xenvif_stat { char name[ETH_GSTRING_LEN]; u16 offset; } xenvif_stats[] = { { "rx_gso_checksum_fixup", offsetof(struct xenvif_stats, rx_gso_checksum_fixup) }, /* If (sent != success + fail), there are probably packets never * freed up properly! */ { "tx_zerocopy_sent", offsetof(struct xenvif_stats, tx_zerocopy_sent), }, { "tx_zerocopy_success", offsetof(struct xenvif_stats, tx_zerocopy_success), }, { "tx_zerocopy_fail", offsetof(struct xenvif_stats, tx_zerocopy_fail) }, /* Number of packets exceeding MAX_SKB_FRAG slots. You should use * a guest with the same MAX_SKB_FRAG */ { "tx_frag_overflow", offsetof(struct xenvif_stats, tx_frag_overflow) }, }; static int xenvif_get_sset_count(struct net_device *dev, int string_set) { switch (string_set) { case ETH_SS_STATS: return ARRAY_SIZE(xenvif_stats); default: return -EINVAL; } } static void xenvif_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data) { struct xenvif *vif = netdev_priv(dev); unsigned int num_queues; int i; unsigned int queue_index; rcu_read_lock(); num_queues = READ_ONCE(vif->num_queues); for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) { unsigned long accum = 0; for (queue_index = 0; queue_index < num_queues; ++queue_index) { void *vif_stats = &vif->queues[queue_index].stats; accum += *(unsigned long *)(vif_stats + xenvif_stats[i].offset); } data[i] = accum; } rcu_read_unlock(); } static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data) { int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) memcpy(data + i * ETH_GSTRING_LEN, xenvif_stats[i].name, ETH_GSTRING_LEN); break; } } static const struct ethtool_ops xenvif_ethtool_ops = { .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, .get_sset_count = xenvif_get_sset_count, .get_ethtool_stats = xenvif_get_ethtool_stats, .get_strings = xenvif_get_strings, }; static const struct net_device_ops xenvif_netdev_ops = { .ndo_select_queue = xenvif_select_queue, .ndo_start_xmit = xenvif_start_xmit, .ndo_get_stats = xenvif_get_stats, .ndo_open = xenvif_open, .ndo_stop = xenvif_close, .ndo_change_mtu = xenvif_change_mtu, .ndo_fix_features = xenvif_fix_features, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, unsigned int handle) { static const u8 dummy_addr[ETH_ALEN] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, }; int err; struct net_device *dev; struct xenvif *vif; char name[IFNAMSIZ] = {}; snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); /* Allocate a netdev with the max. supported number of queues. * When the guest selects the desired number, it will be updated * via netif_set_real_num_*_queues(). */ dev = alloc_netdev_mq(sizeof(struct xenvif), name, NET_NAME_UNKNOWN, ether_setup, xenvif_max_queues); if (dev == NULL) {