module_param(separate_tx_rx_irq, bool, 0644);
/* When guest ring is filled up, qdisc queues the packets for us, but we have
- * to timeout them, otherwise other guests' packets can get stucked there
+ * to timeout them, otherwise other guests' packets can get stuck there
*/
unsigned int rx_drain_timeout_msecs = 10000;
module_param(rx_drain_timeout_msecs, uint, 0444);
return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx));
}
+#define callback_param(vif, pending_idx) \
+ (vif->pending_tx_info[pending_idx].callback_struct)
+
/* Find the containing VIF's structure from a pointer in pending_tx_info array
*/
static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf)
return i & (MAX_PENDING_REQS-1);
}
-static inline pending_ring_idx_t nr_free_slots(struct xen_netif_tx_back_ring *ring)
-{
- return ring->nr_ents - (ring->sring->req_prod - ring->rsp_prod_pvt);
-}
-
bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed)
{
RING_IDX prod, cons;
* into multiple copies tend to give large frags their
* own buffers as before.
*/
- if ((offset + size > MAX_BUFFER_OFFSET) &&
- (size <= MAX_BUFFER_OFFSET) && offset && !head)
+ BUG_ON(size > MAX_BUFFER_OFFSET);
+ if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head)
return true;
return false;
struct gnttab_copy *copy_gop;
struct xenvif_rx_meta *meta;
unsigned long bytes;
- int gso_type;
+ int gso_type = XEN_NETIF_GSO_TYPE_NONE;
/* Data must not cross a page boundary. */
BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
}
/* Leave a gap for the GSO descriptor. */
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
- gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
- gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
- else
- gso_type = XEN_NETIF_GSO_TYPE_NONE;
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
+ }
if (*head && ((1 << gso_type) & vif->gso_mask))
vif->rx.req_cons++;
int head = 1;
int old_meta_prod;
int gso_type;
- int gso_size;
struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg;
grant_ref_t foreign_grefs[MAX_SKB_FRAGS];
struct xenvif *foreign_vif = NULL;
old_meta_prod = npo->meta_prod;
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
- gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
- gso_size = skb_shinfo(skb)->gso_size;
- } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
- gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
- gso_size = skb_shinfo(skb)->gso_size;
- } else {
- gso_type = XEN_NETIF_GSO_TYPE_NONE;
- gso_size = 0;
+ gso_type = XEN_NETIF_GSO_TYPE_NONE;
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
}
/* Set up a GSO prefix descriptor, if necessary */
req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
meta = npo->meta + npo->meta_prod++;
meta->gso_type = gso_type;
- meta->gso_size = gso_size;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
meta->size = 0;
meta->id = req->id;
}
if ((1 << gso_type) & vif->gso_mask) {
meta->gso_type = gso_type;
- meta->gso_size = gso_size;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
} else {
meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
meta->gso_size = 0;
while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) {
RING_IDX max_slots_needed;
+ RING_IDX old_req_cons;
+ RING_IDX ring_slots_used;
int i;
/* We need a cheap worse case estimate for the number of
PAGE_SIZE);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
unsigned int size;
+ unsigned int offset;
+
size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
- max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE);
+ offset = skb_shinfo(skb)->frags[i].page_offset;
+
+ /* For a worse-case estimate we need to factor in
+ * the fragment page offset as this will affect the
+ * number of times xenvif_gop_frag_copy() will
+ * call start_new_rx_buffer().
+ */
+ max_slots_needed += DIV_ROUND_UP(offset + size,
+ PAGE_SIZE);
}
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+
+ /* To avoid the estimate becoming too pessimal for some
+ * frontends that limit posted rx requests, cap the estimate
+ * at MAX_SKB_FRAGS.
+ */
+ if (max_slots_needed > MAX_SKB_FRAGS)
+ max_slots_needed = MAX_SKB_FRAGS;
+
+ /* We may need one more slot for GSO metadata */
+ if (skb_is_gso(skb) &&
+ (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
+ skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
max_slots_needed++;
/* If the skb may not fit then bail out now */
} else
vif->rx_last_skb_slots = 0;
+ old_req_cons = vif->rx.req_cons;
XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo);
- BUG_ON(XENVIF_RX_CB(skb)->meta_slots_used > max_slots_needed);
+ ring_slots_used = vif->rx.req_cons - old_req_cons;
+
+ BUG_ON(ring_slots_used > max_slots_needed);
__skb_queue_tail(&rxq, skb);
}
static void xenvif_fatal_tx_err(struct xenvif *vif)
{
netdev_err(vif->dev, "fatal error; disabling device\n");
- xenvif_carrier_off(vif);
+ vif->disabled = true;
+ xenvif_kick_thread(vif);
}
static int xenvif_count_requests(struct xenvif *vif,
/* If this is not the first frag, chain it to the previous*/
if (unlikely(prev_pending_idx == INVALID_PENDING_IDX))
skb_shinfo(skb)->destructor_arg =
- &vif->pending_tx_info[pending_idx].callback_struct;
+ &callback_param(vif, pending_idx);
else if (likely(pending_idx != prev_pending_idx))
- vif->pending_tx_info[prev_pending_idx].callback_struct.ctx =
- &(vif->pending_tx_info[pending_idx].callback_struct);
+ callback_param(vif, prev_pending_idx).ctx =
+ &callback_param(vif, pending_idx);
- vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL;
+ callback_param(vif, pending_idx).ctx = NULL;
prev_pending_idx = pending_idx;
txp = &vif->pending_tx_info[pending_idx].req;
struct sk_buff *skb;
int ret;
- while (xenvif_tx_pending_slots_available(vif) &&
- (skb_queue_len(&vif->tx_queue) < budget)) {
+ while (skb_queue_len(&vif->tx_queue) < budget) {
struct xen_netif_tx_request txreq;
struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
vif->tx.sring->req_prod, vif->tx.req_cons,
XEN_NETIF_TX_RING_SIZE);
xenvif_fatal_tx_err(vif);
- continue;
+ break;
}
work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx);
memcpy(skb->data,
(void *)(idx_to_kaddr(vif, pending_idx)|txp->offset),
data_len);
- vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL;
+ callback_param(vif, pending_idx).ctx = NULL;
if (data_len < txp->size) {
/* Append the packet payload as a fragment. */
txp->offset += data_len;
txp->size -= data_len;
skb_shinfo(skb)->destructor_arg =
- &vif->pending_tx_info[pending_idx].callback_struct;
+ &callback_param(vif, pending_idx);
} else {
/* Schedule a response immediately. */
xenvif_idx_unmap(vif, pending_idx);
wake_up(&vif->dealloc_wq);
spin_unlock_irqrestore(&vif->callback_lock, flags);
- if (RING_HAS_UNCONSUMED_REQUESTS(&vif->tx) &&
- xenvif_tx_pending_slots_available(vif)) {
- local_bh_disable();
- napi_schedule(&vif->napi);
- local_bh_enable();
- }
-
if (likely(zerocopy_success))
vif->tx_zerocopy_success++;
else
idx_to_kaddr(vif, pending_idx),
GNTMAP_host_map,
vif->grant_tx_handle[pending_idx]);
- /* Btw. already unmapped? */
xenvif_grant_handle_reset(vif, pending_idx);
++gop;
}
vif->pages_to_unmap,
gop - vif->tx_unmap_ops);
if (ret) {
- netdev_err(vif->dev, "Unmap fail: nr_ops %x ret %d\n",
+ netdev_err(vif->dev, "Unmap fail: nr_ops %tx ret %d\n",
gop - vif->tx_unmap_ops, ret);
for (i = 0; i < gop - vif->tx_unmap_ops; ++i) {
if (gop[i].status != GNTST_okay)
idx_to_kaddr(vif, pending_idx),
GNTMAP_host_map,
vif->grant_tx_handle[pending_idx]);
- /* Btw. already unmapped? */
xenvif_grant_handle_reset(vif, pending_idx);
ret = gnttab_unmap_refs(&tx_unmap_op, NULL,
&vif->mmap_pages[pending_idx], 1);
- BUG_ON(ret);
+ if (ret) {
+ netdev_err(vif->dev,
+ "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: %x status: %d\n",
+ ret,
+ pending_idx,
+ tx_unmap_op.host_addr,
+ tx_unmap_op.handle,
+ tx_unmap_op.status);
+ BUG();
+ }
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
}
static inline int tx_work_todo(struct xenvif *vif)
{
- if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) &&
- xenvif_tx_pending_slots_available(vif))
+ if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)))
return 1;
return 0;
}
-static void xenvif_dealloc_delay(unsigned long data)
-{
- struct xenvif *vif = (struct xenvif *)data;
-
- vif->dealloc_delay_timed_out = true;
- wake_up(&vif->dealloc_wq);
-}
-
static inline bool tx_dealloc_work_todo(struct xenvif *vif)
{
- if (vif->dealloc_cons != vif->dealloc_prod) {
- if ((nr_free_slots(&vif->tx) > 2 * XEN_NETBK_LEGACY_SLOTS_MAX) &&
- (vif->dealloc_prod - vif->dealloc_cons < MAX_PENDING_REQS / 4) &&
- !vif->dealloc_delay_timed_out) {
- if (!timer_pending(&vif->dealloc_delay)) {
- vif->dealloc_delay.function =
- xenvif_dealloc_delay;
- vif->dealloc_delay.data = (unsigned long)vif;
- mod_timer(&vif->dealloc_delay,
- jiffies + msecs_to_jiffies(1));
-
- }
- return false;
- }
- del_timer_sync(&vif->dealloc_delay);
- vif->dealloc_delay_timed_out = false;
- return true;
- }
-
- return false;
+ return vif->dealloc_cons != vif->dealloc_prod;
}
void xenvif_unmap_frontend_rings(struct xenvif *vif)
while (!kthread_should_stop()) {
wait_event_interruptible(vif->wq,
rx_work_todo(vif) ||
+ vif->disabled ||
kthread_should_stop());
+
+ /* This frontend is found to be rogue, disable it in
+ * kthread context. Currently this is only set when
+ * netback finds out frontend sends malformed packet,
+ * but we cannot disable the interface in softirq
+ * context so we defer it here.
+ */
+ if (unlikely(vif->disabled && netif_carrier_ok(vif->dev)))
+ xenvif_carrier_off(vif);
+
if (kthread_should_stop())
break;