/* 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 *increasingtheinflightcounter.Weneedtoincreasetheinflight *counterbecausecoredrivercallsintoxenvif_zerocopy_callback *whichcallsxenvif_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 *thatifkthread_stop()hasalreadybeencalled,thedeallocthread *doesnotwaitforeverwithnothingtowakeit.
*/
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 *forthisviftodescheduleitfromNAPI.Butthisinterface *willbeturnedoffinthreadcontextlater.
*/ if (unlikely(queue->vif->disabled)) {
napi_complete(napi); return0;
}
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 *rescheduledinthetimercallback.
*/ 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) return0;
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. *ThishandlershouldbecalledinsideanRCUreadsection *sowedon'tneedtoenterithereexplicitly.
*/
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 *isnohashinformationinthesocketbufferotherwiseit *wouldbeincorrectlyforwardedtothefrontend.
*/ 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 *freedupproperly!
*/
{ "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 *aguestwiththesameMAX_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. *Whentheguestselectsthedesirednumber,itwillbeupdated *vianetif_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);
}
/* If ballooning is disabled, this will consume real memory, so you *betterenableit.Thelongtermsolutionwouldbetousejusta *bunchofvalidpagedescriptors,withoutdependencyonballooning
*/
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;
}
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.