/* * 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.
*/
/* 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);
}
/* 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);
}
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;
}
staticint 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);
}
/* 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;
/* 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 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 (!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;
}
staticconststruct 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)
},
};
staticint 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;
}
}
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;
}
}
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) {
pr_warn("Could not allocate netdev for %s\n", name); return ERR_PTR(-ENOMEM);
}
/* * Initialise a dummy MAC address. We choose the numerically * largest non-broadcast address to prevent the address getting * stolen by an Ethernet bridge for STP purposes. * (FE:FF:FF:FF:FF:FF)
*/
eth_hw_addr_set(dev, dummy_addr);
netif_carrier_off(dev);
err = register_netdev(dev); if (err) {
netdev_warn(dev, "Could not register device: err=%d\n", err);
free_netdev(dev); return ERR_PTR(err);
}
netdev_dbg(dev, "Successfully created xenvif\n");
__module_get(THIS_MODULE);
return vif;
}
int xenvif_init_queue(struct xenvif_queue *queue)
{ int err, i;
/* If ballooning is disabled, this will consume real memory, so you * better enable it. The long term solution would be to use just a * bunch of valid page descriptors, without dependency on ballooning
*/
err = gnttab_alloc_pages(MAX_PENDING_REQS,
queue->mmap_pages); if (err) {
netdev_err(queue->vif->dev, "Could not reserve mmap_pages\n"); return -ENOMEM;
}
for (i = 0; i < MAX_PENDING_REQS; i++) {
queue->pending_tx_info[i].callback_struct = (struct ubuf_info_msgzc)
{ { .ops = &xenvif_ubuf_ops },
{ { .ctx = NULL,
.desc = i } } };
queue->grant_tx_handle[i] = NETBACK_INVALID_HANDLE;
}
task = kthread_run(xenvif_kthread_guest_rx, queue, "%s-guest-rx", queue->name); if (IS_ERR(task)) goto kthread_err;
queue->task = task; /* * Take a reference to the task in order to prevent it from being freed * if the thread function returns before kthread_stop is called.
*/
get_task_struct(task);
if (vif->ctrl.sring) {
xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
vif->ctrl.sring);
vif->ctrl.sring = NULL;
}
}
/* Reverse the relevant parts of xenvif_init_queue(). * Used for queue teardown from xenvif_free(), and on the * error handling paths in xenbus.c:connect().
*/ void xenvif_deinit_queue(struct xenvif_queue *queue)
{
gnttab_free_pages(MAX_PENDING_REQS, queue->mmap_pages);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.