diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/xen-netback/common.h | 5 | ||||
-rw-r--r-- | drivers/net/xen-netback/interface.c | 11 | ||||
-rw-r--r-- | drivers/net/xen-netback/netback.c | 16 |
3 files changed, 30 insertions, 2 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 89b2d429c440..89d1d0556b6e 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
@@ -104,6 +104,11 @@ struct xenvif { | |||
104 | domid_t domid; | 104 | domid_t domid; |
105 | unsigned int handle; | 105 | unsigned int handle; |
106 | 106 | ||
107 | /* Is this interface disabled? True when backend discovers | ||
108 | * frontend is rogue. | ||
109 | */ | ||
110 | bool disabled; | ||
111 | |||
107 | /* Use NAPI for guest TX */ | 112 | /* Use NAPI for guest TX */ |
108 | struct napi_struct napi; | 113 | struct napi_struct napi; |
109 | /* When feature-split-event-channels = 0, tx_irq = rx_irq. */ | 114 | /* When feature-split-event-channels = 0, tx_irq = rx_irq. */ |
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index cdc298e3b747..ef05c5c49d41 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
@@ -63,6 +63,15 @@ static int xenvif_poll(struct napi_struct *napi, int budget) | |||
63 | struct xenvif *vif = container_of(napi, struct xenvif, napi); | 63 | struct xenvif *vif = container_of(napi, struct xenvif, napi); |
64 | int work_done; | 64 | int work_done; |
65 | 65 | ||
66 | /* This vif is rogue, we pretend we've there is nothing to do | ||
67 | * for this vif to deschedule it from NAPI. But this interface | ||
68 | * will be turned off in thread context later. | ||
69 | */ | ||
70 | if (unlikely(vif->disabled)) { | ||
71 | napi_complete(napi); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
66 | work_done = xenvif_tx_action(vif, budget); | 75 | work_done = xenvif_tx_action(vif, budget); |
67 | 76 | ||
68 | if (work_done < budget) { | 77 | if (work_done < budget) { |
@@ -363,6 +372,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, | |||
363 | vif->ip_csum = 1; | 372 | vif->ip_csum = 1; |
364 | vif->dev = dev; | 373 | vif->dev = dev; |
365 | 374 | ||
375 | vif->disabled = false; | ||
376 | |||
366 | vif->credit_bytes = vif->remaining_credit = ~0UL; | 377 | vif->credit_bytes = vif->remaining_credit = ~0UL; |
367 | vif->credit_usec = 0UL; | 378 | vif->credit_usec = 0UL; |
368 | init_timer(&vif->credit_timeout); | 379 | init_timer(&vif->credit_timeout); |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index ae34f5fc7fbc..3f021e054ba1 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -711,7 +711,8 @@ static void xenvif_tx_err(struct xenvif *vif, | |||
711 | static void xenvif_fatal_tx_err(struct xenvif *vif) | 711 | static void xenvif_fatal_tx_err(struct xenvif *vif) |
712 | { | 712 | { |
713 | netdev_err(vif->dev, "fatal error; disabling device\n"); | 713 | netdev_err(vif->dev, "fatal error; disabling device\n"); |
714 | xenvif_carrier_off(vif); | 714 | vif->disabled = true; |
715 | xenvif_kick_thread(vif); | ||
715 | } | 716 | } |
716 | 717 | ||
717 | static int xenvif_count_requests(struct xenvif *vif, | 718 | static int xenvif_count_requests(struct xenvif *vif, |
@@ -1212,7 +1213,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) | |||
1212 | vif->tx.sring->req_prod, vif->tx.req_cons, | 1213 | vif->tx.sring->req_prod, vif->tx.req_cons, |
1213 | XEN_NETIF_TX_RING_SIZE); | 1214 | XEN_NETIF_TX_RING_SIZE); |
1214 | xenvif_fatal_tx_err(vif); | 1215 | xenvif_fatal_tx_err(vif); |
1215 | continue; | 1216 | break; |
1216 | } | 1217 | } |
1217 | 1218 | ||
1218 | work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx); | 1219 | work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx); |
@@ -1808,7 +1809,18 @@ int xenvif_kthread_guest_rx(void *data) | |||
1808 | while (!kthread_should_stop()) { | 1809 | while (!kthread_should_stop()) { |
1809 | wait_event_interruptible(vif->wq, | 1810 | wait_event_interruptible(vif->wq, |
1810 | rx_work_todo(vif) || | 1811 | rx_work_todo(vif) || |
1812 | vif->disabled || | ||
1811 | kthread_should_stop()); | 1813 | kthread_should_stop()); |
1814 | |||
1815 | /* This frontend is found to be rogue, disable it in | ||
1816 | * kthread context. Currently this is only set when | ||
1817 | * netback finds out frontend sends malformed packet, | ||
1818 | * but we cannot disable the interface in softirq | ||
1819 | * context so we defer it here. | ||
1820 | */ | ||
1821 | if (unlikely(vif->disabled && netif_carrier_ok(vif->dev))) | ||
1822 | xenvif_carrier_off(vif); | ||
1823 | |||
1812 | if (kthread_should_stop()) | 1824 | if (kthread_should_stop()) |
1813 | break; | 1825 | break; |
1814 | 1826 | ||