diff options
78 files changed, 1021 insertions, 361 deletions
diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index 68ef0a4cd821..b0c80859f746 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c | |||
@@ -342,7 +342,7 @@ static int sun4i_can_start(struct net_device *dev) | |||
342 | 342 | ||
343 | /* enter the selected mode */ | 343 | /* enter the selected mode */ |
344 | mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); | 344 | mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); |
345 | if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) | 345 | if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) |
346 | mod_reg_val |= SUN4I_MSEL_LOOPBACK_MODE; | 346 | mod_reg_val |= SUN4I_MSEL_LOOPBACK_MODE; |
347 | else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) | 347 | else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) |
348 | mod_reg_val |= SUN4I_MSEL_LISTEN_ONLY_MODE; | 348 | mod_reg_val |= SUN4I_MSEL_LISTEN_ONLY_MODE; |
@@ -811,7 +811,6 @@ static int sun4ican_probe(struct platform_device *pdev) | |||
811 | priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | | 811 | priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | |
812 | CAN_CTRLMODE_LISTENONLY | | 812 | CAN_CTRLMODE_LISTENONLY | |
813 | CAN_CTRLMODE_LOOPBACK | | 813 | CAN_CTRLMODE_LOOPBACK | |
814 | CAN_CTRLMODE_PRESUME_ACK | | ||
815 | CAN_CTRLMODE_3_SAMPLES; | 814 | CAN_CTRLMODE_3_SAMPLES; |
816 | priv->base = addr; | 815 | priv->base = addr; |
817 | priv->clk = clk; | 816 | priv->clk = clk; |
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 18cc529fb807..9b18d96ef526 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c | |||
@@ -137,6 +137,7 @@ static inline bool kvaser_is_usbcan(const struct usb_device_id *id) | |||
137 | #define CMD_RESET_ERROR_COUNTER 49 | 137 | #define CMD_RESET_ERROR_COUNTER 49 |
138 | #define CMD_TX_ACKNOWLEDGE 50 | 138 | #define CMD_TX_ACKNOWLEDGE 50 |
139 | #define CMD_CAN_ERROR_EVENT 51 | 139 | #define CMD_CAN_ERROR_EVENT 51 |
140 | #define CMD_FLUSH_QUEUE_REPLY 68 | ||
140 | 141 | ||
141 | #define CMD_LEAF_USB_THROTTLE 77 | 142 | #define CMD_LEAF_USB_THROTTLE 77 |
142 | #define CMD_LEAF_LOG_MESSAGE 106 | 143 | #define CMD_LEAF_LOG_MESSAGE 106 |
@@ -1301,6 +1302,11 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev, | |||
1301 | goto warn; | 1302 | goto warn; |
1302 | break; | 1303 | break; |
1303 | 1304 | ||
1305 | case CMD_FLUSH_QUEUE_REPLY: | ||
1306 | if (dev->family != KVASER_LEAF) | ||
1307 | goto warn; | ||
1308 | break; | ||
1309 | |||
1304 | default: | 1310 | default: |
1305 | warn: dev_warn(dev->udev->dev.parent, | 1311 | warn: dev_warn(dev->udev->dev.parent, |
1306 | "Unhandled message (%d)\n", msg->id); | 1312 | "Unhandled message (%d)\n", msg->id); |
@@ -1609,7 +1615,8 @@ static int kvaser_usb_close(struct net_device *netdev) | |||
1609 | if (err) | 1615 | if (err) |
1610 | netdev_warn(netdev, "Cannot flush queue, error %d\n", err); | 1616 | netdev_warn(netdev, "Cannot flush queue, error %d\n", err); |
1611 | 1617 | ||
1612 | if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel)) | 1618 | err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel); |
1619 | if (err) | ||
1613 | netdev_warn(netdev, "Cannot reset card, error %d\n", err); | 1620 | netdev_warn(netdev, "Cannot reset card, error %d\n", err); |
1614 | 1621 | ||
1615 | err = kvaser_usb_stop_chip(priv); | 1622 | err = kvaser_usb_stop_chip(priv); |
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index ec8aa4562cc9..3b3983a1ffbb 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c | |||
@@ -1824,11 +1824,12 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, | |||
1824 | { | 1824 | { |
1825 | struct e1000_adapter *adapter = netdev_priv(netdev); | 1825 | struct e1000_adapter *adapter = netdev_priv(netdev); |
1826 | int i; | 1826 | int i; |
1827 | char *p = NULL; | ||
1828 | const struct e1000_stats *stat = e1000_gstrings_stats; | 1827 | const struct e1000_stats *stat = e1000_gstrings_stats; |
1829 | 1828 | ||
1830 | e1000_update_stats(adapter); | 1829 | e1000_update_stats(adapter); |
1831 | for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { | 1830 | for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++, stat++) { |
1831 | char *p; | ||
1832 | |||
1832 | switch (stat->type) { | 1833 | switch (stat->type) { |
1833 | case NETDEV_STATS: | 1834 | case NETDEV_STATS: |
1834 | p = (char *)netdev + stat->stat_offset; | 1835 | p = (char *)netdev + stat->stat_offset; |
@@ -1839,15 +1840,13 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, | |||
1839 | default: | 1840 | default: |
1840 | WARN_ONCE(1, "Invalid E1000 stat type: %u index %d\n", | 1841 | WARN_ONCE(1, "Invalid E1000 stat type: %u index %d\n", |
1841 | stat->type, i); | 1842 | stat->type, i); |
1842 | break; | 1843 | continue; |
1843 | } | 1844 | } |
1844 | 1845 | ||
1845 | if (stat->sizeof_stat == sizeof(u64)) | 1846 | if (stat->sizeof_stat == sizeof(u64)) |
1846 | data[i] = *(u64 *)p; | 1847 | data[i] = *(u64 *)p; |
1847 | else | 1848 | else |
1848 | data[i] = *(u32 *)p; | 1849 | data[i] = *(u32 *)p; |
1849 | |||
1850 | stat++; | ||
1851 | } | 1850 | } |
1852 | /* BUG_ON(i != E1000_STATS_LEN); */ | 1851 | /* BUG_ON(i != E1000_STATS_LEN); */ |
1853 | } | 1852 | } |
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 98375e1e1185..1982f7917a8d 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c | |||
@@ -520,8 +520,6 @@ void e1000_down(struct e1000_adapter *adapter) | |||
520 | struct net_device *netdev = adapter->netdev; | 520 | struct net_device *netdev = adapter->netdev; |
521 | u32 rctl, tctl; | 521 | u32 rctl, tctl; |
522 | 522 | ||
523 | netif_carrier_off(netdev); | ||
524 | |||
525 | /* disable receives in the hardware */ | 523 | /* disable receives in the hardware */ |
526 | rctl = er32(RCTL); | 524 | rctl = er32(RCTL); |
527 | ew32(RCTL, rctl & ~E1000_RCTL_EN); | 525 | ew32(RCTL, rctl & ~E1000_RCTL_EN); |
@@ -537,6 +535,15 @@ void e1000_down(struct e1000_adapter *adapter) | |||
537 | E1000_WRITE_FLUSH(); | 535 | E1000_WRITE_FLUSH(); |
538 | msleep(10); | 536 | msleep(10); |
539 | 537 | ||
538 | /* Set the carrier off after transmits have been disabled in the | ||
539 | * hardware, to avoid race conditions with e1000_watchdog() (which | ||
540 | * may be running concurrently to us, checking for the carrier | ||
541 | * bit to decide whether it should enable transmits again). Such | ||
542 | * a race condition would result into transmission being disabled | ||
543 | * in the hardware until the next IFF_DOWN+IFF_UP cycle. | ||
544 | */ | ||
545 | netif_carrier_off(netdev); | ||
546 | |||
540 | napi_disable(&adapter->napi); | 547 | napi_disable(&adapter->napi); |
541 | 548 | ||
542 | e1000_irq_disable(adapter); | 549 | e1000_irq_disable(adapter); |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 2756131495f0..120c68f78951 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c | |||
@@ -2102,6 +2102,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) | |||
2102 | 2102 | ||
2103 | if (unlikely(i40e_rx_is_programming_status(qword))) { | 2103 | if (unlikely(i40e_rx_is_programming_status(qword))) { |
2104 | i40e_clean_programming_status(rx_ring, rx_desc, qword); | 2104 | i40e_clean_programming_status(rx_ring, rx_desc, qword); |
2105 | cleaned_count++; | ||
2105 | continue; | 2106 | continue; |
2106 | } | 2107 | } |
2107 | size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> | 2108 | size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> |
@@ -2269,7 +2270,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, | |||
2269 | goto enable_int; | 2270 | goto enable_int; |
2270 | } | 2271 | } |
2271 | 2272 | ||
2272 | if (ITR_IS_DYNAMIC(tx_itr_setting)) { | 2273 | if (ITR_IS_DYNAMIC(rx_itr_setting)) { |
2273 | rx = i40e_set_new_dynamic_itr(&q_vector->rx); | 2274 | rx = i40e_set_new_dynamic_itr(&q_vector->rx); |
2274 | rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr); | 2275 | rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr); |
2275 | } | 2276 | } |
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index fd4a46b03cc8..ea69af267d63 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c | |||
@@ -5326,7 +5326,7 @@ dma_error: | |||
5326 | DMA_TO_DEVICE); | 5326 | DMA_TO_DEVICE); |
5327 | dma_unmap_len_set(tx_buffer, len, 0); | 5327 | dma_unmap_len_set(tx_buffer, len, 0); |
5328 | 5328 | ||
5329 | if (i--) | 5329 | if (i-- == 0) |
5330 | i += tx_ring->count; | 5330 | i += tx_ring->count; |
5331 | tx_buffer = &tx_ring->tx_buffer_info[i]; | 5331 | tx_buffer = &tx_ring->tx_buffer_info[i]; |
5332 | } | 5332 | } |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 4d76afd13868..6d5f31e94358 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
@@ -8020,29 +8020,23 @@ static int ixgbe_tx_map(struct ixgbe_ring *tx_ring, | |||
8020 | return 0; | 8020 | return 0; |
8021 | dma_error: | 8021 | dma_error: |
8022 | dev_err(tx_ring->dev, "TX DMA map failed\n"); | 8022 | dev_err(tx_ring->dev, "TX DMA map failed\n"); |
8023 | tx_buffer = &tx_ring->tx_buffer_info[i]; | ||
8024 | 8023 | ||
8025 | /* clear dma mappings for failed tx_buffer_info map */ | 8024 | /* clear dma mappings for failed tx_buffer_info map */ |
8026 | while (tx_buffer != first) { | 8025 | for (;;) { |
8026 | tx_buffer = &tx_ring->tx_buffer_info[i]; | ||
8027 | if (dma_unmap_len(tx_buffer, len)) | 8027 | if (dma_unmap_len(tx_buffer, len)) |
8028 | dma_unmap_page(tx_ring->dev, | 8028 | dma_unmap_page(tx_ring->dev, |
8029 | dma_unmap_addr(tx_buffer, dma), | 8029 | dma_unmap_addr(tx_buffer, dma), |
8030 | dma_unmap_len(tx_buffer, len), | 8030 | dma_unmap_len(tx_buffer, len), |
8031 | DMA_TO_DEVICE); | 8031 | DMA_TO_DEVICE); |
8032 | dma_unmap_len_set(tx_buffer, len, 0); | 8032 | dma_unmap_len_set(tx_buffer, len, 0); |
8033 | 8033 | if (tx_buffer == first) | |
8034 | if (i--) | 8034 | break; |
8035 | if (i == 0) | ||
8035 | i += tx_ring->count; | 8036 | i += tx_ring->count; |
8036 | tx_buffer = &tx_ring->tx_buffer_info[i]; | 8037 | i--; |
8037 | } | 8038 | } |
8038 | 8039 | ||
8039 | if (dma_unmap_len(tx_buffer, len)) | ||
8040 | dma_unmap_single(tx_ring->dev, | ||
8041 | dma_unmap_addr(tx_buffer, dma), | ||
8042 | dma_unmap_len(tx_buffer, len), | ||
8043 | DMA_TO_DEVICE); | ||
8044 | dma_unmap_len_set(tx_buffer, len, 0); | ||
8045 | |||
8046 | dev_kfree_skb_any(first->skb); | 8040 | dev_kfree_skb_any(first->skb); |
8047 | first->skb = NULL; | 8041 | first->skb = NULL; |
8048 | 8042 | ||
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 9c86cb7cb988..a37af5813f33 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c | |||
@@ -1167,6 +1167,11 @@ struct mvpp2_bm_pool { | |||
1167 | u32 port_map; | 1167 | u32 port_map; |
1168 | }; | 1168 | }; |
1169 | 1169 | ||
1170 | #define IS_TSO_HEADER(txq_pcpu, addr) \ | ||
1171 | ((addr) >= (txq_pcpu)->tso_headers_dma && \ | ||
1172 | (addr) < (txq_pcpu)->tso_headers_dma + \ | ||
1173 | (txq_pcpu)->size * TSO_HEADER_SIZE) | ||
1174 | |||
1170 | /* Queue modes */ | 1175 | /* Queue modes */ |
1171 | #define MVPP2_QDIST_SINGLE_MODE 0 | 1176 | #define MVPP2_QDIST_SINGLE_MODE 0 |
1172 | #define MVPP2_QDIST_MULTI_MODE 1 | 1177 | #define MVPP2_QDIST_MULTI_MODE 1 |
@@ -1534,7 +1539,7 @@ static bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs, | |||
1534 | int off = MVPP2_PRS_TCAM_DATA_BYTE(offs); | 1539 | int off = MVPP2_PRS_TCAM_DATA_BYTE(offs); |
1535 | u16 tcam_data; | 1540 | u16 tcam_data; |
1536 | 1541 | ||
1537 | tcam_data = (8 << pe->tcam.byte[off + 1]) | pe->tcam.byte[off]; | 1542 | tcam_data = (pe->tcam.byte[off + 1] << 8) | pe->tcam.byte[off]; |
1538 | if (tcam_data != data) | 1543 | if (tcam_data != data) |
1539 | return false; | 1544 | return false; |
1540 | return true; | 1545 | return true; |
@@ -2609,8 +2614,8 @@ static void mvpp2_prs_mac_init(struct mvpp2 *priv) | |||
2609 | /* place holders only - no ports */ | 2614 | /* place holders only - no ports */ |
2610 | mvpp2_prs_mac_drop_all_set(priv, 0, false); | 2615 | mvpp2_prs_mac_drop_all_set(priv, 0, false); |
2611 | mvpp2_prs_mac_promisc_set(priv, 0, false); | 2616 | mvpp2_prs_mac_promisc_set(priv, 0, false); |
2612 | mvpp2_prs_mac_multi_set(priv, MVPP2_PE_MAC_MC_ALL, 0, false); | 2617 | mvpp2_prs_mac_multi_set(priv, 0, MVPP2_PE_MAC_MC_ALL, false); |
2613 | mvpp2_prs_mac_multi_set(priv, MVPP2_PE_MAC_MC_IP6, 0, false); | 2618 | mvpp2_prs_mac_multi_set(priv, 0, MVPP2_PE_MAC_MC_IP6, false); |
2614 | } | 2619 | } |
2615 | 2620 | ||
2616 | /* Set default entries for various types of dsa packets */ | 2621 | /* Set default entries for various types of dsa packets */ |
@@ -3391,7 +3396,7 @@ mvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da, | |||
3391 | struct mvpp2_prs_entry *pe; | 3396 | struct mvpp2_prs_entry *pe; |
3392 | int tid; | 3397 | int tid; |
3393 | 3398 | ||
3394 | pe = kzalloc(sizeof(*pe), GFP_KERNEL); | 3399 | pe = kzalloc(sizeof(*pe), GFP_ATOMIC); |
3395 | if (!pe) | 3400 | if (!pe) |
3396 | return NULL; | 3401 | return NULL; |
3397 | mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC); | 3402 | mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC); |
@@ -3453,7 +3458,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port, | |||
3453 | if (tid < 0) | 3458 | if (tid < 0) |
3454 | return tid; | 3459 | return tid; |
3455 | 3460 | ||
3456 | pe = kzalloc(sizeof(*pe), GFP_KERNEL); | 3461 | pe = kzalloc(sizeof(*pe), GFP_ATOMIC); |
3457 | if (!pe) | 3462 | if (!pe) |
3458 | return -ENOMEM; | 3463 | return -ENOMEM; |
3459 | mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC); | 3464 | mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC); |
@@ -5321,8 +5326,9 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, | |||
5321 | struct mvpp2_txq_pcpu_buf *tx_buf = | 5326 | struct mvpp2_txq_pcpu_buf *tx_buf = |
5322 | txq_pcpu->buffs + txq_pcpu->txq_get_index; | 5327 | txq_pcpu->buffs + txq_pcpu->txq_get_index; |
5323 | 5328 | ||
5324 | dma_unmap_single(port->dev->dev.parent, tx_buf->dma, | 5329 | if (!IS_TSO_HEADER(txq_pcpu, tx_buf->dma)) |
5325 | tx_buf->size, DMA_TO_DEVICE); | 5330 | dma_unmap_single(port->dev->dev.parent, tx_buf->dma, |
5331 | tx_buf->size, DMA_TO_DEVICE); | ||
5326 | if (tx_buf->skb) | 5332 | if (tx_buf->skb) |
5327 | dev_kfree_skb_any(tx_buf->skb); | 5333 | dev_kfree_skb_any(tx_buf->skb); |
5328 | 5334 | ||
@@ -5609,7 +5615,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, | |||
5609 | 5615 | ||
5610 | txq_pcpu->tso_headers = | 5616 | txq_pcpu->tso_headers = |
5611 | dma_alloc_coherent(port->dev->dev.parent, | 5617 | dma_alloc_coherent(port->dev->dev.parent, |
5612 | MVPP2_AGGR_TXQ_SIZE * TSO_HEADER_SIZE, | 5618 | txq_pcpu->size * TSO_HEADER_SIZE, |
5613 | &txq_pcpu->tso_headers_dma, | 5619 | &txq_pcpu->tso_headers_dma, |
5614 | GFP_KERNEL); | 5620 | GFP_KERNEL); |
5615 | if (!txq_pcpu->tso_headers) | 5621 | if (!txq_pcpu->tso_headers) |
@@ -5623,7 +5629,7 @@ cleanup: | |||
5623 | kfree(txq_pcpu->buffs); | 5629 | kfree(txq_pcpu->buffs); |
5624 | 5630 | ||
5625 | dma_free_coherent(port->dev->dev.parent, | 5631 | dma_free_coherent(port->dev->dev.parent, |
5626 | MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE, | 5632 | txq_pcpu->size * TSO_HEADER_SIZE, |
5627 | txq_pcpu->tso_headers, | 5633 | txq_pcpu->tso_headers, |
5628 | txq_pcpu->tso_headers_dma); | 5634 | txq_pcpu->tso_headers_dma); |
5629 | } | 5635 | } |
@@ -5647,7 +5653,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, | |||
5647 | kfree(txq_pcpu->buffs); | 5653 | kfree(txq_pcpu->buffs); |
5648 | 5654 | ||
5649 | dma_free_coherent(port->dev->dev.parent, | 5655 | dma_free_coherent(port->dev->dev.parent, |
5650 | MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE, | 5656 | txq_pcpu->size * TSO_HEADER_SIZE, |
5651 | txq_pcpu->tso_headers, | 5657 | txq_pcpu->tso_headers, |
5652 | txq_pcpu->tso_headers_dma); | 5658 | txq_pcpu->tso_headers_dma); |
5653 | } | 5659 | } |
@@ -6212,12 +6218,15 @@ static inline void | |||
6212 | tx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, | 6218 | tx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, |
6213 | struct mvpp2_tx_desc *desc) | 6219 | struct mvpp2_tx_desc *desc) |
6214 | { | 6220 | { |
6221 | struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu); | ||
6222 | |||
6215 | dma_addr_t buf_dma_addr = | 6223 | dma_addr_t buf_dma_addr = |
6216 | mvpp2_txdesc_dma_addr_get(port, desc); | 6224 | mvpp2_txdesc_dma_addr_get(port, desc); |
6217 | size_t buf_sz = | 6225 | size_t buf_sz = |
6218 | mvpp2_txdesc_size_get(port, desc); | 6226 | mvpp2_txdesc_size_get(port, desc); |
6219 | dma_unmap_single(port->dev->dev.parent, buf_dma_addr, | 6227 | if (!IS_TSO_HEADER(txq_pcpu, buf_dma_addr)) |
6220 | buf_sz, DMA_TO_DEVICE); | 6228 | dma_unmap_single(port->dev->dev.parent, buf_dma_addr, |
6229 | buf_sz, DMA_TO_DEVICE); | ||
6221 | mvpp2_txq_desc_put(txq); | 6230 | mvpp2_txq_desc_put(txq); |
6222 | } | 6231 | } |
6223 | 6232 | ||
@@ -6490,7 +6499,7 @@ out: | |||
6490 | } | 6499 | } |
6491 | 6500 | ||
6492 | /* Finalize TX processing */ | 6501 | /* Finalize TX processing */ |
6493 | if (txq_pcpu->count >= txq->done_pkts_coal) | 6502 | if (!port->has_tx_irqs && txq_pcpu->count >= txq->done_pkts_coal) |
6494 | mvpp2_txq_done(port, txq, txq_pcpu); | 6503 | mvpp2_txq_done(port, txq, txq_pcpu); |
6495 | 6504 | ||
6496 | /* Set the timer in case not all frags were processed */ | 6505 | /* Set the timer in case not all frags were processed */ |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index ff60cf7342ca..fc281712869b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c | |||
@@ -77,35 +77,41 @@ static void add_delayed_event(struct mlx5_priv *priv, | |||
77 | list_add_tail(&delayed_event->list, &priv->waiting_events_list); | 77 | list_add_tail(&delayed_event->list, &priv->waiting_events_list); |
78 | } | 78 | } |
79 | 79 | ||
80 | static void fire_delayed_event_locked(struct mlx5_device_context *dev_ctx, | 80 | static void delayed_event_release(struct mlx5_device_context *dev_ctx, |
81 | struct mlx5_core_dev *dev, | 81 | struct mlx5_priv *priv) |
82 | struct mlx5_priv *priv) | ||
83 | { | 82 | { |
83 | struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); | ||
84 | struct mlx5_delayed_event *de; | 84 | struct mlx5_delayed_event *de; |
85 | struct mlx5_delayed_event *n; | 85 | struct mlx5_delayed_event *n; |
86 | struct list_head temp; | ||
86 | 87 | ||
87 | /* stop delaying events */ | 88 | INIT_LIST_HEAD(&temp); |
88 | priv->is_accum_events = false; | 89 | |
90 | spin_lock_irq(&priv->ctx_lock); | ||
89 | 91 | ||
90 | /* fire all accumulated events before new event comes */ | 92 | priv->is_accum_events = false; |
91 | list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) { | 93 | list_splice_init(&priv->waiting_events_list, &temp); |
94 | if (!dev_ctx->context) | ||
95 | goto out; | ||
96 | list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) | ||
92 | dev_ctx->intf->event(dev, dev_ctx->context, de->event, de->param); | 97 | dev_ctx->intf->event(dev, dev_ctx->context, de->event, de->param); |
98 | |||
99 | out: | ||
100 | spin_unlock_irq(&priv->ctx_lock); | ||
101 | |||
102 | list_for_each_entry_safe(de, n, &temp, list) { | ||
93 | list_del(&de->list); | 103 | list_del(&de->list); |
94 | kfree(de); | 104 | kfree(de); |
95 | } | 105 | } |
96 | } | 106 | } |
97 | 107 | ||
98 | static void cleanup_delayed_evets(struct mlx5_priv *priv) | 108 | /* accumulating events that can come after mlx5_ib calls to |
109 | * ib_register_device, till adding that interface to the events list. | ||
110 | */ | ||
111 | static void delayed_event_start(struct mlx5_priv *priv) | ||
99 | { | 112 | { |
100 | struct mlx5_delayed_event *de; | ||
101 | struct mlx5_delayed_event *n; | ||
102 | |||
103 | spin_lock_irq(&priv->ctx_lock); | 113 | spin_lock_irq(&priv->ctx_lock); |
104 | priv->is_accum_events = false; | 114 | priv->is_accum_events = true; |
105 | list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) { | ||
106 | list_del(&de->list); | ||
107 | kfree(de); | ||
108 | } | ||
109 | spin_unlock_irq(&priv->ctx_lock); | 115 | spin_unlock_irq(&priv->ctx_lock); |
110 | } | 116 | } |
111 | 117 | ||
@@ -122,11 +128,8 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv) | |||
122 | return; | 128 | return; |
123 | 129 | ||
124 | dev_ctx->intf = intf; | 130 | dev_ctx->intf = intf; |
125 | /* accumulating events that can come after mlx5_ib calls to | ||
126 | * ib_register_device, till adding that interface to the events list. | ||
127 | */ | ||
128 | 131 | ||
129 | priv->is_accum_events = true; | 132 | delayed_event_start(priv); |
130 | 133 | ||
131 | dev_ctx->context = intf->add(dev); | 134 | dev_ctx->context = intf->add(dev); |
132 | set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); | 135 | set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); |
@@ -137,8 +140,6 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv) | |||
137 | spin_lock_irq(&priv->ctx_lock); | 140 | spin_lock_irq(&priv->ctx_lock); |
138 | list_add_tail(&dev_ctx->list, &priv->ctx_list); | 141 | list_add_tail(&dev_ctx->list, &priv->ctx_list); |
139 | 142 | ||
140 | fire_delayed_event_locked(dev_ctx, dev, priv); | ||
141 | |||
142 | #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING | 143 | #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING |
143 | if (dev_ctx->intf->pfault) { | 144 | if (dev_ctx->intf->pfault) { |
144 | if (priv->pfault) { | 145 | if (priv->pfault) { |
@@ -150,11 +151,12 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv) | |||
150 | } | 151 | } |
151 | #endif | 152 | #endif |
152 | spin_unlock_irq(&priv->ctx_lock); | 153 | spin_unlock_irq(&priv->ctx_lock); |
153 | } else { | ||
154 | kfree(dev_ctx); | ||
155 | /* delete all accumulated events */ | ||
156 | cleanup_delayed_evets(priv); | ||
157 | } | 154 | } |
155 | |||
156 | delayed_event_release(dev_ctx, priv); | ||
157 | |||
158 | if (!dev_ctx->context) | ||
159 | kfree(dev_ctx); | ||
158 | } | 160 | } |
159 | 161 | ||
160 | static struct mlx5_device_context *mlx5_get_device(struct mlx5_interface *intf, | 162 | static struct mlx5_device_context *mlx5_get_device(struct mlx5_interface *intf, |
@@ -205,17 +207,21 @@ static void mlx5_attach_interface(struct mlx5_interface *intf, struct mlx5_priv | |||
205 | if (!dev_ctx) | 207 | if (!dev_ctx) |
206 | return; | 208 | return; |
207 | 209 | ||
210 | delayed_event_start(priv); | ||
208 | if (intf->attach) { | 211 | if (intf->attach) { |
209 | if (test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state)) | 212 | if (test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state)) |
210 | return; | 213 | goto out; |
211 | intf->attach(dev, dev_ctx->context); | 214 | intf->attach(dev, dev_ctx->context); |
212 | set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); | 215 | set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); |
213 | } else { | 216 | } else { |
214 | if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) | 217 | if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) |
215 | return; | 218 | goto out; |
216 | dev_ctx->context = intf->add(dev); | 219 | dev_ctx->context = intf->add(dev); |
217 | set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); | 220 | set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); |
218 | } | 221 | } |
222 | |||
223 | out: | ||
224 | delayed_event_release(dev_ctx, priv); | ||
219 | } | 225 | } |
220 | 226 | ||
221 | void mlx5_attach_device(struct mlx5_core_dev *dev) | 227 | void mlx5_attach_device(struct mlx5_core_dev *dev) |
@@ -414,8 +420,14 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, | |||
414 | if (priv->is_accum_events) | 420 | if (priv->is_accum_events) |
415 | add_delayed_event(priv, dev, event, param); | 421 | add_delayed_event(priv, dev, event, param); |
416 | 422 | ||
423 | /* After mlx5_detach_device, the dev_ctx->intf is still set and dev_ctx is | ||
424 | * still in priv->ctx_list. In this case, only notify the dev_ctx if its | ||
425 | * ADDED or ATTACHED bit are set. | ||
426 | */ | ||
417 | list_for_each_entry(dev_ctx, &priv->ctx_list, list) | 427 | list_for_each_entry(dev_ctx, &priv->ctx_list, list) |
418 | if (dev_ctx->intf->event) | 428 | if (dev_ctx->intf->event && |
429 | (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state) || | ||
430 | test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state))) | ||
419 | dev_ctx->intf->event(dev, dev_ctx->context, event, param); | 431 | dev_ctx->intf->event(dev, dev_ctx->context, event, param); |
420 | 432 | ||
421 | spin_unlock_irqrestore(&priv->ctx_lock, flags); | 433 | spin_unlock_irqrestore(&priv->ctx_lock, flags); |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index c1d384fca4dc..51c4cc00a186 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c | |||
@@ -41,6 +41,11 @@ | |||
41 | #define MLX5E_CEE_STATE_UP 1 | 41 | #define MLX5E_CEE_STATE_UP 1 |
42 | #define MLX5E_CEE_STATE_DOWN 0 | 42 | #define MLX5E_CEE_STATE_DOWN 0 |
43 | 43 | ||
44 | enum { | ||
45 | MLX5E_VENDOR_TC_GROUP_NUM = 7, | ||
46 | MLX5E_LOWEST_PRIO_GROUP = 0, | ||
47 | }; | ||
48 | |||
44 | /* If dcbx mode is non-host set the dcbx mode to host. | 49 | /* If dcbx mode is non-host set the dcbx mode to host. |
45 | */ | 50 | */ |
46 | static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv, | 51 | static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv, |
@@ -85,6 +90,9 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, | |||
85 | { | 90 | { |
86 | struct mlx5e_priv *priv = netdev_priv(netdev); | 91 | struct mlx5e_priv *priv = netdev_priv(netdev); |
87 | struct mlx5_core_dev *mdev = priv->mdev; | 92 | struct mlx5_core_dev *mdev = priv->mdev; |
93 | u8 tc_group[IEEE_8021QAZ_MAX_TCS]; | ||
94 | bool is_tc_group_6_exist = false; | ||
95 | bool is_zero_bw_ets_tc = false; | ||
88 | int err = 0; | 96 | int err = 0; |
89 | int i; | 97 | int i; |
90 | 98 | ||
@@ -96,37 +104,64 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, | |||
96 | err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]); | 104 | err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]); |
97 | if (err) | 105 | if (err) |
98 | return err; | 106 | return err; |
99 | } | ||
100 | 107 | ||
101 | for (i = 0; i < ets->ets_cap; i++) { | 108 | err = mlx5_query_port_tc_group(mdev, i, &tc_group[i]); |
109 | if (err) | ||
110 | return err; | ||
111 | |||
102 | err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]); | 112 | err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]); |
103 | if (err) | 113 | if (err) |
104 | return err; | 114 | return err; |
115 | |||
116 | if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC && | ||
117 | tc_group[i] == (MLX5E_LOWEST_PRIO_GROUP + 1)) | ||
118 | is_zero_bw_ets_tc = true; | ||
119 | |||
120 | if (tc_group[i] == (MLX5E_VENDOR_TC_GROUP_NUM - 1)) | ||
121 | is_tc_group_6_exist = true; | ||
122 | } | ||
123 | |||
124 | /* Report 0% ets tc if exits*/ | ||
125 | if (is_zero_bw_ets_tc) { | ||
126 | for (i = 0; i < ets->ets_cap; i++) | ||
127 | if (tc_group[i] == MLX5E_LOWEST_PRIO_GROUP) | ||
128 | ets->tc_tx_bw[i] = 0; | ||
129 | } | ||
130 | |||
131 | /* Update tc_tsa based on fw setting*/ | ||
132 | for (i = 0; i < ets->ets_cap; i++) { | ||
105 | if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC) | 133 | if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC) |
106 | priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; | 134 | priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; |
135 | else if (tc_group[i] == MLX5E_VENDOR_TC_GROUP_NUM && | ||
136 | !is_tc_group_6_exist) | ||
137 | priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR; | ||
107 | } | 138 | } |
108 | |||
109 | memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa)); | 139 | memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa)); |
110 | 140 | ||
111 | return err; | 141 | return err; |
112 | } | 142 | } |
113 | 143 | ||
114 | enum { | ||
115 | MLX5E_VENDOR_TC_GROUP_NUM = 7, | ||
116 | MLX5E_ETS_TC_GROUP_NUM = 0, | ||
117 | }; | ||
118 | |||
119 | static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) | 144 | static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) |
120 | { | 145 | { |
121 | bool any_tc_mapped_to_ets = false; | 146 | bool any_tc_mapped_to_ets = false; |
147 | bool ets_zero_bw = false; | ||
122 | int strict_group; | 148 | int strict_group; |
123 | int i; | 149 | int i; |
124 | 150 | ||
125 | for (i = 0; i <= max_tc; i++) | 151 | for (i = 0; i <= max_tc; i++) { |
126 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) | 152 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { |
127 | any_tc_mapped_to_ets = true; | 153 | any_tc_mapped_to_ets = true; |
154 | if (!ets->tc_tx_bw[i]) | ||
155 | ets_zero_bw = true; | ||
156 | } | ||
157 | } | ||
128 | 158 | ||
129 | strict_group = any_tc_mapped_to_ets ? 1 : 0; | 159 | /* strict group has higher priority than ets group */ |
160 | strict_group = MLX5E_LOWEST_PRIO_GROUP; | ||
161 | if (any_tc_mapped_to_ets) | ||
162 | strict_group++; | ||
163 | if (ets_zero_bw) | ||
164 | strict_group++; | ||
130 | 165 | ||
131 | for (i = 0; i <= max_tc; i++) { | 166 | for (i = 0; i <= max_tc; i++) { |
132 | switch (ets->tc_tsa[i]) { | 167 | switch (ets->tc_tsa[i]) { |
@@ -137,7 +172,9 @@ static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) | |||
137 | tc_group[i] = strict_group++; | 172 | tc_group[i] = strict_group++; |
138 | break; | 173 | break; |
139 | case IEEE_8021QAZ_TSA_ETS: | 174 | case IEEE_8021QAZ_TSA_ETS: |
140 | tc_group[i] = MLX5E_ETS_TC_GROUP_NUM; | 175 | tc_group[i] = MLX5E_LOWEST_PRIO_GROUP; |
176 | if (ets->tc_tx_bw[i] && ets_zero_bw) | ||
177 | tc_group[i] = MLX5E_LOWEST_PRIO_GROUP + 1; | ||
141 | break; | 178 | break; |
142 | } | 179 | } |
143 | } | 180 | } |
@@ -146,9 +183,23 @@ static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) | |||
146 | static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, | 183 | static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, |
147 | u8 *tc_group, int max_tc) | 184 | u8 *tc_group, int max_tc) |
148 | { | 185 | { |
186 | int bw_for_ets_zero_bw_tc = 0; | ||
187 | int last_ets_zero_bw_tc = -1; | ||
188 | int num_ets_zero_bw = 0; | ||
149 | int i; | 189 | int i; |
150 | 190 | ||
151 | for (i = 0; i <= max_tc; i++) { | 191 | for (i = 0; i <= max_tc; i++) { |
192 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS && | ||
193 | !ets->tc_tx_bw[i]) { | ||
194 | num_ets_zero_bw++; | ||
195 | last_ets_zero_bw_tc = i; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | if (num_ets_zero_bw) | ||
200 | bw_for_ets_zero_bw_tc = MLX5E_MAX_BW_ALLOC / num_ets_zero_bw; | ||
201 | |||
202 | for (i = 0; i <= max_tc; i++) { | ||
152 | switch (ets->tc_tsa[i]) { | 203 | switch (ets->tc_tsa[i]) { |
153 | case IEEE_8021QAZ_TSA_VENDOR: | 204 | case IEEE_8021QAZ_TSA_VENDOR: |
154 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | 205 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; |
@@ -157,12 +208,26 @@ static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, | |||
157 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; | 208 | tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; |
158 | break; | 209 | break; |
159 | case IEEE_8021QAZ_TSA_ETS: | 210 | case IEEE_8021QAZ_TSA_ETS: |
160 | tc_tx_bw[i] = ets->tc_tx_bw[i]; | 211 | tc_tx_bw[i] = ets->tc_tx_bw[i] ? |
212 | ets->tc_tx_bw[i] : | ||
213 | bw_for_ets_zero_bw_tc; | ||
161 | break; | 214 | break; |
162 | } | 215 | } |
163 | } | 216 | } |
217 | |||
218 | /* Make sure the total bw for ets zero bw group is 100% */ | ||
219 | if (last_ets_zero_bw_tc != -1) | ||
220 | tc_tx_bw[last_ets_zero_bw_tc] += | ||
221 | MLX5E_MAX_BW_ALLOC % num_ets_zero_bw; | ||
164 | } | 222 | } |
165 | 223 | ||
224 | /* If there are ETS BW 0, | ||
225 | * Set ETS group # to 1 for all ETS non zero BW tcs. Their sum must be 100%. | ||
226 | * Set group #0 to all the ETS BW 0 tcs and | ||
227 | * equally splits the 100% BW between them | ||
228 | * Report both group #0 and #1 as ETS type. | ||
229 | * All the tcs in group #0 will be reported with 0% BW. | ||
230 | */ | ||
166 | int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) | 231 | int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) |
167 | { | 232 | { |
168 | struct mlx5_core_dev *mdev = priv->mdev; | 233 | struct mlx5_core_dev *mdev = priv->mdev; |
@@ -188,7 +253,6 @@ int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) | |||
188 | return err; | 253 | return err; |
189 | 254 | ||
190 | memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); | 255 | memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); |
191 | |||
192 | return err; | 256 | return err; |
193 | } | 257 | } |
194 | 258 | ||
@@ -209,17 +273,9 @@ static int mlx5e_dbcnl_validate_ets(struct net_device *netdev, | |||
209 | } | 273 | } |
210 | 274 | ||
211 | /* Validate Bandwidth Sum */ | 275 | /* Validate Bandwidth Sum */ |
212 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | 276 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) |
213 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { | 277 | if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) |
214 | if (!ets->tc_tx_bw[i]) { | ||
215 | netdev_err(netdev, | ||
216 | "Failed to validate ETS: BW 0 is illegal\n"); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | bw_sum += ets->tc_tx_bw[i]; | 278 | bw_sum += ets->tc_tx_bw[i]; |
221 | } | ||
222 | } | ||
223 | 279 | ||
224 | if (bw_sum != 0 && bw_sum != 100) { | 280 | if (bw_sum != 0 && bw_sum != 100) { |
225 | netdev_err(netdev, | 281 | netdev_err(netdev, |
@@ -533,8 +589,7 @@ static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev, | |||
533 | static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, | 589 | static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, |
534 | int pgid, u8 *bw_pct) | 590 | int pgid, u8 *bw_pct) |
535 | { | 591 | { |
536 | struct mlx5e_priv *priv = netdev_priv(netdev); | 592 | struct ieee_ets ets; |
537 | struct mlx5_core_dev *mdev = priv->mdev; | ||
538 | 593 | ||
539 | if (pgid >= CEE_DCBX_MAX_PGS) { | 594 | if (pgid >= CEE_DCBX_MAX_PGS) { |
540 | netdev_err(netdev, | 595 | netdev_err(netdev, |
@@ -542,8 +597,8 @@ static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, | |||
542 | return; | 597 | return; |
543 | } | 598 | } |
544 | 599 | ||
545 | if (mlx5_query_port_tc_bw_alloc(mdev, pgid, bw_pct)) | 600 | mlx5e_dcbnl_ieee_getets(netdev, &ets); |
546 | *bw_pct = 0; | 601 | *bw_pct = ets.tc_tx_bw[pgid]; |
547 | } | 602 | } |
548 | 603 | ||
549 | static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev, | 604 | static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev, |
@@ -739,8 +794,6 @@ static void mlx5e_ets_init(struct mlx5e_priv *priv) | |||
739 | ets.prio_tc[i] = i; | 794 | ets.prio_tc[i] = i; |
740 | } | 795 | } |
741 | 796 | ||
742 | memcpy(priv->dcbx.tc_tsa, ets.tc_tsa, sizeof(ets.tc_tsa)); | ||
743 | |||
744 | /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */ | 797 | /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */ |
745 | ets.prio_tc[0] = 1; | 798 | ets.prio_tc[0] = 1; |
746 | ets.prio_tc[1] = 0; | 799 | ets.prio_tc[1] = 0; |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 1aa2028ed995..9ba1f72060aa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | |||
@@ -78,9 +78,11 @@ struct mlx5e_tc_flow { | |||
78 | }; | 78 | }; |
79 | 79 | ||
80 | struct mlx5e_tc_flow_parse_attr { | 80 | struct mlx5e_tc_flow_parse_attr { |
81 | struct ip_tunnel_info tun_info; | ||
81 | struct mlx5_flow_spec spec; | 82 | struct mlx5_flow_spec spec; |
82 | int num_mod_hdr_actions; | 83 | int num_mod_hdr_actions; |
83 | void *mod_hdr_actions; | 84 | void *mod_hdr_actions; |
85 | int mirred_ifindex; | ||
84 | }; | 86 | }; |
85 | 87 | ||
86 | enum { | 88 | enum { |
@@ -322,6 +324,12 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, | |||
322 | static void mlx5e_detach_encap(struct mlx5e_priv *priv, | 324 | static void mlx5e_detach_encap(struct mlx5e_priv *priv, |
323 | struct mlx5e_tc_flow *flow); | 325 | struct mlx5e_tc_flow *flow); |
324 | 326 | ||
327 | static int mlx5e_attach_encap(struct mlx5e_priv *priv, | ||
328 | struct ip_tunnel_info *tun_info, | ||
329 | struct net_device *mirred_dev, | ||
330 | struct net_device **encap_dev, | ||
331 | struct mlx5e_tc_flow *flow); | ||
332 | |||
325 | static struct mlx5_flow_handle * | 333 | static struct mlx5_flow_handle * |
326 | mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, | 334 | mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, |
327 | struct mlx5e_tc_flow_parse_attr *parse_attr, | 335 | struct mlx5e_tc_flow_parse_attr *parse_attr, |
@@ -329,9 +337,27 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, | |||
329 | { | 337 | { |
330 | struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; | 338 | struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; |
331 | struct mlx5_esw_flow_attr *attr = flow->esw_attr; | 339 | struct mlx5_esw_flow_attr *attr = flow->esw_attr; |
332 | struct mlx5_flow_handle *rule; | 340 | struct net_device *out_dev, *encap_dev = NULL; |
341 | struct mlx5_flow_handle *rule = NULL; | ||
342 | struct mlx5e_rep_priv *rpriv; | ||
343 | struct mlx5e_priv *out_priv; | ||
333 | int err; | 344 | int err; |
334 | 345 | ||
346 | if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) { | ||
347 | out_dev = __dev_get_by_index(dev_net(priv->netdev), | ||
348 | attr->parse_attr->mirred_ifindex); | ||
349 | err = mlx5e_attach_encap(priv, &parse_attr->tun_info, | ||
350 | out_dev, &encap_dev, flow); | ||
351 | if (err) { | ||
352 | rule = ERR_PTR(err); | ||
353 | if (err != -EAGAIN) | ||
354 | goto err_attach_encap; | ||
355 | } | ||
356 | out_priv = netdev_priv(encap_dev); | ||
357 | rpriv = out_priv->ppriv; | ||
358 | attr->out_rep = rpriv->rep; | ||
359 | } | ||
360 | |||
335 | err = mlx5_eswitch_add_vlan_action(esw, attr); | 361 | err = mlx5_eswitch_add_vlan_action(esw, attr); |
336 | if (err) { | 362 | if (err) { |
337 | rule = ERR_PTR(err); | 363 | rule = ERR_PTR(err); |
@@ -347,10 +373,14 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, | |||
347 | } | 373 | } |
348 | } | 374 | } |
349 | 375 | ||
350 | rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); | 376 | /* we get here if (1) there's no error (rule being null) or when |
351 | if (IS_ERR(rule)) | 377 | * (2) there's an encap action and we're on -EAGAIN (no valid neigh) |
352 | goto err_add_rule; | 378 | */ |
353 | 379 | if (rule != ERR_PTR(-EAGAIN)) { | |
380 | rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); | ||
381 | if (IS_ERR(rule)) | ||
382 | goto err_add_rule; | ||
383 | } | ||
354 | return rule; | 384 | return rule; |
355 | 385 | ||
356 | err_add_rule: | 386 | err_add_rule: |
@@ -361,6 +391,7 @@ err_mod_hdr: | |||
361 | err_add_vlan: | 391 | err_add_vlan: |
362 | if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) | 392 | if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) |
363 | mlx5e_detach_encap(priv, flow); | 393 | mlx5e_detach_encap(priv, flow); |
394 | err_attach_encap: | ||
364 | return rule; | 395 | return rule; |
365 | } | 396 | } |
366 | 397 | ||
@@ -389,6 +420,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, | |||
389 | void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, | 420 | void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, |
390 | struct mlx5e_encap_entry *e) | 421 | struct mlx5e_encap_entry *e) |
391 | { | 422 | { |
423 | struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; | ||
424 | struct mlx5_esw_flow_attr *esw_attr; | ||
392 | struct mlx5e_tc_flow *flow; | 425 | struct mlx5e_tc_flow *flow; |
393 | int err; | 426 | int err; |
394 | 427 | ||
@@ -404,10 +437,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, | |||
404 | mlx5e_rep_queue_neigh_stats_work(priv); | 437 | mlx5e_rep_queue_neigh_stats_work(priv); |
405 | 438 | ||
406 | list_for_each_entry(flow, &e->flows, encap) { | 439 | list_for_each_entry(flow, &e->flows, encap) { |
407 | flow->esw_attr->encap_id = e->encap_id; | 440 | esw_attr = flow->esw_attr; |
408 | flow->rule = mlx5e_tc_add_fdb_flow(priv, | 441 | esw_attr->encap_id = e->encap_id; |
409 | flow->esw_attr->parse_attr, | 442 | flow->rule = mlx5_eswitch_add_offloaded_rule(esw, &esw_attr->parse_attr->spec, esw_attr); |
410 | flow); | ||
411 | if (IS_ERR(flow->rule)) { | 443 | if (IS_ERR(flow->rule)) { |
412 | err = PTR_ERR(flow->rule); | 444 | err = PTR_ERR(flow->rule); |
413 | mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n", | 445 | mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n", |
@@ -421,15 +453,13 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, | |||
421 | void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, | 453 | void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, |
422 | struct mlx5e_encap_entry *e) | 454 | struct mlx5e_encap_entry *e) |
423 | { | 455 | { |
456 | struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; | ||
424 | struct mlx5e_tc_flow *flow; | 457 | struct mlx5e_tc_flow *flow; |
425 | struct mlx5_fc *counter; | ||
426 | 458 | ||
427 | list_for_each_entry(flow, &e->flows, encap) { | 459 | list_for_each_entry(flow, &e->flows, encap) { |
428 | if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { | 460 | if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { |
429 | flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; | 461 | flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; |
430 | counter = mlx5_flow_rule_counter(flow->rule); | 462 | mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr); |
431 | mlx5_del_flow_rules(flow->rule); | ||
432 | mlx5_fc_destroy(priv->mdev, counter); | ||
433 | } | 463 | } |
434 | } | 464 | } |
435 | 465 | ||
@@ -1942,7 +1972,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, | |||
1942 | 1972 | ||
1943 | if (is_tcf_mirred_egress_redirect(a)) { | 1973 | if (is_tcf_mirred_egress_redirect(a)) { |
1944 | int ifindex = tcf_mirred_ifindex(a); | 1974 | int ifindex = tcf_mirred_ifindex(a); |
1945 | struct net_device *out_dev, *encap_dev = NULL; | 1975 | struct net_device *out_dev; |
1946 | struct mlx5e_priv *out_priv; | 1976 | struct mlx5e_priv *out_priv; |
1947 | 1977 | ||
1948 | out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex); | 1978 | out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex); |
@@ -1955,17 +1985,13 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, | |||
1955 | rpriv = out_priv->ppriv; | 1985 | rpriv = out_priv->ppriv; |
1956 | attr->out_rep = rpriv->rep; | 1986 | attr->out_rep = rpriv->rep; |
1957 | } else if (encap) { | 1987 | } else if (encap) { |
1958 | err = mlx5e_attach_encap(priv, info, | 1988 | parse_attr->mirred_ifindex = ifindex; |
1959 | out_dev, &encap_dev, flow); | 1989 | parse_attr->tun_info = *info; |
1960 | if (err && err != -EAGAIN) | 1990 | attr->parse_attr = parse_attr; |
1961 | return err; | ||
1962 | attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | | 1991 | attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | |
1963 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | | 1992 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | |
1964 | MLX5_FLOW_CONTEXT_ACTION_COUNT; | 1993 | MLX5_FLOW_CONTEXT_ACTION_COUNT; |
1965 | out_priv = netdev_priv(encap_dev); | 1994 | /* attr->out_rep is resolved when we handle encap */ |
1966 | rpriv = out_priv->ppriv; | ||
1967 | attr->out_rep = rpriv->rep; | ||
1968 | attr->parse_attr = parse_attr; | ||
1969 | } else { | 1995 | } else { |
1970 | pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", | 1996 | pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", |
1971 | priv->netdev->name, out_dev->name); | 1997 | priv->netdev->name, out_dev->name); |
@@ -2047,7 +2073,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, | |||
2047 | if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { | 2073 | if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { |
2048 | err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow); | 2074 | err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow); |
2049 | if (err < 0) | 2075 | if (err < 0) |
2050 | goto err_handle_encap_flow; | 2076 | goto err_free; |
2051 | flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow); | 2077 | flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow); |
2052 | } else { | 2078 | } else { |
2053 | err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow); | 2079 | err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow); |
@@ -2058,10 +2084,13 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, | |||
2058 | 2084 | ||
2059 | if (IS_ERR(flow->rule)) { | 2085 | if (IS_ERR(flow->rule)) { |
2060 | err = PTR_ERR(flow->rule); | 2086 | err = PTR_ERR(flow->rule); |
2061 | goto err_free; | 2087 | if (err != -EAGAIN) |
2088 | goto err_free; | ||
2062 | } | 2089 | } |
2063 | 2090 | ||
2064 | flow->flags |= MLX5E_TC_FLOW_OFFLOADED; | 2091 | if (err != -EAGAIN) |
2092 | flow->flags |= MLX5E_TC_FLOW_OFFLOADED; | ||
2093 | |||
2065 | err = rhashtable_insert_fast(&tc->ht, &flow->node, | 2094 | err = rhashtable_insert_fast(&tc->ht, &flow->node, |
2066 | tc->ht_params); | 2095 | tc->ht_params); |
2067 | if (err) | 2096 | if (err) |
@@ -2075,16 +2104,6 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, | |||
2075 | err_del_rule: | 2104 | err_del_rule: |
2076 | mlx5e_tc_del_flow(priv, flow); | 2105 | mlx5e_tc_del_flow(priv, flow); |
2077 | 2106 | ||
2078 | err_handle_encap_flow: | ||
2079 | if (err == -EAGAIN) { | ||
2080 | err = rhashtable_insert_fast(&tc->ht, &flow->node, | ||
2081 | tc->ht_params); | ||
2082 | if (err) | ||
2083 | mlx5e_tc_del_flow(priv, flow); | ||
2084 | else | ||
2085 | return 0; | ||
2086 | } | ||
2087 | |||
2088 | err_free: | 2107 | err_free: |
2089 | kvfree(parse_attr); | 2108 | kvfree(parse_attr); |
2090 | kfree(flow); | 2109 | kfree(flow); |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 8aea0a065e56..db86e1506c8b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c | |||
@@ -356,10 +356,11 @@ void mlx5_drain_health_wq(struct mlx5_core_dev *dev) | |||
356 | void mlx5_drain_health_recovery(struct mlx5_core_dev *dev) | 356 | void mlx5_drain_health_recovery(struct mlx5_core_dev *dev) |
357 | { | 357 | { |
358 | struct mlx5_core_health *health = &dev->priv.health; | 358 | struct mlx5_core_health *health = &dev->priv.health; |
359 | unsigned long flags; | ||
359 | 360 | ||
360 | spin_lock(&health->wq_lock); | 361 | spin_lock_irqsave(&health->wq_lock, flags); |
361 | set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); | 362 | set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); |
362 | spin_unlock(&health->wq_lock); | 363 | spin_unlock_irqrestore(&health->wq_lock, flags); |
363 | cancel_delayed_work_sync(&dev->priv.health.recover_work); | 364 | cancel_delayed_work_sync(&dev->priv.health.recover_work); |
364 | } | 365 | } |
365 | 366 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 1975d4388d4f..e07061f565d6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c | |||
@@ -677,6 +677,27 @@ int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group) | |||
677 | } | 677 | } |
678 | EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); | 678 | EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); |
679 | 679 | ||
680 | int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev, | ||
681 | u8 tc, u8 *tc_group) | ||
682 | { | ||
683 | u32 out[MLX5_ST_SZ_DW(qetc_reg)]; | ||
684 | void *ets_tcn_conf; | ||
685 | int err; | ||
686 | |||
687 | err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); | ||
688 | if (err) | ||
689 | return err; | ||
690 | |||
691 | ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, | ||
692 | tc_configuration[tc]); | ||
693 | |||
694 | *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, | ||
695 | group); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group); | ||
700 | |||
680 | int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) | 701 | int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) |
681 | { | 702 | { |
682 | u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; | 703 | u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; |
diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c index db9750695dc7..8ea9320014ee 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/action.c +++ b/drivers/net/ethernet/netronome/nfp/flower/action.c | |||
@@ -110,6 +110,8 @@ nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action, | |||
110 | */ | 110 | */ |
111 | if (!switchdev_port_same_parent_id(in_dev, out_dev)) | 111 | if (!switchdev_port_same_parent_id(in_dev, out_dev)) |
112 | return -EOPNOTSUPP; | 112 | return -EOPNOTSUPP; |
113 | if (!nfp_netdev_is_nfp_repr(out_dev)) | ||
114 | return -EOPNOTSUPP; | ||
113 | 115 | ||
114 | output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev)); | 116 | output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev)); |
115 | if (!output->port) | 117 | if (!output->port) |
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c index 5efef8001edf..3256e5cbad27 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c | |||
@@ -74,7 +74,7 @@ static int dwc_eth_dwmac_config_dt(struct platform_device *pdev, | |||
74 | plat_dat->axi->axi_wr_osr_lmt--; | 74 | plat_dat->axi->axi_wr_osr_lmt--; |
75 | } | 75 | } |
76 | 76 | ||
77 | if (of_property_read_u32(np, "read,read-requests", | 77 | if (of_property_read_u32(np, "snps,read-requests", |
78 | &plat_dat->axi->axi_rd_osr_lmt)) { | 78 | &plat_dat->axi->axi_rd_osr_lmt)) { |
79 | /** | 79 | /** |
80 | * Since the register has a reset value of 1, if property | 80 | * Since the register has a reset value of 1, if property |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 8a280b48e3a9..6383695004a5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | |||
@@ -150,6 +150,13 @@ static void stmmac_mtl_setup(struct platform_device *pdev, | |||
150 | plat->rx_queues_to_use = 1; | 150 | plat->rx_queues_to_use = 1; |
151 | plat->tx_queues_to_use = 1; | 151 | plat->tx_queues_to_use = 1; |
152 | 152 | ||
153 | /* First Queue must always be in DCB mode. As MTL_QUEUE_DCB = 1 we need | ||
154 | * to always set this, otherwise Queue will be classified as AVB | ||
155 | * (because MTL_QUEUE_AVB = 0). | ||
156 | */ | ||
157 | plat->rx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB; | ||
158 | plat->tx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB; | ||
159 | |||
153 | rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0); | 160 | rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0); |
154 | if (!rx_node) | 161 | if (!rx_node) |
155 | return; | 162 | return; |
diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c index 5dea2063dbc8..0bcc07f346c3 100644 --- a/drivers/net/ipvlan/ipvtap.c +++ b/drivers/net/ipvlan/ipvtap.c | |||
@@ -197,8 +197,8 @@ static int ipvtap_init(void) | |||
197 | { | 197 | { |
198 | int err; | 198 | int err; |
199 | 199 | ||
200 | err = tap_create_cdev(&ipvtap_cdev, &ipvtap_major, "ipvtap"); | 200 | err = tap_create_cdev(&ipvtap_cdev, &ipvtap_major, "ipvtap", |
201 | 201 | THIS_MODULE); | |
202 | if (err) | 202 | if (err) |
203 | goto out1; | 203 | goto out1; |
204 | 204 | ||
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index c2d0ea2fb019..cba5cb3b849a 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -204,8 +204,8 @@ static int macvtap_init(void) | |||
204 | { | 204 | { |
205 | int err; | 205 | int err; |
206 | 206 | ||
207 | err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap"); | 207 | err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap", |
208 | 208 | THIS_MODULE); | |
209 | if (err) | 209 | if (err) |
210 | goto out1; | 210 | goto out1; |
211 | 211 | ||
diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 21b71ae947fd..1b10fcc6a58d 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c | |||
@@ -517,6 +517,10 @@ static int tap_open(struct inode *inode, struct file *file) | |||
517 | &tap_proto, 0); | 517 | &tap_proto, 0); |
518 | if (!q) | 518 | if (!q) |
519 | goto err; | 519 | goto err; |
520 | if (skb_array_init(&q->skb_array, tap->dev->tx_queue_len, GFP_KERNEL)) { | ||
521 | sk_free(&q->sk); | ||
522 | goto err; | ||
523 | } | ||
520 | 524 | ||
521 | RCU_INIT_POINTER(q->sock.wq, &q->wq); | 525 | RCU_INIT_POINTER(q->sock.wq, &q->wq); |
522 | init_waitqueue_head(&q->wq.wait); | 526 | init_waitqueue_head(&q->wq.wait); |
@@ -540,22 +544,18 @@ static int tap_open(struct inode *inode, struct file *file) | |||
540 | if ((tap->dev->features & NETIF_F_HIGHDMA) && (tap->dev->features & NETIF_F_SG)) | 544 | if ((tap->dev->features & NETIF_F_HIGHDMA) && (tap->dev->features & NETIF_F_SG)) |
541 | sock_set_flag(&q->sk, SOCK_ZEROCOPY); | 545 | sock_set_flag(&q->sk, SOCK_ZEROCOPY); |
542 | 546 | ||
543 | err = -ENOMEM; | ||
544 | if (skb_array_init(&q->skb_array, tap->dev->tx_queue_len, GFP_KERNEL)) | ||
545 | goto err_array; | ||
546 | |||
547 | err = tap_set_queue(tap, file, q); | 547 | err = tap_set_queue(tap, file, q); |
548 | if (err) | 548 | if (err) { |
549 | goto err_queue; | 549 | /* tap_sock_destruct() will take care of freeing skb_array */ |
550 | goto err_put; | ||
551 | } | ||
550 | 552 | ||
551 | dev_put(tap->dev); | 553 | dev_put(tap->dev); |
552 | 554 | ||
553 | rtnl_unlock(); | 555 | rtnl_unlock(); |
554 | return err; | 556 | return err; |
555 | 557 | ||
556 | err_queue: | 558 | err_put: |
557 | skb_array_cleanup(&q->skb_array); | ||
558 | err_array: | ||
559 | sock_put(&q->sk); | 559 | sock_put(&q->sk); |
560 | err: | 560 | err: |
561 | if (tap) | 561 | if (tap) |
@@ -1249,8 +1249,8 @@ static int tap_list_add(dev_t major, const char *device_name) | |||
1249 | return 0; | 1249 | return 0; |
1250 | } | 1250 | } |
1251 | 1251 | ||
1252 | int tap_create_cdev(struct cdev *tap_cdev, | 1252 | int tap_create_cdev(struct cdev *tap_cdev, dev_t *tap_major, |
1253 | dev_t *tap_major, const char *device_name) | 1253 | const char *device_name, struct module *module) |
1254 | { | 1254 | { |
1255 | int err; | 1255 | int err; |
1256 | 1256 | ||
@@ -1259,6 +1259,7 @@ int tap_create_cdev(struct cdev *tap_cdev, | |||
1259 | goto out1; | 1259 | goto out1; |
1260 | 1260 | ||
1261 | cdev_init(tap_cdev, &tap_fops); | 1261 | cdev_init(tap_cdev, &tap_fops); |
1262 | tap_cdev->owner = module; | ||
1262 | err = cdev_add(tap_cdev, *tap_major, TAP_NUM_DEVS); | 1263 | err = cdev_add(tap_cdev, *tap_major, TAP_NUM_DEVS); |
1263 | if (err) | 1264 | if (err) |
1264 | goto out2; | 1265 | goto out2; |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e21bf90b819f..5550f56cb895 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -1286,6 +1286,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, | |||
1286 | buflen += SKB_DATA_ALIGN(len + pad); | 1286 | buflen += SKB_DATA_ALIGN(len + pad); |
1287 | rcu_read_unlock(); | 1287 | rcu_read_unlock(); |
1288 | 1288 | ||
1289 | alloc_frag->offset = ALIGN((u64)alloc_frag->offset, SMP_CACHE_BYTES); | ||
1289 | if (unlikely(!skb_page_frag_refill(buflen, alloc_frag, GFP_KERNEL))) | 1290 | if (unlikely(!skb_page_frag_refill(buflen, alloc_frag, GFP_KERNEL))) |
1290 | return ERR_PTR(-ENOMEM); | 1291 | return ERR_PTR(-ENOMEM); |
1291 | 1292 | ||
@@ -2028,7 +2029,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
2028 | if (!dev) | 2029 | if (!dev) |
2029 | return -ENOMEM; | 2030 | return -ENOMEM; |
2030 | err = dev_get_valid_name(net, dev, name); | 2031 | err = dev_get_valid_name(net, dev, name); |
2031 | if (err) | 2032 | if (err < 0) |
2032 | goto err_free_dev; | 2033 | goto err_free_dev; |
2033 | 2034 | ||
2034 | dev_net_set(dev, net); | 2035 | dev_net_set(dev, net); |
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 52ea80bcd639..3e7a3ac3a362 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c | |||
@@ -561,6 +561,7 @@ static const struct driver_info wwan_info = { | |||
561 | #define HP_VENDOR_ID 0x03f0 | 561 | #define HP_VENDOR_ID 0x03f0 |
562 | #define MICROSOFT_VENDOR_ID 0x045e | 562 | #define MICROSOFT_VENDOR_ID 0x045e |
563 | #define UBLOX_VENDOR_ID 0x1546 | 563 | #define UBLOX_VENDOR_ID 0x1546 |
564 | #define TPLINK_VENDOR_ID 0x2357 | ||
564 | 565 | ||
565 | static const struct usb_device_id products[] = { | 566 | static const struct usb_device_id products[] = { |
566 | /* BLACKLIST !! | 567 | /* BLACKLIST !! |
@@ -813,6 +814,13 @@ static const struct usb_device_id products[] = { | |||
813 | .driver_info = 0, | 814 | .driver_info = 0, |
814 | }, | 815 | }, |
815 | 816 | ||
817 | /* TP-LINK UE300 USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */ | ||
818 | { | ||
819 | USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, 0x0601, USB_CLASS_COMM, | ||
820 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | ||
821 | .driver_info = 0, | ||
822 | }, | ||
823 | |||
816 | /* WHITELIST!!! | 824 | /* WHITELIST!!! |
817 | * | 825 | * |
818 | * CDC Ether uses two interfaces, not necessarily consecutive. | 826 | * CDC Ether uses two interfaces, not necessarily consecutive. |
@@ -864,6 +872,12 @@ static const struct usb_device_id products[] = { | |||
864 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | 872 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), |
865 | .driver_info = (kernel_ulong_t)&wwan_info, | 873 | .driver_info = (kernel_ulong_t)&wwan_info, |
866 | }, { | 874 | }, { |
875 | /* Huawei ME906 and ME909 */ | ||
876 | USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x15c1, USB_CLASS_COMM, | ||
877 | USB_CDC_SUBCLASS_ETHERNET, | ||
878 | USB_CDC_PROTO_NONE), | ||
879 | .driver_info = (unsigned long)&wwan_info, | ||
880 | }, { | ||
867 | /* ZTE modules */ | 881 | /* ZTE modules */ |
868 | USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, USB_CLASS_COMM, | 882 | USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, USB_CLASS_COMM, |
869 | USB_CDC_SUBCLASS_ETHERNET, | 883 | USB_CDC_SUBCLASS_ETHERNET, |
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 941ece08ba78..d51d9abf7986 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c | |||
@@ -615,6 +615,7 @@ enum rtl8152_flags { | |||
615 | #define VENDOR_ID_LENOVO 0x17ef | 615 | #define VENDOR_ID_LENOVO 0x17ef |
616 | #define VENDOR_ID_LINKSYS 0x13b1 | 616 | #define VENDOR_ID_LINKSYS 0x13b1 |
617 | #define VENDOR_ID_NVIDIA 0x0955 | 617 | #define VENDOR_ID_NVIDIA 0x0955 |
618 | #define VENDOR_ID_TPLINK 0x2357 | ||
618 | 619 | ||
619 | #define MCU_TYPE_PLA 0x0100 | 620 | #define MCU_TYPE_PLA 0x0100 |
620 | #define MCU_TYPE_USB 0x0000 | 621 | #define MCU_TYPE_USB 0x0000 |
@@ -5319,6 +5320,7 @@ static const struct usb_device_id rtl8152_table[] = { | |||
5319 | {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214)}, | 5320 | {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214)}, |
5320 | {REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)}, | 5321 | {REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)}, |
5321 | {REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)}, | 5322 | {REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)}, |
5323 | {REALTEK_USB_DEVICE(VENDOR_ID_TPLINK, 0x0601)}, | ||
5322 | {} | 5324 | {} |
5323 | }; | 5325 | }; |
5324 | 5326 | ||
diff --git a/include/linux/if_tap.h b/include/linux/if_tap.h index 4837157da0dc..9ae41cdd0d4c 100644 --- a/include/linux/if_tap.h +++ b/include/linux/if_tap.h | |||
@@ -73,8 +73,8 @@ void tap_del_queues(struct tap_dev *tap); | |||
73 | int tap_get_minor(dev_t major, struct tap_dev *tap); | 73 | int tap_get_minor(dev_t major, struct tap_dev *tap); |
74 | void tap_free_minor(dev_t major, struct tap_dev *tap); | 74 | void tap_free_minor(dev_t major, struct tap_dev *tap); |
75 | int tap_queue_resize(struct tap_dev *tap); | 75 | int tap_queue_resize(struct tap_dev *tap); |
76 | int tap_create_cdev(struct cdev *tap_cdev, | 76 | int tap_create_cdev(struct cdev *tap_cdev, dev_t *tap_major, |
77 | dev_t *tap_major, const char *device_name); | 77 | const char *device_name, struct module *module); |
78 | void tap_destroy_cdev(dev_t major, struct cdev *tap_cdev); | 78 | void tap_destroy_cdev(dev_t major, struct cdev *tap_cdev); |
79 | 79 | ||
80 | #endif /*_LINUX_IF_TAP_H_*/ | 80 | #endif /*_LINUX_IF_TAP_H_*/ |
diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h index c57d4b7de3a8..c59af8ab753a 100644 --- a/include/linux/mlx5/port.h +++ b/include/linux/mlx5/port.h | |||
@@ -157,6 +157,8 @@ int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc); | |||
157 | int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, | 157 | int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, |
158 | u8 prio, u8 *tc); | 158 | u8 prio, u8 *tc); |
159 | int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group); | 159 | int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group); |
160 | int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev, | ||
161 | u8 tc, u8 *tc_group); | ||
160 | int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw); | 162 | int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw); |
161 | int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, | 163 | int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, |
162 | u8 tc, u8 *bw_pct); | 164 | u8 tc, u8 *bw_pct); |
diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 82b171e1aa0b..da803dfc7a39 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h | |||
@@ -231,7 +231,7 @@ struct sctp_datahdr { | |||
231 | __be32 tsn; | 231 | __be32 tsn; |
232 | __be16 stream; | 232 | __be16 stream; |
233 | __be16 ssn; | 233 | __be16 ssn; |
234 | __be32 ppid; | 234 | __u32 ppid; |
235 | __u8 payload[0]; | 235 | __u8 payload[0]; |
236 | }; | 236 | }; |
237 | 237 | ||
@@ -716,28 +716,28 @@ struct sctp_reconf_chunk { | |||
716 | 716 | ||
717 | struct sctp_strreset_outreq { | 717 | struct sctp_strreset_outreq { |
718 | struct sctp_paramhdr param_hdr; | 718 | struct sctp_paramhdr param_hdr; |
719 | __u32 request_seq; | 719 | __be32 request_seq; |
720 | __u32 response_seq; | 720 | __be32 response_seq; |
721 | __u32 send_reset_at_tsn; | 721 | __be32 send_reset_at_tsn; |
722 | __u16 list_of_streams[0]; | 722 | __be16 list_of_streams[0]; |
723 | }; | 723 | }; |
724 | 724 | ||
725 | struct sctp_strreset_inreq { | 725 | struct sctp_strreset_inreq { |
726 | struct sctp_paramhdr param_hdr; | 726 | struct sctp_paramhdr param_hdr; |
727 | __u32 request_seq; | 727 | __be32 request_seq; |
728 | __u16 list_of_streams[0]; | 728 | __be16 list_of_streams[0]; |
729 | }; | 729 | }; |
730 | 730 | ||
731 | struct sctp_strreset_tsnreq { | 731 | struct sctp_strreset_tsnreq { |
732 | struct sctp_paramhdr param_hdr; | 732 | struct sctp_paramhdr param_hdr; |
733 | __u32 request_seq; | 733 | __be32 request_seq; |
734 | }; | 734 | }; |
735 | 735 | ||
736 | struct sctp_strreset_addstrm { | 736 | struct sctp_strreset_addstrm { |
737 | struct sctp_paramhdr param_hdr; | 737 | struct sctp_paramhdr param_hdr; |
738 | __u32 request_seq; | 738 | __be32 request_seq; |
739 | __u16 number_of_streams; | 739 | __be16 number_of_streams; |
740 | __u16 reserved; | 740 | __be16 reserved; |
741 | }; | 741 | }; |
742 | 742 | ||
743 | enum { | 743 | enum { |
@@ -752,16 +752,16 @@ enum { | |||
752 | 752 | ||
753 | struct sctp_strreset_resp { | 753 | struct sctp_strreset_resp { |
754 | struct sctp_paramhdr param_hdr; | 754 | struct sctp_paramhdr param_hdr; |
755 | __u32 response_seq; | 755 | __be32 response_seq; |
756 | __u32 result; | 756 | __be32 result; |
757 | }; | 757 | }; |
758 | 758 | ||
759 | struct sctp_strreset_resptsn { | 759 | struct sctp_strreset_resptsn { |
760 | struct sctp_paramhdr param_hdr; | 760 | struct sctp_paramhdr param_hdr; |
761 | __u32 response_seq; | 761 | __be32 response_seq; |
762 | __u32 result; | 762 | __be32 result; |
763 | __u32 senders_next_tsn; | 763 | __be32 senders_next_tsn; |
764 | __u32 receivers_next_tsn; | 764 | __be32 receivers_next_tsn; |
765 | }; | 765 | }; |
766 | 766 | ||
767 | #endif /* __LINUX_SCTP_H__ */ | 767 | #endif /* __LINUX_SCTP_H__ */ |
diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h index 4e6131cd3f43..ac1a2317941e 100644 --- a/include/net/fq_impl.h +++ b/include/net/fq_impl.h | |||
@@ -146,6 +146,7 @@ static void fq_tin_enqueue(struct fq *fq, | |||
146 | fq_flow_get_default_t get_default_func) | 146 | fq_flow_get_default_t get_default_func) |
147 | { | 147 | { |
148 | struct fq_flow *flow; | 148 | struct fq_flow *flow; |
149 | bool oom; | ||
149 | 150 | ||
150 | lockdep_assert_held(&fq->lock); | 151 | lockdep_assert_held(&fq->lock); |
151 | 152 | ||
@@ -167,8 +168,8 @@ static void fq_tin_enqueue(struct fq *fq, | |||
167 | } | 168 | } |
168 | 169 | ||
169 | __skb_queue_tail(&flow->queue, skb); | 170 | __skb_queue_tail(&flow->queue, skb); |
170 | 171 | oom = (fq->memory_usage > fq->memory_limit); | |
171 | if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) { | 172 | while (fq->backlog > fq->limit || oom) { |
172 | flow = list_first_entry_or_null(&fq->backlogs, | 173 | flow = list_first_entry_or_null(&fq->backlogs, |
173 | struct fq_flow, | 174 | struct fq_flow, |
174 | backlogchain); | 175 | backlogchain); |
@@ -183,8 +184,10 @@ static void fq_tin_enqueue(struct fq *fq, | |||
183 | 184 | ||
184 | flow->tin->overlimit++; | 185 | flow->tin->overlimit++; |
185 | fq->overlimit++; | 186 | fq->overlimit++; |
186 | if (fq->memory_usage > fq->memory_limit) | 187 | if (oom) { |
187 | fq->overmemory++; | 188 | fq->overmemory++; |
189 | oom = (fq->memory_usage > fq->memory_limit); | ||
190 | } | ||
188 | } | 191 | } |
189 | } | 192 | } |
190 | 193 | ||
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 425752f768d2..db8162dd8c0b 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h | |||
@@ -132,6 +132,12 @@ static inline int inet_request_bound_dev_if(const struct sock *sk, | |||
132 | return sk->sk_bound_dev_if; | 132 | return sk->sk_bound_dev_if; |
133 | } | 133 | } |
134 | 134 | ||
135 | static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq) | ||
136 | { | ||
137 | return rcu_dereference_check(ireq->ireq_opt, | ||
138 | refcount_read(&ireq->req.rsk_refcnt) > 0); | ||
139 | } | ||
140 | |||
135 | struct inet_cork { | 141 | struct inet_cork { |
136 | unsigned int flags; | 142 | unsigned int flags; |
137 | __be32 addr; | 143 | __be32 addr; |
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index e80edd8879ef..3009547f3c66 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __NET_PKT_CLS_H | 2 | #define __NET_PKT_CLS_H |
3 | 3 | ||
4 | #include <linux/pkt_cls.h> | 4 | #include <linux/pkt_cls.h> |
5 | #include <linux/workqueue.h> | ||
5 | #include <net/sch_generic.h> | 6 | #include <net/sch_generic.h> |
6 | #include <net/act_api.h> | 7 | #include <net/act_api.h> |
7 | 8 | ||
@@ -17,6 +18,8 @@ struct tcf_walker { | |||
17 | int register_tcf_proto_ops(struct tcf_proto_ops *ops); | 18 | int register_tcf_proto_ops(struct tcf_proto_ops *ops); |
18 | int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); | 19 | int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); |
19 | 20 | ||
21 | bool tcf_queue_work(struct work_struct *work); | ||
22 | |||
20 | #ifdef CONFIG_NET_CLS | 23 | #ifdef CONFIG_NET_CLS |
21 | struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, | 24 | struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, |
22 | bool create); | 25 | bool create); |
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 135f5a2dd931..0dec8a23be57 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/dynamic_queue_limits.h> | 10 | #include <linux/dynamic_queue_limits.h> |
11 | #include <linux/list.h> | 11 | #include <linux/list.h> |
12 | #include <linux/refcount.h> | 12 | #include <linux/refcount.h> |
13 | #include <linux/workqueue.h> | ||
13 | #include <net/gen_stats.h> | 14 | #include <net/gen_stats.h> |
14 | #include <net/rtnetlink.h> | 15 | #include <net/rtnetlink.h> |
15 | 16 | ||
@@ -271,6 +272,7 @@ struct tcf_chain { | |||
271 | 272 | ||
272 | struct tcf_block { | 273 | struct tcf_block { |
273 | struct list_head chain_list; | 274 | struct list_head chain_list; |
275 | struct work_struct work; | ||
274 | }; | 276 | }; |
275 | 277 | ||
276 | static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) | 278 | static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) |
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 2db3d3a9ce1d..88233cf8b8d4 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h | |||
@@ -261,7 +261,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, | |||
261 | struct sctp_fwdtsn_skip *skiplist); | 261 | struct sctp_fwdtsn_skip *skiplist); |
262 | struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc); | 262 | struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc); |
263 | struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc, | 263 | struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc, |
264 | __u16 stream_num, __u16 *stream_list, | 264 | __u16 stream_num, __be16 *stream_list, |
265 | bool out, bool in); | 265 | bool out, bool in); |
266 | struct sctp_chunk *sctp_make_strreset_tsnreq( | 266 | struct sctp_chunk *sctp_make_strreset_tsnreq( |
267 | const struct sctp_association *asoc); | 267 | const struct sctp_association *asoc); |
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index b8c86ec1a8f5..231dc42f1da6 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h | |||
@@ -130,7 +130,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( | |||
130 | 130 | ||
131 | struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( | 131 | struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( |
132 | const struct sctp_association *asoc, __u16 flags, | 132 | const struct sctp_association *asoc, __u16 flags, |
133 | __u16 stream_num, __u16 *stream_list, gfp_t gfp); | 133 | __u16 stream_num, __be16 *stream_list, gfp_t gfp); |
134 | 134 | ||
135 | struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event( | 135 | struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event( |
136 | const struct sctp_association *asoc, __u16 flags, | 136 | const struct sctp_association *asoc, __u16 flags, |
diff --git a/include/net/strparser.h b/include/net/strparser.h index 7dc131d62ad5..d96b59f45eba 100644 --- a/include/net/strparser.h +++ b/include/net/strparser.h | |||
@@ -74,10 +74,9 @@ struct strparser { | |||
74 | u32 unrecov_intr : 1; | 74 | u32 unrecov_intr : 1; |
75 | 75 | ||
76 | struct sk_buff **skb_nextp; | 76 | struct sk_buff **skb_nextp; |
77 | struct timer_list msg_timer; | ||
78 | struct sk_buff *skb_head; | 77 | struct sk_buff *skb_head; |
79 | unsigned int need_bytes; | 78 | unsigned int need_bytes; |
80 | struct delayed_work delayed_work; | 79 | struct delayed_work msg_timer_work; |
81 | struct work_struct work; | 80 | struct work_struct work; |
82 | struct strp_stats stats; | 81 | struct strp_stats stats; |
83 | struct strp_callbacks cb; | 82 | struct strp_callbacks cb; |
diff --git a/include/net/tcp.h b/include/net/tcp.h index b1ef98ebce53..33599d17522d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -844,6 +844,7 @@ struct tcp_skb_cb { | |||
844 | __u32 key; | 844 | __u32 key; |
845 | __u32 flags; | 845 | __u32 flags; |
846 | struct bpf_map *map; | 846 | struct bpf_map *map; |
847 | void *data_end; | ||
847 | } bpf; | 848 | } bpf; |
848 | }; | 849 | }; |
849 | }; | 850 | }; |
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f90860d1f897..0d7948ce2128 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
@@ -575,7 +575,7 @@ union bpf_attr { | |||
575 | * @map: pointer to sockmap | 575 | * @map: pointer to sockmap |
576 | * @key: key to lookup sock in map | 576 | * @key: key to lookup sock in map |
577 | * @flags: reserved for future use | 577 | * @flags: reserved for future use |
578 | * Return: SK_REDIRECT | 578 | * Return: SK_PASS |
579 | * | 579 | * |
580 | * int bpf_sock_map_update(skops, map, key, flags) | 580 | * int bpf_sock_map_update(skops, map, key, flags) |
581 | * @skops: pointer to bpf_sock_ops | 581 | * @skops: pointer to bpf_sock_ops |
@@ -786,8 +786,8 @@ struct xdp_md { | |||
786 | }; | 786 | }; |
787 | 787 | ||
788 | enum sk_action { | 788 | enum sk_action { |
789 | SK_ABORTED = 0, | 789 | SK_DROP = 0, |
790 | SK_DROP, | 790 | SK_PASS, |
791 | SK_REDIRECT, | 791 | SK_REDIRECT, |
792 | }; | 792 | }; |
793 | 793 | ||
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index 6217ff8500a1..84fc2914b7fb 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h | |||
@@ -376,7 +376,7 @@ struct sctp_remote_error { | |||
376 | __u16 sre_type; | 376 | __u16 sre_type; |
377 | __u16 sre_flags; | 377 | __u16 sre_flags; |
378 | __u32 sre_length; | 378 | __u32 sre_length; |
379 | __u16 sre_error; | 379 | __be16 sre_error; |
380 | sctp_assoc_t sre_assoc_id; | 380 | sctp_assoc_t sre_assoc_id; |
381 | __u8 sre_data[0]; | 381 | __u8 sre_data[0]; |
382 | }; | 382 | }; |
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 2b6eb35ae5d3..66f00a2b27f4 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -93,6 +93,14 @@ static inline struct smap_psock *smap_psock_sk(const struct sock *sk) | |||
93 | return rcu_dereference_sk_user_data(sk); | 93 | return rcu_dereference_sk_user_data(sk); |
94 | } | 94 | } |
95 | 95 | ||
96 | /* compute the linear packet data range [data, data_end) for skb when | ||
97 | * sk_skb type programs are in use. | ||
98 | */ | ||
99 | static inline void bpf_compute_data_end_sk_skb(struct sk_buff *skb) | ||
100 | { | ||
101 | TCP_SKB_CB(skb)->bpf.data_end = skb->data + skb_headlen(skb); | ||
102 | } | ||
103 | |||
96 | static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) | 104 | static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) |
97 | { | 105 | { |
98 | struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); | 106 | struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); |
@@ -108,13 +116,14 @@ static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) | |||
108 | */ | 116 | */ |
109 | TCP_SKB_CB(skb)->bpf.map = NULL; | 117 | TCP_SKB_CB(skb)->bpf.map = NULL; |
110 | skb->sk = psock->sock; | 118 | skb->sk = psock->sock; |
111 | bpf_compute_data_end(skb); | 119 | bpf_compute_data_end_sk_skb(skb); |
112 | preempt_disable(); | 120 | preempt_disable(); |
113 | rc = (*prog->bpf_func)(skb, prog->insnsi); | 121 | rc = (*prog->bpf_func)(skb, prog->insnsi); |
114 | preempt_enable(); | 122 | preempt_enable(); |
115 | skb->sk = NULL; | 123 | skb->sk = NULL; |
116 | 124 | ||
117 | return rc; | 125 | return rc == SK_PASS ? |
126 | (TCP_SKB_CB(skb)->bpf.map ? SK_REDIRECT : SK_PASS) : SK_DROP; | ||
118 | } | 127 | } |
119 | 128 | ||
120 | static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) | 129 | static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) |
@@ -368,7 +377,7 @@ static int smap_parse_func_strparser(struct strparser *strp, | |||
368 | * any socket yet. | 377 | * any socket yet. |
369 | */ | 378 | */ |
370 | skb->sk = psock->sock; | 379 | skb->sk = psock->sock; |
371 | bpf_compute_data_end(skb); | 380 | bpf_compute_data_end_sk_skb(skb); |
372 | rc = (*prog->bpf_func)(skb, prog->insnsi); | 381 | rc = (*prog->bpf_func)(skb, prog->insnsi); |
373 | skb->sk = NULL; | 382 | skb->sk = NULL; |
374 | rcu_read_unlock(); | 383 | rcu_read_unlock(); |
diff --git a/net/core/filter.c b/net/core/filter.c index aa0265997f93..6ae94f825f72 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -1844,14 +1844,15 @@ BPF_CALL_4(bpf_sk_redirect_map, struct sk_buff *, skb, | |||
1844 | { | 1844 | { |
1845 | struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); | 1845 | struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); |
1846 | 1846 | ||
1847 | /* If user passes invalid input drop the packet. */ | ||
1847 | if (unlikely(flags)) | 1848 | if (unlikely(flags)) |
1848 | return SK_ABORTED; | 1849 | return SK_DROP; |
1849 | 1850 | ||
1850 | tcb->bpf.key = key; | 1851 | tcb->bpf.key = key; |
1851 | tcb->bpf.flags = flags; | 1852 | tcb->bpf.flags = flags; |
1852 | tcb->bpf.map = map; | 1853 | tcb->bpf.map = map; |
1853 | 1854 | ||
1854 | return SK_REDIRECT; | 1855 | return SK_PASS; |
1855 | } | 1856 | } |
1856 | 1857 | ||
1857 | struct sock *do_sk_redirect_map(struct sk_buff *skb) | 1858 | struct sock *do_sk_redirect_map(struct sk_buff *skb) |
@@ -4243,6 +4244,31 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, | |||
4243 | return insn - insn_buf; | 4244 | return insn - insn_buf; |
4244 | } | 4245 | } |
4245 | 4246 | ||
4247 | static u32 sk_skb_convert_ctx_access(enum bpf_access_type type, | ||
4248 | const struct bpf_insn *si, | ||
4249 | struct bpf_insn *insn_buf, | ||
4250 | struct bpf_prog *prog, u32 *target_size) | ||
4251 | { | ||
4252 | struct bpf_insn *insn = insn_buf; | ||
4253 | int off; | ||
4254 | |||
4255 | switch (si->off) { | ||
4256 | case offsetof(struct __sk_buff, data_end): | ||
4257 | off = si->off; | ||
4258 | off -= offsetof(struct __sk_buff, data_end); | ||
4259 | off += offsetof(struct sk_buff, cb); | ||
4260 | off += offsetof(struct tcp_skb_cb, bpf.data_end); | ||
4261 | *insn++ = BPF_LDX_MEM(BPF_SIZEOF(void *), si->dst_reg, | ||
4262 | si->src_reg, off); | ||
4263 | break; | ||
4264 | default: | ||
4265 | return bpf_convert_ctx_access(type, si, insn_buf, prog, | ||
4266 | target_size); | ||
4267 | } | ||
4268 | |||
4269 | return insn - insn_buf; | ||
4270 | } | ||
4271 | |||
4246 | const struct bpf_verifier_ops sk_filter_prog_ops = { | 4272 | const struct bpf_verifier_ops sk_filter_prog_ops = { |
4247 | .get_func_proto = sk_filter_func_proto, | 4273 | .get_func_proto = sk_filter_func_proto, |
4248 | .is_valid_access = sk_filter_is_valid_access, | 4274 | .is_valid_access = sk_filter_is_valid_access, |
@@ -4301,7 +4327,7 @@ const struct bpf_verifier_ops sock_ops_prog_ops = { | |||
4301 | const struct bpf_verifier_ops sk_skb_prog_ops = { | 4327 | const struct bpf_verifier_ops sk_skb_prog_ops = { |
4302 | .get_func_proto = sk_skb_func_proto, | 4328 | .get_func_proto = sk_skb_func_proto, |
4303 | .is_valid_access = sk_skb_is_valid_access, | 4329 | .is_valid_access = sk_skb_is_valid_access, |
4304 | .convert_ctx_access = bpf_convert_ctx_access, | 4330 | .convert_ctx_access = sk_skb_convert_ctx_access, |
4305 | .gen_prologue = sk_skb_prologue, | 4331 | .gen_prologue = sk_skb_prologue, |
4306 | }; | 4332 | }; |
4307 | 4333 | ||
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 0490916864f9..e65fcb45c3f6 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -495,7 +495,7 @@ static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req | |||
495 | ireq->ir_rmt_addr); | 495 | ireq->ir_rmt_addr); |
496 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, | 496 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, |
497 | ireq->ir_rmt_addr, | 497 | ireq->ir_rmt_addr, |
498 | rcu_dereference(ireq->ireq_opt)); | 498 | ireq_opt_deref(ireq)); |
499 | err = net_xmit_eval(err); | 499 | err = net_xmit_eval(err); |
500 | } | 500 | } |
501 | 501 | ||
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 873af0108e24..045d8a176279 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c | |||
@@ -496,14 +496,15 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index, | |||
496 | if (!ethernet) | 496 | if (!ethernet) |
497 | return -EINVAL; | 497 | return -EINVAL; |
498 | ethernet_dev = of_find_net_device_by_node(ethernet); | 498 | ethernet_dev = of_find_net_device_by_node(ethernet); |
499 | if (!ethernet_dev) | ||
500 | return -EPROBE_DEFER; | ||
499 | } else { | 501 | } else { |
500 | ethernet_dev = dsa_dev_to_net_device(ds->cd->netdev[index]); | 502 | ethernet_dev = dsa_dev_to_net_device(ds->cd->netdev[index]); |
503 | if (!ethernet_dev) | ||
504 | return -EPROBE_DEFER; | ||
501 | dev_put(ethernet_dev); | 505 | dev_put(ethernet_dev); |
502 | } | 506 | } |
503 | 507 | ||
504 | if (!ethernet_dev) | ||
505 | return -EPROBE_DEFER; | ||
506 | |||
507 | if (!dst->cpu_dp) { | 508 | if (!dst->cpu_dp) { |
508 | dst->cpu_dp = port; | 509 | dst->cpu_dp = port; |
509 | dst->cpu_dp->netdev = ethernet_dev; | 510 | dst->cpu_dp->netdev = ethernet_dev; |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 5ec9136a7c36..b47a59cb3573 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -543,7 +543,8 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk, | |||
543 | struct ip_options_rcu *opt; | 543 | struct ip_options_rcu *opt; |
544 | struct rtable *rt; | 544 | struct rtable *rt; |
545 | 545 | ||
546 | opt = rcu_dereference(ireq->ireq_opt); | 546 | opt = ireq_opt_deref(ireq); |
547 | |||
547 | flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, | 548 | flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, |
548 | RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, | 549 | RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, |
549 | sk->sk_protocol, inet_sk_flowi_flags(sk), | 550 | sk->sk_protocol, inet_sk_flowi_flags(sk), |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index fb1ad22b5e29..cdd627355ed1 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -128,43 +128,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly; | |||
128 | 128 | ||
129 | static int ipip_err(struct sk_buff *skb, u32 info) | 129 | static int ipip_err(struct sk_buff *skb, u32 info) |
130 | { | 130 | { |
131 | 131 | /* All the routers (except for Linux) return only | |
132 | /* All the routers (except for Linux) return only | 132 | * 8 bytes of packet payload. It means, that precise relaying of |
133 | 8 bytes of packet payload. It means, that precise relaying of | 133 | * ICMP in the real Internet is absolutely infeasible. |
134 | ICMP in the real Internet is absolutely infeasible. | 134 | */ |
135 | */ | ||
136 | struct net *net = dev_net(skb->dev); | 135 | struct net *net = dev_net(skb->dev); |
137 | struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); | 136 | struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); |
138 | const struct iphdr *iph = (const struct iphdr *)skb->data; | 137 | const struct iphdr *iph = (const struct iphdr *)skb->data; |
139 | struct ip_tunnel *t; | ||
140 | int err; | ||
141 | const int type = icmp_hdr(skb)->type; | 138 | const int type = icmp_hdr(skb)->type; |
142 | const int code = icmp_hdr(skb)->code; | 139 | const int code = icmp_hdr(skb)->code; |
140 | struct ip_tunnel *t; | ||
141 | int err = 0; | ||
142 | |||
143 | switch (type) { | ||
144 | case ICMP_DEST_UNREACH: | ||
145 | switch (code) { | ||
146 | case ICMP_SR_FAILED: | ||
147 | /* Impossible event. */ | ||
148 | goto out; | ||
149 | default: | ||
150 | /* All others are translated to HOST_UNREACH. | ||
151 | * rfc2003 contains "deep thoughts" about NET_UNREACH, | ||
152 | * I believe they are just ether pollution. --ANK | ||
153 | */ | ||
154 | break; | ||
155 | } | ||
156 | break; | ||
157 | |||
158 | case ICMP_TIME_EXCEEDED: | ||
159 | if (code != ICMP_EXC_TTL) | ||
160 | goto out; | ||
161 | break; | ||
162 | |||
163 | case ICMP_REDIRECT: | ||
164 | break; | ||
165 | |||
166 | default: | ||
167 | goto out; | ||
168 | } | ||
143 | 169 | ||
144 | err = -ENOENT; | ||
145 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, | 170 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, |
146 | iph->daddr, iph->saddr, 0); | 171 | iph->daddr, iph->saddr, 0); |
147 | if (!t) | 172 | if (!t) { |
173 | err = -ENOENT; | ||
148 | goto out; | 174 | goto out; |
175 | } | ||
149 | 176 | ||
150 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | 177 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { |
151 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | 178 | ipv4_update_pmtu(skb, net, info, t->parms.link, 0, |
152 | t->parms.link, 0, iph->protocol, 0); | 179 | iph->protocol, 0); |
153 | err = 0; | ||
154 | goto out; | 180 | goto out; |
155 | } | 181 | } |
156 | 182 | ||
157 | if (type == ICMP_REDIRECT) { | 183 | if (type == ICMP_REDIRECT) { |
158 | ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, | 184 | ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0); |
159 | iph->protocol, 0); | ||
160 | err = 0; | ||
161 | goto out; | 185 | goto out; |
162 | } | 186 | } |
163 | 187 | ||
164 | if (t->parms.iph.daddr == 0) | 188 | if (t->parms.iph.daddr == 0) { |
189 | err = -ENOENT; | ||
165 | goto out; | 190 | goto out; |
191 | } | ||
166 | 192 | ||
167 | err = 0; | ||
168 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) | 193 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) |
169 | goto out; | 194 | goto out; |
170 | 195 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4c43365c374c..5b027c69cbc5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -877,7 +877,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
877 | 877 | ||
878 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, | 878 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, |
879 | ireq->ir_rmt_addr, | 879 | ireq->ir_rmt_addr, |
880 | rcu_dereference(ireq->ireq_opt)); | 880 | ireq_opt_deref(ireq)); |
881 | err = net_xmit_eval(err); | 881 | err = net_xmit_eval(err); |
882 | } | 882 | } |
883 | 883 | ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0bc9e46a5369..ae60dd3faed0 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -739,8 +739,10 @@ static void tcp_tsq_handler(struct sock *sk) | |||
739 | struct tcp_sock *tp = tcp_sk(sk); | 739 | struct tcp_sock *tp = tcp_sk(sk); |
740 | 740 | ||
741 | if (tp->lost_out > tp->retrans_out && | 741 | if (tp->lost_out > tp->retrans_out && |
742 | tp->snd_cwnd > tcp_packets_in_flight(tp)) | 742 | tp->snd_cwnd > tcp_packets_in_flight(tp)) { |
743 | tcp_mstamp_refresh(tp); | ||
743 | tcp_xmit_retransmit_queue(sk); | 744 | tcp_xmit_retransmit_queue(sk); |
745 | } | ||
744 | 746 | ||
745 | tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, | 747 | tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, |
746 | 0, GFP_ATOMIC); | 748 | 0, GFP_ATOMIC); |
@@ -2237,6 +2239,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, | |||
2237 | 2239 | ||
2238 | sent_pkts = 0; | 2240 | sent_pkts = 0; |
2239 | 2241 | ||
2242 | tcp_mstamp_refresh(tp); | ||
2240 | if (!push_one) { | 2243 | if (!push_one) { |
2241 | /* Do MTU probing. */ | 2244 | /* Do MTU probing. */ |
2242 | result = tcp_mtu_probe(sk); | 2245 | result = tcp_mtu_probe(sk); |
@@ -2248,7 +2251,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, | |||
2248 | } | 2251 | } |
2249 | 2252 | ||
2250 | max_segs = tcp_tso_segs(sk, mss_now); | 2253 | max_segs = tcp_tso_segs(sk, mss_now); |
2251 | tcp_mstamp_refresh(tp); | ||
2252 | while ((skb = tcp_send_head(sk))) { | 2254 | while ((skb = tcp_send_head(sk))) { |
2253 | unsigned int limit; | 2255 | unsigned int limit; |
2254 | 2256 | ||
@@ -2841,8 +2843,10 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) | |||
2841 | nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); | 2843 | nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); |
2842 | err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : | 2844 | err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : |
2843 | -ENOBUFS; | 2845 | -ENOBUFS; |
2844 | if (!err) | 2846 | if (!err) { |
2845 | skb->skb_mstamp = tp->tcp_mstamp; | 2847 | skb->skb_mstamp = tp->tcp_mstamp; |
2848 | tcp_rate_skb_sent(sk, skb); | ||
2849 | } | ||
2846 | } else { | 2850 | } else { |
2847 | err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); | 2851 | err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); |
2848 | } | 2852 | } |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 1602b491b281..59c121b932ac 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -408,13 +408,16 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
408 | case ICMPV6_DEST_UNREACH: | 408 | case ICMPV6_DEST_UNREACH: |
409 | net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n", | 409 | net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n", |
410 | t->parms.name); | 410 | t->parms.name); |
411 | break; | 411 | if (code != ICMPV6_PORT_UNREACH) |
412 | break; | ||
413 | return; | ||
412 | case ICMPV6_TIME_EXCEED: | 414 | case ICMPV6_TIME_EXCEED: |
413 | if (code == ICMPV6_EXC_HOPLIMIT) { | 415 | if (code == ICMPV6_EXC_HOPLIMIT) { |
414 | net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n", | 416 | net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n", |
415 | t->parms.name); | 417 | t->parms.name); |
418 | break; | ||
416 | } | 419 | } |
417 | break; | 420 | return; |
418 | case ICMPV6_PARAMPROB: | 421 | case ICMPV6_PARAMPROB: |
419 | teli = 0; | 422 | teli = 0; |
420 | if (code == ICMPV6_HDR_FIELD) | 423 | if (code == ICMPV6_HDR_FIELD) |
@@ -430,7 +433,7 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
430 | net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n", | 433 | net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n", |
431 | t->parms.name); | 434 | t->parms.name); |
432 | } | 435 | } |
433 | break; | 436 | return; |
434 | case ICMPV6_PKT_TOOBIG: | 437 | case ICMPV6_PKT_TOOBIG: |
435 | mtu = be32_to_cpu(info) - offset - t->tun_hlen; | 438 | mtu = be32_to_cpu(info) - offset - t->tun_hlen; |
436 | if (t->dev->type == ARPHRD_ETHER) | 439 | if (t->dev->type == ARPHRD_ETHER) |
@@ -438,7 +441,7 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
438 | if (mtu < IPV6_MIN_MTU) | 441 | if (mtu < IPV6_MIN_MTU) |
439 | mtu = IPV6_MIN_MTU; | 442 | mtu = IPV6_MIN_MTU; |
440 | t->dev->mtu = mtu; | 443 | t->dev->mtu = mtu; |
441 | break; | 444 | return; |
442 | } | 445 | } |
443 | 446 | ||
444 | if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO)) | 447 | if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO)) |
@@ -500,8 +503,8 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb, | |||
500 | __u32 *pmtu, __be16 proto) | 503 | __u32 *pmtu, __be16 proto) |
501 | { | 504 | { |
502 | struct ip6_tnl *tunnel = netdev_priv(dev); | 505 | struct ip6_tnl *tunnel = netdev_priv(dev); |
503 | __be16 protocol = (dev->type == ARPHRD_ETHER) ? | 506 | struct dst_entry *dst = skb_dst(skb); |
504 | htons(ETH_P_TEB) : proto; | 507 | __be16 protocol; |
505 | 508 | ||
506 | if (dev->type == ARPHRD_ETHER) | 509 | if (dev->type == ARPHRD_ETHER) |
507 | IPCB(skb)->flags = 0; | 510 | IPCB(skb)->flags = 0; |
@@ -515,9 +518,14 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb, | |||
515 | tunnel->o_seqno++; | 518 | tunnel->o_seqno++; |
516 | 519 | ||
517 | /* Push GRE header. */ | 520 | /* Push GRE header. */ |
521 | protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto; | ||
518 | gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, | 522 | gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, |
519 | protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno)); | 523 | protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno)); |
520 | 524 | ||
525 | /* TooBig packet may have updated dst->dev's mtu */ | ||
526 | if (dst && dst_mtu(dst) > dst->dev->mtu) | ||
527 | dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu); | ||
528 | |||
521 | return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu, | 529 | return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu, |
522 | NEXTHDR_GRE); | 530 | NEXTHDR_GRE); |
523 | } | 531 | } |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a354f1939e49..fb15d3b97cb2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2727,12 +2727,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
2727 | if (!ieee80211_sdata_running(sdata)) | 2727 | if (!ieee80211_sdata_running(sdata)) |
2728 | return -ENETDOWN; | 2728 | return -ENETDOWN; |
2729 | 2729 | ||
2730 | if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { | ||
2731 | ret = drv_set_bitrate_mask(local, sdata, mask); | ||
2732 | if (ret) | ||
2733 | return ret; | ||
2734 | } | ||
2735 | |||
2736 | /* | 2730 | /* |
2737 | * If active validate the setting and reject it if it doesn't leave | 2731 | * If active validate the setting and reject it if it doesn't leave |
2738 | * at least one basic rate usable, since we really have to be able | 2732 | * at least one basic rate usable, since we really have to be able |
@@ -2748,6 +2742,12 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
2748 | return -EINVAL; | 2742 | return -EINVAL; |
2749 | } | 2743 | } |
2750 | 2744 | ||
2745 | if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { | ||
2746 | ret = drv_set_bitrate_mask(local, sdata, mask); | ||
2747 | if (ret) | ||
2748 | return ret; | ||
2749 | } | ||
2750 | |||
2751 | for (i = 0; i < NUM_NL80211_BANDS; i++) { | 2751 | for (i = 0; i < NUM_NL80211_BANDS; i++) { |
2752 | struct ieee80211_supported_band *sband = wiphy->bands[i]; | 2752 | struct ieee80211_supported_band *sband = wiphy->bands[i]; |
2753 | int j; | 2753 | int j; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ae995c8480db..938049395f90 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/export.h> | 20 | #include <linux/export.h> |
21 | #include <net/mac80211.h> | 21 | #include <net/mac80211.h> |
22 | #include <crypto/algapi.h> | ||
22 | #include <asm/unaligned.h> | 23 | #include <asm/unaligned.h> |
23 | #include "ieee80211_i.h" | 24 | #include "ieee80211_i.h" |
24 | #include "driver-ops.h" | 25 | #include "driver-ops.h" |
@@ -609,6 +610,39 @@ void ieee80211_key_free_unused(struct ieee80211_key *key) | |||
609 | ieee80211_key_free_common(key); | 610 | ieee80211_key_free_common(key); |
610 | } | 611 | } |
611 | 612 | ||
613 | static bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata, | ||
614 | struct ieee80211_key *old, | ||
615 | struct ieee80211_key *new) | ||
616 | { | ||
617 | u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP]; | ||
618 | u8 *tk_old, *tk_new; | ||
619 | |||
620 | if (!old || new->conf.keylen != old->conf.keylen) | ||
621 | return false; | ||
622 | |||
623 | tk_old = old->conf.key; | ||
624 | tk_new = new->conf.key; | ||
625 | |||
626 | /* | ||
627 | * In station mode, don't compare the TX MIC key, as it's never used | ||
628 | * and offloaded rekeying may not care to send it to the host. This | ||
629 | * is the case in iwlwifi, for example. | ||
630 | */ | ||
631 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
632 | new->conf.cipher == WLAN_CIPHER_SUITE_TKIP && | ||
633 | new->conf.keylen == WLAN_KEY_LEN_TKIP && | ||
634 | !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | ||
635 | memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP); | ||
636 | memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP); | ||
637 | memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8); | ||
638 | memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8); | ||
639 | tk_old = tkip_old; | ||
640 | tk_new = tkip_new; | ||
641 | } | ||
642 | |||
643 | return !crypto_memneq(tk_old, tk_new, new->conf.keylen); | ||
644 | } | ||
645 | |||
612 | int ieee80211_key_link(struct ieee80211_key *key, | 646 | int ieee80211_key_link(struct ieee80211_key *key, |
613 | struct ieee80211_sub_if_data *sdata, | 647 | struct ieee80211_sub_if_data *sdata, |
614 | struct sta_info *sta) | 648 | struct sta_info *sta) |
@@ -634,8 +668,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
634 | * Silently accept key re-installation without really installing the | 668 | * Silently accept key re-installation without really installing the |
635 | * new version of the key to avoid nonce reuse or replay issues. | 669 | * new version of the key to avoid nonce reuse or replay issues. |
636 | */ | 670 | */ |
637 | if (old_key && key->conf.keylen == old_key->conf.keylen && | 671 | if (ieee80211_key_identical(sdata, old_key, key)) { |
638 | !memcmp(key->conf.key, old_key->conf.key, key->conf.keylen)) { | ||
639 | ieee80211_key_free_unused(key); | 672 | ieee80211_key_free_unused(key); |
640 | ret = 0; | 673 | ret = 0; |
641 | goto out; | 674 | goto out; |
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index 6ab39dbcca01..8557a1cae041 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c | |||
@@ -661,13 +661,15 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | 663 | ||
664 | rds_ib_set_wr_signal_state(ic, send, 0); | 664 | rds_ib_set_wr_signal_state(ic, send, false); |
665 | 665 | ||
666 | /* | 666 | /* |
667 | * Always signal the last one if we're stopping due to flow control. | 667 | * Always signal the last one if we're stopping due to flow control. |
668 | */ | 668 | */ |
669 | if (ic->i_flowctl && flow_controlled && i == (work_alloc-1)) | 669 | if (ic->i_flowctl && flow_controlled && i == (work_alloc - 1)) { |
670 | send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED; | 670 | rds_ib_set_wr_signal_state(ic, send, true); |
671 | send->s_wr.send_flags |= IB_SEND_SOLICITED; | ||
672 | } | ||
671 | 673 | ||
672 | if (send->s_wr.send_flags & IB_SEND_SIGNALED) | 674 | if (send->s_wr.send_flags & IB_SEND_SIGNALED) |
673 | nr_sig++; | 675 | nr_sig++; |
@@ -705,11 +707,8 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, | |||
705 | if (scat == &rm->data.op_sg[rm->data.op_count]) { | 707 | if (scat == &rm->data.op_sg[rm->data.op_count]) { |
706 | prev->s_op = ic->i_data_op; | 708 | prev->s_op = ic->i_data_op; |
707 | prev->s_wr.send_flags |= IB_SEND_SOLICITED; | 709 | prev->s_wr.send_flags |= IB_SEND_SOLICITED; |
708 | if (!(prev->s_wr.send_flags & IB_SEND_SIGNALED)) { | 710 | if (!(prev->s_wr.send_flags & IB_SEND_SIGNALED)) |
709 | ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs; | 711 | nr_sig += rds_ib_set_wr_signal_state(ic, prev, true); |
710 | prev->s_wr.send_flags |= IB_SEND_SIGNALED; | ||
711 | nr_sig++; | ||
712 | } | ||
713 | ic->i_data_op = NULL; | 712 | ic->i_data_op = NULL; |
714 | } | 713 | } |
715 | 714 | ||
@@ -792,6 +791,7 @@ int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op) | |||
792 | send->s_atomic_wr.compare_add_mask = op->op_m_fadd.nocarry_mask; | 791 | send->s_atomic_wr.compare_add_mask = op->op_m_fadd.nocarry_mask; |
793 | send->s_atomic_wr.swap_mask = 0; | 792 | send->s_atomic_wr.swap_mask = 0; |
794 | } | 793 | } |
794 | send->s_wr.send_flags = 0; | ||
795 | nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify); | 795 | nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify); |
796 | send->s_atomic_wr.wr.num_sge = 1; | 796 | send->s_atomic_wr.wr.num_sge = 1; |
797 | send->s_atomic_wr.wr.next = NULL; | 797 | send->s_atomic_wr.wr.next = NULL; |
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index ec986ae52808..a9f9a2ccc664 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c | |||
@@ -264,6 +264,7 @@ static int __init sample_init_module(void) | |||
264 | 264 | ||
265 | static void __exit sample_cleanup_module(void) | 265 | static void __exit sample_cleanup_module(void) |
266 | { | 266 | { |
267 | rcu_barrier(); | ||
267 | tcf_unregister_action(&act_sample_ops, &sample_net_ops); | 268 | tcf_unregister_action(&act_sample_ops, &sample_net_ops); |
268 | } | 269 | } |
269 | 270 | ||
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 0b2219adf520..231181c602ed 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
@@ -77,6 +77,8 @@ out: | |||
77 | } | 77 | } |
78 | EXPORT_SYMBOL(register_tcf_proto_ops); | 78 | EXPORT_SYMBOL(register_tcf_proto_ops); |
79 | 79 | ||
80 | static struct workqueue_struct *tc_filter_wq; | ||
81 | |||
80 | int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) | 82 | int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) |
81 | { | 83 | { |
82 | struct tcf_proto_ops *t; | 84 | struct tcf_proto_ops *t; |
@@ -86,6 +88,7 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) | |||
86 | * tcf_proto_ops's destroy() handler. | 88 | * tcf_proto_ops's destroy() handler. |
87 | */ | 89 | */ |
88 | rcu_barrier(); | 90 | rcu_barrier(); |
91 | flush_workqueue(tc_filter_wq); | ||
89 | 92 | ||
90 | write_lock(&cls_mod_lock); | 93 | write_lock(&cls_mod_lock); |
91 | list_for_each_entry(t, &tcf_proto_base, head) { | 94 | list_for_each_entry(t, &tcf_proto_base, head) { |
@@ -100,6 +103,12 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) | |||
100 | } | 103 | } |
101 | EXPORT_SYMBOL(unregister_tcf_proto_ops); | 104 | EXPORT_SYMBOL(unregister_tcf_proto_ops); |
102 | 105 | ||
106 | bool tcf_queue_work(struct work_struct *work) | ||
107 | { | ||
108 | return queue_work(tc_filter_wq, work); | ||
109 | } | ||
110 | EXPORT_SYMBOL(tcf_queue_work); | ||
111 | |||
103 | /* Select new prio value from the range, managed by kernel. */ | 112 | /* Select new prio value from the range, managed by kernel. */ |
104 | 113 | ||
105 | static inline u32 tcf_auto_prio(struct tcf_proto *tp) | 114 | static inline u32 tcf_auto_prio(struct tcf_proto *tp) |
@@ -266,23 +275,30 @@ err_chain_create: | |||
266 | } | 275 | } |
267 | EXPORT_SYMBOL(tcf_block_get); | 276 | EXPORT_SYMBOL(tcf_block_get); |
268 | 277 | ||
269 | void tcf_block_put(struct tcf_block *block) | 278 | static void tcf_block_put_final(struct work_struct *work) |
270 | { | 279 | { |
280 | struct tcf_block *block = container_of(work, struct tcf_block, work); | ||
271 | struct tcf_chain *chain, *tmp; | 281 | struct tcf_chain *chain, *tmp; |
272 | 282 | ||
273 | if (!block) | 283 | /* At this point, all the chains should have refcnt == 1. */ |
274 | return; | 284 | rtnl_lock(); |
275 | 285 | list_for_each_entry_safe(chain, tmp, &block->chain_list, list) | |
276 | /* XXX: Standalone actions are not allowed to jump to any chain, and | 286 | tcf_chain_put(chain); |
277 | * bound actions should be all removed after flushing. However, | 287 | rtnl_unlock(); |
278 | * filters are destroyed in RCU callbacks, we have to hold the chains | 288 | kfree(block); |
279 | * first, otherwise we would always race with RCU callbacks on this list | 289 | } |
280 | * without proper locking. | ||
281 | */ | ||
282 | 290 | ||
283 | /* Wait for existing RCU callbacks to cool down. */ | 291 | /* XXX: Standalone actions are not allowed to jump to any chain, and bound |
284 | rcu_barrier(); | 292 | * actions should be all removed after flushing. However, filters are destroyed |
293 | * in RCU callbacks, we have to hold the chains first, otherwise we would | ||
294 | * always race with RCU callbacks on this list without proper locking. | ||
295 | */ | ||
296 | static void tcf_block_put_deferred(struct work_struct *work) | ||
297 | { | ||
298 | struct tcf_block *block = container_of(work, struct tcf_block, work); | ||
299 | struct tcf_chain *chain; | ||
285 | 300 | ||
301 | rtnl_lock(); | ||
286 | /* Hold a refcnt for all chains, except 0, in case they are gone. */ | 302 | /* Hold a refcnt for all chains, except 0, in case they are gone. */ |
287 | list_for_each_entry(chain, &block->chain_list, list) | 303 | list_for_each_entry(chain, &block->chain_list, list) |
288 | if (chain->index) | 304 | if (chain->index) |
@@ -292,13 +308,27 @@ void tcf_block_put(struct tcf_block *block) | |||
292 | list_for_each_entry(chain, &block->chain_list, list) | 308 | list_for_each_entry(chain, &block->chain_list, list) |
293 | tcf_chain_flush(chain); | 309 | tcf_chain_flush(chain); |
294 | 310 | ||
295 | /* Wait for RCU callbacks to release the reference count. */ | 311 | INIT_WORK(&block->work, tcf_block_put_final); |
312 | /* Wait for RCU callbacks to release the reference count and make | ||
313 | * sure their works have been queued before this. | ||
314 | */ | ||
296 | rcu_barrier(); | 315 | rcu_barrier(); |
316 | tcf_queue_work(&block->work); | ||
317 | rtnl_unlock(); | ||
318 | } | ||
297 | 319 | ||
298 | /* At this point, all the chains should have refcnt == 1. */ | 320 | void tcf_block_put(struct tcf_block *block) |
299 | list_for_each_entry_safe(chain, tmp, &block->chain_list, list) | 321 | { |
300 | tcf_chain_put(chain); | 322 | if (!block) |
301 | kfree(block); | 323 | return; |
324 | |||
325 | INIT_WORK(&block->work, tcf_block_put_deferred); | ||
326 | /* Wait for existing RCU callbacks to cool down, make sure their works | ||
327 | * have been queued before this. We can not flush pending works here | ||
328 | * because we are holding the RTNL lock. | ||
329 | */ | ||
330 | rcu_barrier(); | ||
331 | tcf_queue_work(&block->work); | ||
302 | } | 332 | } |
303 | EXPORT_SYMBOL(tcf_block_put); | 333 | EXPORT_SYMBOL(tcf_block_put); |
304 | 334 | ||
@@ -879,6 +909,7 @@ void tcf_exts_destroy(struct tcf_exts *exts) | |||
879 | #ifdef CONFIG_NET_CLS_ACT | 909 | #ifdef CONFIG_NET_CLS_ACT |
880 | LIST_HEAD(actions); | 910 | LIST_HEAD(actions); |
881 | 911 | ||
912 | ASSERT_RTNL(); | ||
882 | tcf_exts_to_list(exts, &actions); | 913 | tcf_exts_to_list(exts, &actions); |
883 | tcf_action_destroy(&actions, TCA_ACT_UNBIND); | 914 | tcf_action_destroy(&actions, TCA_ACT_UNBIND); |
884 | kfree(exts->actions); | 915 | kfree(exts->actions); |
@@ -1030,6 +1061,10 @@ EXPORT_SYMBOL(tcf_exts_get_dev); | |||
1030 | 1061 | ||
1031 | static int __init tc_filter_init(void) | 1062 | static int __init tc_filter_init(void) |
1032 | { | 1063 | { |
1064 | tc_filter_wq = alloc_ordered_workqueue("tc_filter_workqueue", 0); | ||
1065 | if (!tc_filter_wq) | ||
1066 | return -ENOMEM; | ||
1067 | |||
1033 | rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, 0); | 1068 | rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, 0); |
1034 | rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, 0); | 1069 | rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, 0); |
1035 | rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter, | 1070 | rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter, |
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index d89ebafd2239..f177649a2419 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c | |||
@@ -34,7 +34,10 @@ struct basic_filter { | |||
34 | struct tcf_result res; | 34 | struct tcf_result res; |
35 | struct tcf_proto *tp; | 35 | struct tcf_proto *tp; |
36 | struct list_head link; | 36 | struct list_head link; |
37 | struct rcu_head rcu; | 37 | union { |
38 | struct work_struct work; | ||
39 | struct rcu_head rcu; | ||
40 | }; | ||
38 | }; | 41 | }; |
39 | 42 | ||
40 | static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 43 | static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
@@ -82,15 +85,26 @@ static int basic_init(struct tcf_proto *tp) | |||
82 | return 0; | 85 | return 0; |
83 | } | 86 | } |
84 | 87 | ||
85 | static void basic_delete_filter(struct rcu_head *head) | 88 | static void basic_delete_filter_work(struct work_struct *work) |
86 | { | 89 | { |
87 | struct basic_filter *f = container_of(head, struct basic_filter, rcu); | 90 | struct basic_filter *f = container_of(work, struct basic_filter, work); |
88 | 91 | ||
92 | rtnl_lock(); | ||
89 | tcf_exts_destroy(&f->exts); | 93 | tcf_exts_destroy(&f->exts); |
90 | tcf_em_tree_destroy(&f->ematches); | 94 | tcf_em_tree_destroy(&f->ematches); |
95 | rtnl_unlock(); | ||
96 | |||
91 | kfree(f); | 97 | kfree(f); |
92 | } | 98 | } |
93 | 99 | ||
100 | static void basic_delete_filter(struct rcu_head *head) | ||
101 | { | ||
102 | struct basic_filter *f = container_of(head, struct basic_filter, rcu); | ||
103 | |||
104 | INIT_WORK(&f->work, basic_delete_filter_work); | ||
105 | tcf_queue_work(&f->work); | ||
106 | } | ||
107 | |||
94 | static void basic_destroy(struct tcf_proto *tp) | 108 | static void basic_destroy(struct tcf_proto *tp) |
95 | { | 109 | { |
96 | struct basic_head *head = rtnl_dereference(tp->root); | 110 | struct basic_head *head = rtnl_dereference(tp->root); |
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 520c5027646a..037a3ae86829 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c | |||
@@ -49,7 +49,10 @@ struct cls_bpf_prog { | |||
49 | struct sock_filter *bpf_ops; | 49 | struct sock_filter *bpf_ops; |
50 | const char *bpf_name; | 50 | const char *bpf_name; |
51 | struct tcf_proto *tp; | 51 | struct tcf_proto *tp; |
52 | struct rcu_head rcu; | 52 | union { |
53 | struct work_struct work; | ||
54 | struct rcu_head rcu; | ||
55 | }; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = { | 58 | static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = { |
@@ -257,9 +260,21 @@ static void __cls_bpf_delete_prog(struct cls_bpf_prog *prog) | |||
257 | kfree(prog); | 260 | kfree(prog); |
258 | } | 261 | } |
259 | 262 | ||
263 | static void cls_bpf_delete_prog_work(struct work_struct *work) | ||
264 | { | ||
265 | struct cls_bpf_prog *prog = container_of(work, struct cls_bpf_prog, work); | ||
266 | |||
267 | rtnl_lock(); | ||
268 | __cls_bpf_delete_prog(prog); | ||
269 | rtnl_unlock(); | ||
270 | } | ||
271 | |||
260 | static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu) | 272 | static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu) |
261 | { | 273 | { |
262 | __cls_bpf_delete_prog(container_of(rcu, struct cls_bpf_prog, rcu)); | 274 | struct cls_bpf_prog *prog = container_of(rcu, struct cls_bpf_prog, rcu); |
275 | |||
276 | INIT_WORK(&prog->work, cls_bpf_delete_prog_work); | ||
277 | tcf_queue_work(&prog->work); | ||
263 | } | 278 | } |
264 | 279 | ||
265 | static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog) | 280 | static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog) |
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index d48452f87975..a97e069bee89 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
@@ -23,7 +23,10 @@ struct cls_cgroup_head { | |||
23 | struct tcf_exts exts; | 23 | struct tcf_exts exts; |
24 | struct tcf_ematch_tree ematches; | 24 | struct tcf_ematch_tree ematches; |
25 | struct tcf_proto *tp; | 25 | struct tcf_proto *tp; |
26 | struct rcu_head rcu; | 26 | union { |
27 | struct work_struct work; | ||
28 | struct rcu_head rcu; | ||
29 | }; | ||
27 | }; | 30 | }; |
28 | 31 | ||
29 | static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 32 | static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
@@ -57,15 +60,26 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { | |||
57 | [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, | 60 | [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, |
58 | }; | 61 | }; |
59 | 62 | ||
63 | static void cls_cgroup_destroy_work(struct work_struct *work) | ||
64 | { | ||
65 | struct cls_cgroup_head *head = container_of(work, | ||
66 | struct cls_cgroup_head, | ||
67 | work); | ||
68 | rtnl_lock(); | ||
69 | tcf_exts_destroy(&head->exts); | ||
70 | tcf_em_tree_destroy(&head->ematches); | ||
71 | kfree(head); | ||
72 | rtnl_unlock(); | ||
73 | } | ||
74 | |||
60 | static void cls_cgroup_destroy_rcu(struct rcu_head *root) | 75 | static void cls_cgroup_destroy_rcu(struct rcu_head *root) |
61 | { | 76 | { |
62 | struct cls_cgroup_head *head = container_of(root, | 77 | struct cls_cgroup_head *head = container_of(root, |
63 | struct cls_cgroup_head, | 78 | struct cls_cgroup_head, |
64 | rcu); | 79 | rcu); |
65 | 80 | ||
66 | tcf_exts_destroy(&head->exts); | 81 | INIT_WORK(&head->work, cls_cgroup_destroy_work); |
67 | tcf_em_tree_destroy(&head->ematches); | 82 | tcf_queue_work(&head->work); |
68 | kfree(head); | ||
69 | } | 83 | } |
70 | 84 | ||
71 | static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, | 85 | static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, |
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 2a3a60ec5b86..67f3a2af6aab 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
@@ -57,7 +57,10 @@ struct flow_filter { | |||
57 | u32 divisor; | 57 | u32 divisor; |
58 | u32 baseclass; | 58 | u32 baseclass; |
59 | u32 hashrnd; | 59 | u32 hashrnd; |
60 | struct rcu_head rcu; | 60 | union { |
61 | struct work_struct work; | ||
62 | struct rcu_head rcu; | ||
63 | }; | ||
61 | }; | 64 | }; |
62 | 65 | ||
63 | static inline u32 addr_fold(void *addr) | 66 | static inline u32 addr_fold(void *addr) |
@@ -369,14 +372,24 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { | |||
369 | [TCA_FLOW_PERTURB] = { .type = NLA_U32 }, | 372 | [TCA_FLOW_PERTURB] = { .type = NLA_U32 }, |
370 | }; | 373 | }; |
371 | 374 | ||
372 | static void flow_destroy_filter(struct rcu_head *head) | 375 | static void flow_destroy_filter_work(struct work_struct *work) |
373 | { | 376 | { |
374 | struct flow_filter *f = container_of(head, struct flow_filter, rcu); | 377 | struct flow_filter *f = container_of(work, struct flow_filter, work); |
375 | 378 | ||
379 | rtnl_lock(); | ||
376 | del_timer_sync(&f->perturb_timer); | 380 | del_timer_sync(&f->perturb_timer); |
377 | tcf_exts_destroy(&f->exts); | 381 | tcf_exts_destroy(&f->exts); |
378 | tcf_em_tree_destroy(&f->ematches); | 382 | tcf_em_tree_destroy(&f->ematches); |
379 | kfree(f); | 383 | kfree(f); |
384 | rtnl_unlock(); | ||
385 | } | ||
386 | |||
387 | static void flow_destroy_filter(struct rcu_head *head) | ||
388 | { | ||
389 | struct flow_filter *f = container_of(head, struct flow_filter, rcu); | ||
390 | |||
391 | INIT_WORK(&f->work, flow_destroy_filter_work); | ||
392 | tcf_queue_work(&f->work); | ||
380 | } | 393 | } |
381 | 394 | ||
382 | static int flow_change(struct net *net, struct sk_buff *in_skb, | 395 | static int flow_change(struct net *net, struct sk_buff *in_skb, |
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index b480d7c792ba..5b5722c8b32c 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -87,7 +87,10 @@ struct cls_fl_filter { | |||
87 | struct list_head list; | 87 | struct list_head list; |
88 | u32 handle; | 88 | u32 handle; |
89 | u32 flags; | 89 | u32 flags; |
90 | struct rcu_head rcu; | 90 | union { |
91 | struct work_struct work; | ||
92 | struct rcu_head rcu; | ||
93 | }; | ||
91 | struct net_device *hw_dev; | 94 | struct net_device *hw_dev; |
92 | }; | 95 | }; |
93 | 96 | ||
@@ -215,12 +218,22 @@ static int fl_init(struct tcf_proto *tp) | |||
215 | return 0; | 218 | return 0; |
216 | } | 219 | } |
217 | 220 | ||
218 | static void fl_destroy_filter(struct rcu_head *head) | 221 | static void fl_destroy_filter_work(struct work_struct *work) |
219 | { | 222 | { |
220 | struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); | 223 | struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work); |
221 | 224 | ||
225 | rtnl_lock(); | ||
222 | tcf_exts_destroy(&f->exts); | 226 | tcf_exts_destroy(&f->exts); |
223 | kfree(f); | 227 | kfree(f); |
228 | rtnl_unlock(); | ||
229 | } | ||
230 | |||
231 | static void fl_destroy_filter(struct rcu_head *head) | ||
232 | { | ||
233 | struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); | ||
234 | |||
235 | INIT_WORK(&f->work, fl_destroy_filter_work); | ||
236 | tcf_queue_work(&f->work); | ||
224 | } | 237 | } |
225 | 238 | ||
226 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) | 239 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) |
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 941245ad07fd..99183b8621ec 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c | |||
@@ -46,7 +46,10 @@ struct fw_filter { | |||
46 | #endif /* CONFIG_NET_CLS_IND */ | 46 | #endif /* CONFIG_NET_CLS_IND */ |
47 | struct tcf_exts exts; | 47 | struct tcf_exts exts; |
48 | struct tcf_proto *tp; | 48 | struct tcf_proto *tp; |
49 | struct rcu_head rcu; | 49 | union { |
50 | struct work_struct work; | ||
51 | struct rcu_head rcu; | ||
52 | }; | ||
50 | }; | 53 | }; |
51 | 54 | ||
52 | static u32 fw_hash(u32 handle) | 55 | static u32 fw_hash(u32 handle) |
@@ -119,12 +122,22 @@ static int fw_init(struct tcf_proto *tp) | |||
119 | return 0; | 122 | return 0; |
120 | } | 123 | } |
121 | 124 | ||
122 | static void fw_delete_filter(struct rcu_head *head) | 125 | static void fw_delete_filter_work(struct work_struct *work) |
123 | { | 126 | { |
124 | struct fw_filter *f = container_of(head, struct fw_filter, rcu); | 127 | struct fw_filter *f = container_of(work, struct fw_filter, work); |
125 | 128 | ||
129 | rtnl_lock(); | ||
126 | tcf_exts_destroy(&f->exts); | 130 | tcf_exts_destroy(&f->exts); |
127 | kfree(f); | 131 | kfree(f); |
132 | rtnl_unlock(); | ||
133 | } | ||
134 | |||
135 | static void fw_delete_filter(struct rcu_head *head) | ||
136 | { | ||
137 | struct fw_filter *f = container_of(head, struct fw_filter, rcu); | ||
138 | |||
139 | INIT_WORK(&f->work, fw_delete_filter_work); | ||
140 | tcf_queue_work(&f->work); | ||
128 | } | 141 | } |
129 | 142 | ||
130 | static void fw_destroy(struct tcf_proto *tp) | 143 | static void fw_destroy(struct tcf_proto *tp) |
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c index eeac606c95ab..c33f711b9019 100644 --- a/net/sched/cls_matchall.c +++ b/net/sched/cls_matchall.c | |||
@@ -21,7 +21,10 @@ struct cls_mall_head { | |||
21 | struct tcf_result res; | 21 | struct tcf_result res; |
22 | u32 handle; | 22 | u32 handle; |
23 | u32 flags; | 23 | u32 flags; |
24 | struct rcu_head rcu; | 24 | union { |
25 | struct work_struct work; | ||
26 | struct rcu_head rcu; | ||
27 | }; | ||
25 | }; | 28 | }; |
26 | 29 | ||
27 | static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 30 | static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
@@ -41,13 +44,23 @@ static int mall_init(struct tcf_proto *tp) | |||
41 | return 0; | 44 | return 0; |
42 | } | 45 | } |
43 | 46 | ||
47 | static void mall_destroy_work(struct work_struct *work) | ||
48 | { | ||
49 | struct cls_mall_head *head = container_of(work, struct cls_mall_head, | ||
50 | work); | ||
51 | rtnl_lock(); | ||
52 | tcf_exts_destroy(&head->exts); | ||
53 | kfree(head); | ||
54 | rtnl_unlock(); | ||
55 | } | ||
56 | |||
44 | static void mall_destroy_rcu(struct rcu_head *rcu) | 57 | static void mall_destroy_rcu(struct rcu_head *rcu) |
45 | { | 58 | { |
46 | struct cls_mall_head *head = container_of(rcu, struct cls_mall_head, | 59 | struct cls_mall_head *head = container_of(rcu, struct cls_mall_head, |
47 | rcu); | 60 | rcu); |
48 | 61 | ||
49 | tcf_exts_destroy(&head->exts); | 62 | INIT_WORK(&head->work, mall_destroy_work); |
50 | kfree(head); | 63 | tcf_queue_work(&head->work); |
51 | } | 64 | } |
52 | 65 | ||
53 | static int mall_replace_hw_filter(struct tcf_proto *tp, | 66 | static int mall_replace_hw_filter(struct tcf_proto *tp, |
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 9ddde65915d2..4b14ccd8b8f2 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c | |||
@@ -57,7 +57,10 @@ struct route4_filter { | |||
57 | u32 handle; | 57 | u32 handle; |
58 | struct route4_bucket *bkt; | 58 | struct route4_bucket *bkt; |
59 | struct tcf_proto *tp; | 59 | struct tcf_proto *tp; |
60 | struct rcu_head rcu; | 60 | union { |
61 | struct work_struct work; | ||
62 | struct rcu_head rcu; | ||
63 | }; | ||
61 | }; | 64 | }; |
62 | 65 | ||
63 | #define ROUTE4_FAILURE ((struct route4_filter *)(-1L)) | 66 | #define ROUTE4_FAILURE ((struct route4_filter *)(-1L)) |
@@ -254,12 +257,22 @@ static int route4_init(struct tcf_proto *tp) | |||
254 | return 0; | 257 | return 0; |
255 | } | 258 | } |
256 | 259 | ||
257 | static void route4_delete_filter(struct rcu_head *head) | 260 | static void route4_delete_filter_work(struct work_struct *work) |
258 | { | 261 | { |
259 | struct route4_filter *f = container_of(head, struct route4_filter, rcu); | 262 | struct route4_filter *f = container_of(work, struct route4_filter, work); |
260 | 263 | ||
264 | rtnl_lock(); | ||
261 | tcf_exts_destroy(&f->exts); | 265 | tcf_exts_destroy(&f->exts); |
262 | kfree(f); | 266 | kfree(f); |
267 | rtnl_unlock(); | ||
268 | } | ||
269 | |||
270 | static void route4_delete_filter(struct rcu_head *head) | ||
271 | { | ||
272 | struct route4_filter *f = container_of(head, struct route4_filter, rcu); | ||
273 | |||
274 | INIT_WORK(&f->work, route4_delete_filter_work); | ||
275 | tcf_queue_work(&f->work); | ||
263 | } | 276 | } |
264 | 277 | ||
265 | static void route4_destroy(struct tcf_proto *tp) | 278 | static void route4_destroy(struct tcf_proto *tp) |
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index b1f6ed48bc72..bdbc541787f8 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h | |||
@@ -97,7 +97,10 @@ struct rsvp_filter { | |||
97 | 97 | ||
98 | u32 handle; | 98 | u32 handle; |
99 | struct rsvp_session *sess; | 99 | struct rsvp_session *sess; |
100 | struct rcu_head rcu; | 100 | union { |
101 | struct work_struct work; | ||
102 | struct rcu_head rcu; | ||
103 | }; | ||
101 | }; | 104 | }; |
102 | 105 | ||
103 | static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) | 106 | static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) |
@@ -282,12 +285,22 @@ static int rsvp_init(struct tcf_proto *tp) | |||
282 | return -ENOBUFS; | 285 | return -ENOBUFS; |
283 | } | 286 | } |
284 | 287 | ||
285 | static void rsvp_delete_filter_rcu(struct rcu_head *head) | 288 | static void rsvp_delete_filter_work(struct work_struct *work) |
286 | { | 289 | { |
287 | struct rsvp_filter *f = container_of(head, struct rsvp_filter, rcu); | 290 | struct rsvp_filter *f = container_of(work, struct rsvp_filter, work); |
288 | 291 | ||
292 | rtnl_lock(); | ||
289 | tcf_exts_destroy(&f->exts); | 293 | tcf_exts_destroy(&f->exts); |
290 | kfree(f); | 294 | kfree(f); |
295 | rtnl_unlock(); | ||
296 | } | ||
297 | |||
298 | static void rsvp_delete_filter_rcu(struct rcu_head *head) | ||
299 | { | ||
300 | struct rsvp_filter *f = container_of(head, struct rsvp_filter, rcu); | ||
301 | |||
302 | INIT_WORK(&f->work, rsvp_delete_filter_work); | ||
303 | tcf_queue_work(&f->work); | ||
291 | } | 304 | } |
292 | 305 | ||
293 | static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) | 306 | static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) |
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 14a7e08b2fa9..beaa95e09c25 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c | |||
@@ -27,14 +27,20 @@ | |||
27 | struct tcindex_filter_result { | 27 | struct tcindex_filter_result { |
28 | struct tcf_exts exts; | 28 | struct tcf_exts exts; |
29 | struct tcf_result res; | 29 | struct tcf_result res; |
30 | struct rcu_head rcu; | 30 | union { |
31 | struct work_struct work; | ||
32 | struct rcu_head rcu; | ||
33 | }; | ||
31 | }; | 34 | }; |
32 | 35 | ||
33 | struct tcindex_filter { | 36 | struct tcindex_filter { |
34 | u16 key; | 37 | u16 key; |
35 | struct tcindex_filter_result result; | 38 | struct tcindex_filter_result result; |
36 | struct tcindex_filter __rcu *next; | 39 | struct tcindex_filter __rcu *next; |
37 | struct rcu_head rcu; | 40 | union { |
41 | struct work_struct work; | ||
42 | struct rcu_head rcu; | ||
43 | }; | ||
38 | }; | 44 | }; |
39 | 45 | ||
40 | 46 | ||
@@ -133,12 +139,34 @@ static int tcindex_init(struct tcf_proto *tp) | |||
133 | return 0; | 139 | return 0; |
134 | } | 140 | } |
135 | 141 | ||
142 | static void tcindex_destroy_rexts_work(struct work_struct *work) | ||
143 | { | ||
144 | struct tcindex_filter_result *r; | ||
145 | |||
146 | r = container_of(work, struct tcindex_filter_result, work); | ||
147 | rtnl_lock(); | ||
148 | tcf_exts_destroy(&r->exts); | ||
149 | rtnl_unlock(); | ||
150 | } | ||
151 | |||
136 | static void tcindex_destroy_rexts(struct rcu_head *head) | 152 | static void tcindex_destroy_rexts(struct rcu_head *head) |
137 | { | 153 | { |
138 | struct tcindex_filter_result *r; | 154 | struct tcindex_filter_result *r; |
139 | 155 | ||
140 | r = container_of(head, struct tcindex_filter_result, rcu); | 156 | r = container_of(head, struct tcindex_filter_result, rcu); |
141 | tcf_exts_destroy(&r->exts); | 157 | INIT_WORK(&r->work, tcindex_destroy_rexts_work); |
158 | tcf_queue_work(&r->work); | ||
159 | } | ||
160 | |||
161 | static void tcindex_destroy_fexts_work(struct work_struct *work) | ||
162 | { | ||
163 | struct tcindex_filter *f = container_of(work, struct tcindex_filter, | ||
164 | work); | ||
165 | |||
166 | rtnl_lock(); | ||
167 | tcf_exts_destroy(&f->result.exts); | ||
168 | kfree(f); | ||
169 | rtnl_unlock(); | ||
142 | } | 170 | } |
143 | 171 | ||
144 | static void tcindex_destroy_fexts(struct rcu_head *head) | 172 | static void tcindex_destroy_fexts(struct rcu_head *head) |
@@ -146,8 +174,8 @@ static void tcindex_destroy_fexts(struct rcu_head *head) | |||
146 | struct tcindex_filter *f = container_of(head, struct tcindex_filter, | 174 | struct tcindex_filter *f = container_of(head, struct tcindex_filter, |
147 | rcu); | 175 | rcu); |
148 | 176 | ||
149 | tcf_exts_destroy(&f->result.exts); | 177 | INIT_WORK(&f->work, tcindex_destroy_fexts_work); |
150 | kfree(f); | 178 | tcf_queue_work(&f->work); |
151 | } | 179 | } |
152 | 180 | ||
153 | static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last) | 181 | static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last) |
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 10b8d851fc6b..dadd1b344497 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
@@ -68,7 +68,10 @@ struct tc_u_knode { | |||
68 | u32 __percpu *pcpu_success; | 68 | u32 __percpu *pcpu_success; |
69 | #endif | 69 | #endif |
70 | struct tcf_proto *tp; | 70 | struct tcf_proto *tp; |
71 | struct rcu_head rcu; | 71 | union { |
72 | struct work_struct work; | ||
73 | struct rcu_head rcu; | ||
74 | }; | ||
72 | /* The 'sel' field MUST be the last field in structure to allow for | 75 | /* The 'sel' field MUST be the last field in structure to allow for |
73 | * tc_u32_keys allocated at end of structure. | 76 | * tc_u32_keys allocated at end of structure. |
74 | */ | 77 | */ |
@@ -418,11 +421,21 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, | |||
418 | * this the u32_delete_key_rcu variant does not free the percpu | 421 | * this the u32_delete_key_rcu variant does not free the percpu |
419 | * statistics. | 422 | * statistics. |
420 | */ | 423 | */ |
424 | static void u32_delete_key_work(struct work_struct *work) | ||
425 | { | ||
426 | struct tc_u_knode *key = container_of(work, struct tc_u_knode, work); | ||
427 | |||
428 | rtnl_lock(); | ||
429 | u32_destroy_key(key->tp, key, false); | ||
430 | rtnl_unlock(); | ||
431 | } | ||
432 | |||
421 | static void u32_delete_key_rcu(struct rcu_head *rcu) | 433 | static void u32_delete_key_rcu(struct rcu_head *rcu) |
422 | { | 434 | { |
423 | struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu); | 435 | struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu); |
424 | 436 | ||
425 | u32_destroy_key(key->tp, key, false); | 437 | INIT_WORK(&key->work, u32_delete_key_work); |
438 | tcf_queue_work(&key->work); | ||
426 | } | 439 | } |
427 | 440 | ||
428 | /* u32_delete_key_freepf_rcu is the rcu callback variant | 441 | /* u32_delete_key_freepf_rcu is the rcu callback variant |
@@ -432,11 +445,21 @@ static void u32_delete_key_rcu(struct rcu_head *rcu) | |||
432 | * for the variant that should be used with keys return from | 445 | * for the variant that should be used with keys return from |
433 | * u32_init_knode() | 446 | * u32_init_knode() |
434 | */ | 447 | */ |
448 | static void u32_delete_key_freepf_work(struct work_struct *work) | ||
449 | { | ||
450 | struct tc_u_knode *key = container_of(work, struct tc_u_knode, work); | ||
451 | |||
452 | rtnl_lock(); | ||
453 | u32_destroy_key(key->tp, key, true); | ||
454 | rtnl_unlock(); | ||
455 | } | ||
456 | |||
435 | static void u32_delete_key_freepf_rcu(struct rcu_head *rcu) | 457 | static void u32_delete_key_freepf_rcu(struct rcu_head *rcu) |
436 | { | 458 | { |
437 | struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu); | 459 | struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu); |
438 | 460 | ||
439 | u32_destroy_key(key->tp, key, true); | 461 | INIT_WORK(&key->work, u32_delete_key_freepf_work); |
462 | tcf_queue_work(&key->work); | ||
440 | } | 463 | } |
441 | 464 | ||
442 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) | 465 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) |
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index c6deb74e3d2f..22bc6fc48311 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -301,6 +301,8 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) | |||
301 | { | 301 | { |
302 | struct Qdisc *q; | 302 | struct Qdisc *q; |
303 | 303 | ||
304 | if (!handle) | ||
305 | return NULL; | ||
304 | q = qdisc_match_from_root(dev->qdisc, handle); | 306 | q = qdisc_match_from_root(dev->qdisc, handle); |
305 | if (q) | 307 | if (q) |
306 | goto out; | 308 | goto out; |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 34f10e75f3b9..621b5ca3fd1c 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -794,7 +794,7 @@ hit: | |||
794 | struct sctp_hash_cmp_arg { | 794 | struct sctp_hash_cmp_arg { |
795 | const union sctp_addr *paddr; | 795 | const union sctp_addr *paddr; |
796 | const struct net *net; | 796 | const struct net *net; |
797 | u16 lport; | 797 | __be16 lport; |
798 | }; | 798 | }; |
799 | 799 | ||
800 | static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg, | 800 | static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg, |
@@ -820,37 +820,37 @@ out: | |||
820 | return err; | 820 | return err; |
821 | } | 821 | } |
822 | 822 | ||
823 | static inline u32 sctp_hash_obj(const void *data, u32 len, u32 seed) | 823 | static inline __u32 sctp_hash_obj(const void *data, u32 len, u32 seed) |
824 | { | 824 | { |
825 | const struct sctp_transport *t = data; | 825 | const struct sctp_transport *t = data; |
826 | const union sctp_addr *paddr = &t->ipaddr; | 826 | const union sctp_addr *paddr = &t->ipaddr; |
827 | const struct net *net = sock_net(t->asoc->base.sk); | 827 | const struct net *net = sock_net(t->asoc->base.sk); |
828 | u16 lport = htons(t->asoc->base.bind_addr.port); | 828 | __be16 lport = htons(t->asoc->base.bind_addr.port); |
829 | u32 addr; | 829 | __u32 addr; |
830 | 830 | ||
831 | if (paddr->sa.sa_family == AF_INET6) | 831 | if (paddr->sa.sa_family == AF_INET6) |
832 | addr = jhash(&paddr->v6.sin6_addr, 16, seed); | 832 | addr = jhash(&paddr->v6.sin6_addr, 16, seed); |
833 | else | 833 | else |
834 | addr = paddr->v4.sin_addr.s_addr; | 834 | addr = (__force __u32)paddr->v4.sin_addr.s_addr; |
835 | 835 | ||
836 | return jhash_3words(addr, ((__u32)paddr->v4.sin_port) << 16 | | 836 | return jhash_3words(addr, ((__force __u32)paddr->v4.sin_port) << 16 | |
837 | (__force __u32)lport, net_hash_mix(net), seed); | 837 | (__force __u32)lport, net_hash_mix(net), seed); |
838 | } | 838 | } |
839 | 839 | ||
840 | static inline u32 sctp_hash_key(const void *data, u32 len, u32 seed) | 840 | static inline __u32 sctp_hash_key(const void *data, u32 len, u32 seed) |
841 | { | 841 | { |
842 | const struct sctp_hash_cmp_arg *x = data; | 842 | const struct sctp_hash_cmp_arg *x = data; |
843 | const union sctp_addr *paddr = x->paddr; | 843 | const union sctp_addr *paddr = x->paddr; |
844 | const struct net *net = x->net; | 844 | const struct net *net = x->net; |
845 | u16 lport = x->lport; | 845 | __be16 lport = x->lport; |
846 | u32 addr; | 846 | __u32 addr; |
847 | 847 | ||
848 | if (paddr->sa.sa_family == AF_INET6) | 848 | if (paddr->sa.sa_family == AF_INET6) |
849 | addr = jhash(&paddr->v6.sin6_addr, 16, seed); | 849 | addr = jhash(&paddr->v6.sin6_addr, 16, seed); |
850 | else | 850 | else |
851 | addr = paddr->v4.sin_addr.s_addr; | 851 | addr = (__force __u32)paddr->v4.sin_addr.s_addr; |
852 | 852 | ||
853 | return jhash_3words(addr, ((__u32)paddr->v4.sin_port) << 16 | | 853 | return jhash_3words(addr, ((__force __u32)paddr->v4.sin_port) << 16 | |
854 | (__force __u32)lport, net_hash_mix(net), seed); | 854 | (__force __u32)lport, net_hash_mix(net), seed); |
855 | } | 855 | } |
856 | 856 | ||
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 51c488769590..a6dfa86c0201 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -738,7 +738,7 @@ static int sctp_v6_skb_iif(const struct sk_buff *skb) | |||
738 | /* Was this packet marked by Explicit Congestion Notification? */ | 738 | /* Was this packet marked by Explicit Congestion Notification? */ |
739 | static int sctp_v6_is_ce(const struct sk_buff *skb) | 739 | static int sctp_v6_is_ce(const struct sk_buff *skb) |
740 | { | 740 | { |
741 | return *((__u32 *)(ipv6_hdr(skb))) & htonl(1 << 20); | 741 | return *((__u32 *)(ipv6_hdr(skb))) & (__force __u32)htonl(1 << 20); |
742 | } | 742 | } |
743 | 743 | ||
744 | /* Dump the v6 addr to the seq file. */ | 744 | /* Dump the v6 addr to the seq file. */ |
@@ -882,8 +882,10 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) | |||
882 | net = sock_net(&opt->inet.sk); | 882 | net = sock_net(&opt->inet.sk); |
883 | rcu_read_lock(); | 883 | rcu_read_lock(); |
884 | dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id); | 884 | dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id); |
885 | if (!dev || | 885 | if (!dev || !(opt->inet.freebind || |
886 | !ipv6_chk_addr(net, &addr->v6.sin6_addr, dev, 0)) { | 886 | net->ipv6.sysctl.ip_nonlocal_bind || |
887 | ipv6_chk_addr(net, &addr->v6.sin6_addr, | ||
888 | dev, 0))) { | ||
887 | rcu_read_unlock(); | 889 | rcu_read_unlock(); |
888 | return 0; | 890 | return 0; |
889 | } | 891 | } |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index ca8f196b6c6c..514465b03829 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -2854,7 +2854,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, | |||
2854 | addr_param_len = af->to_addr_param(addr, &addr_param); | 2854 | addr_param_len = af->to_addr_param(addr, &addr_param); |
2855 | param.param_hdr.type = flags; | 2855 | param.param_hdr.type = flags; |
2856 | param.param_hdr.length = htons(paramlen + addr_param_len); | 2856 | param.param_hdr.length = htons(paramlen + addr_param_len); |
2857 | param.crr_id = i; | 2857 | param.crr_id = htonl(i); |
2858 | 2858 | ||
2859 | sctp_addto_chunk(retval, paramlen, ¶m); | 2859 | sctp_addto_chunk(retval, paramlen, ¶m); |
2860 | sctp_addto_chunk(retval, addr_param_len, &addr_param); | 2860 | sctp_addto_chunk(retval, addr_param_len, &addr_param); |
@@ -2867,7 +2867,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, | |||
2867 | addr_param_len = af->to_addr_param(addr, &addr_param); | 2867 | addr_param_len = af->to_addr_param(addr, &addr_param); |
2868 | param.param_hdr.type = SCTP_PARAM_DEL_IP; | 2868 | param.param_hdr.type = SCTP_PARAM_DEL_IP; |
2869 | param.param_hdr.length = htons(paramlen + addr_param_len); | 2869 | param.param_hdr.length = htons(paramlen + addr_param_len); |
2870 | param.crr_id = i; | 2870 | param.crr_id = htonl(i); |
2871 | 2871 | ||
2872 | sctp_addto_chunk(retval, paramlen, ¶m); | 2872 | sctp_addto_chunk(retval, paramlen, ¶m); |
2873 | sctp_addto_chunk(retval, addr_param_len, &addr_param); | 2873 | sctp_addto_chunk(retval, addr_param_len, &addr_param); |
@@ -3591,7 +3591,7 @@ static struct sctp_chunk *sctp_make_reconf(const struct sctp_association *asoc, | |||
3591 | */ | 3591 | */ |
3592 | struct sctp_chunk *sctp_make_strreset_req( | 3592 | struct sctp_chunk *sctp_make_strreset_req( |
3593 | const struct sctp_association *asoc, | 3593 | const struct sctp_association *asoc, |
3594 | __u16 stream_num, __u16 *stream_list, | 3594 | __u16 stream_num, __be16 *stream_list, |
3595 | bool out, bool in) | 3595 | bool out, bool in) |
3596 | { | 3596 | { |
3597 | struct sctp_strreset_outreq outreq; | 3597 | struct sctp_strreset_outreq outreq; |
@@ -3788,7 +3788,8 @@ bool sctp_verify_reconf(const struct sctp_association *asoc, | |||
3788 | { | 3788 | { |
3789 | struct sctp_reconf_chunk *hdr; | 3789 | struct sctp_reconf_chunk *hdr; |
3790 | union sctp_params param; | 3790 | union sctp_params param; |
3791 | __u16 last = 0, cnt = 0; | 3791 | __be16 last = 0; |
3792 | __u16 cnt = 0; | ||
3792 | 3793 | ||
3793 | hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; | 3794 | hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; |
3794 | sctp_walk_params(param, hdr, params) { | 3795 | sctp_walk_params(param, hdr, params) { |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index e6a2974e020e..e2d9a4b49c9c 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -1607,12 +1607,12 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, | |||
1607 | break; | 1607 | break; |
1608 | 1608 | ||
1609 | case SCTP_CMD_INIT_FAILED: | 1609 | case SCTP_CMD_INIT_FAILED: |
1610 | sctp_cmd_init_failed(commands, asoc, cmd->obj.err); | 1610 | sctp_cmd_init_failed(commands, asoc, cmd->obj.u32); |
1611 | break; | 1611 | break; |
1612 | 1612 | ||
1613 | case SCTP_CMD_ASSOC_FAILED: | 1613 | case SCTP_CMD_ASSOC_FAILED: |
1614 | sctp_cmd_assoc_failed(commands, asoc, event_type, | 1614 | sctp_cmd_assoc_failed(commands, asoc, event_type, |
1615 | subtype, chunk, cmd->obj.err); | 1615 | subtype, chunk, cmd->obj.u32); |
1616 | break; | 1616 | break; |
1617 | 1617 | ||
1618 | case SCTP_CMD_INIT_COUNTER_INC: | 1618 | case SCTP_CMD_INIT_COUNTER_INC: |
@@ -1680,8 +1680,8 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, | |||
1680 | case SCTP_CMD_PROCESS_CTSN: | 1680 | case SCTP_CMD_PROCESS_CTSN: |
1681 | /* Dummy up a SACK for processing. */ | 1681 | /* Dummy up a SACK for processing. */ |
1682 | sackh.cum_tsn_ack = cmd->obj.be32; | 1682 | sackh.cum_tsn_ack = cmd->obj.be32; |
1683 | sackh.a_rwnd = asoc->peer.rwnd + | 1683 | sackh.a_rwnd = htonl(asoc->peer.rwnd + |
1684 | asoc->outqueue.outstanding_bytes; | 1684 | asoc->outqueue.outstanding_bytes); |
1685 | sackh.num_gap_ack_blocks = 0; | 1685 | sackh.num_gap_ack_blocks = 0; |
1686 | sackh.num_dup_tsns = 0; | 1686 | sackh.num_dup_tsns = 0; |
1687 | chunk->subh.sack_hdr = &sackh; | 1687 | chunk->subh.sack_hdr = &sackh; |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 17841ab30798..6f45d1713452 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -170,6 +170,36 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) | |||
170 | sk_mem_charge(sk, chunk->skb->truesize); | 170 | sk_mem_charge(sk, chunk->skb->truesize); |
171 | } | 171 | } |
172 | 172 | ||
173 | static void sctp_clear_owner_w(struct sctp_chunk *chunk) | ||
174 | { | ||
175 | skb_orphan(chunk->skb); | ||
176 | } | ||
177 | |||
178 | static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, | ||
179 | void (*cb)(struct sctp_chunk *)) | ||
180 | |||
181 | { | ||
182 | struct sctp_outq *q = &asoc->outqueue; | ||
183 | struct sctp_transport *t; | ||
184 | struct sctp_chunk *chunk; | ||
185 | |||
186 | list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) | ||
187 | list_for_each_entry(chunk, &t->transmitted, transmitted_list) | ||
188 | cb(chunk); | ||
189 | |||
190 | list_for_each_entry(chunk, &q->retransmit, list) | ||
191 | cb(chunk); | ||
192 | |||
193 | list_for_each_entry(chunk, &q->sacked, list) | ||
194 | cb(chunk); | ||
195 | |||
196 | list_for_each_entry(chunk, &q->abandoned, list) | ||
197 | cb(chunk); | ||
198 | |||
199 | list_for_each_entry(chunk, &q->out_chunk_list, list) | ||
200 | cb(chunk); | ||
201 | } | ||
202 | |||
173 | /* Verify that this is a valid address. */ | 203 | /* Verify that this is a valid address. */ |
174 | static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, | 204 | static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, |
175 | int len) | 205 | int len) |
@@ -8212,7 +8242,9 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
8212 | * paths won't try to lock it and then oldsk. | 8242 | * paths won't try to lock it and then oldsk. |
8213 | */ | 8243 | */ |
8214 | lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); | 8244 | lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); |
8245 | sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w); | ||
8215 | sctp_assoc_migrate(assoc, newsk); | 8246 | sctp_assoc_migrate(assoc, newsk); |
8247 | sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w); | ||
8216 | 8248 | ||
8217 | /* If the association on the newsk is already closed before accept() | 8249 | /* If the association on the newsk is already closed before accept() |
8218 | * is called, set RCV_SHUTDOWN flag. | 8250 | * is called, set RCV_SHUTDOWN flag. |
diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 63ea15503714..fa8371ff05c4 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c | |||
@@ -118,6 +118,7 @@ int sctp_send_reset_streams(struct sctp_association *asoc, | |||
118 | __u16 i, str_nums, *str_list; | 118 | __u16 i, str_nums, *str_list; |
119 | struct sctp_chunk *chunk; | 119 | struct sctp_chunk *chunk; |
120 | int retval = -EINVAL; | 120 | int retval = -EINVAL; |
121 | __be16 *nstr_list; | ||
121 | bool out, in; | 122 | bool out, in; |
122 | 123 | ||
123 | if (!asoc->peer.reconf_capable || | 124 | if (!asoc->peer.reconf_capable || |
@@ -148,13 +149,18 @@ int sctp_send_reset_streams(struct sctp_association *asoc, | |||
148 | if (str_list[i] >= stream->incnt) | 149 | if (str_list[i] >= stream->incnt) |
149 | goto out; | 150 | goto out; |
150 | 151 | ||
152 | nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL); | ||
153 | if (!nstr_list) { | ||
154 | retval = -ENOMEM; | ||
155 | goto out; | ||
156 | } | ||
157 | |||
151 | for (i = 0; i < str_nums; i++) | 158 | for (i = 0; i < str_nums; i++) |
152 | str_list[i] = htons(str_list[i]); | 159 | nstr_list[i] = htons(str_list[i]); |
153 | 160 | ||
154 | chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in); | 161 | chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in); |
155 | 162 | ||
156 | for (i = 0; i < str_nums; i++) | 163 | kfree(nstr_list); |
157 | str_list[i] = ntohs(str_list[i]); | ||
158 | 164 | ||
159 | if (!chunk) { | 165 | if (!chunk) { |
160 | retval = -ENOMEM; | 166 | retval = -ENOMEM; |
@@ -305,7 +311,7 @@ out: | |||
305 | } | 311 | } |
306 | 312 | ||
307 | static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param( | 313 | static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param( |
308 | struct sctp_association *asoc, __u32 resp_seq, | 314 | struct sctp_association *asoc, __be32 resp_seq, |
309 | __be16 type) | 315 | __be16 type) |
310 | { | 316 | { |
311 | struct sctp_chunk *chunk = asoc->strreset_chunk; | 317 | struct sctp_chunk *chunk = asoc->strreset_chunk; |
@@ -345,8 +351,9 @@ struct sctp_chunk *sctp_process_strreset_outreq( | |||
345 | { | 351 | { |
346 | struct sctp_strreset_outreq *outreq = param.v; | 352 | struct sctp_strreset_outreq *outreq = param.v; |
347 | struct sctp_stream *stream = &asoc->stream; | 353 | struct sctp_stream *stream = &asoc->stream; |
348 | __u16 i, nums, flags = 0, *str_p = NULL; | ||
349 | __u32 result = SCTP_STRRESET_DENIED; | 354 | __u32 result = SCTP_STRRESET_DENIED; |
355 | __u16 i, nums, flags = 0; | ||
356 | __be16 *str_p = NULL; | ||
350 | __u32 request_seq; | 357 | __u32 request_seq; |
351 | 358 | ||
352 | request_seq = ntohl(outreq->request_seq); | 359 | request_seq = ntohl(outreq->request_seq); |
@@ -439,8 +446,9 @@ struct sctp_chunk *sctp_process_strreset_inreq( | |||
439 | struct sctp_stream *stream = &asoc->stream; | 446 | struct sctp_stream *stream = &asoc->stream; |
440 | __u32 result = SCTP_STRRESET_DENIED; | 447 | __u32 result = SCTP_STRRESET_DENIED; |
441 | struct sctp_chunk *chunk = NULL; | 448 | struct sctp_chunk *chunk = NULL; |
442 | __u16 i, nums, *str_p; | ||
443 | __u32 request_seq; | 449 | __u32 request_seq; |
450 | __u16 i, nums; | ||
451 | __be16 *str_p; | ||
444 | 452 | ||
445 | request_seq = ntohl(inreq->request_seq); | 453 | request_seq = ntohl(inreq->request_seq); |
446 | if (TSN_lt(asoc->strreset_inseq, request_seq) || | 454 | if (TSN_lt(asoc->strreset_inseq, request_seq) || |
@@ -769,7 +777,7 @@ struct sctp_chunk *sctp_process_strreset_resp( | |||
769 | 777 | ||
770 | if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) { | 778 | if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) { |
771 | struct sctp_strreset_outreq *outreq; | 779 | struct sctp_strreset_outreq *outreq; |
772 | __u16 *str_p; | 780 | __be16 *str_p; |
773 | 781 | ||
774 | outreq = (struct sctp_strreset_outreq *)req; | 782 | outreq = (struct sctp_strreset_outreq *)req; |
775 | str_p = outreq->list_of_streams; | 783 | str_p = outreq->list_of_streams; |
@@ -794,7 +802,7 @@ struct sctp_chunk *sctp_process_strreset_resp( | |||
794 | nums, str_p, GFP_ATOMIC); | 802 | nums, str_p, GFP_ATOMIC); |
795 | } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) { | 803 | } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) { |
796 | struct sctp_strreset_inreq *inreq; | 804 | struct sctp_strreset_inreq *inreq; |
797 | __u16 *str_p; | 805 | __be16 *str_p; |
798 | 806 | ||
799 | /* if the result is performed, it's impossible for inreq */ | 807 | /* if the result is performed, it's impossible for inreq */ |
800 | if (result == SCTP_STRRESET_PERFORMED) | 808 | if (result == SCTP_STRRESET_PERFORMED) |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 67abc0194f30..5447228bf1a0 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -847,7 +847,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( | |||
847 | 847 | ||
848 | struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( | 848 | struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( |
849 | const struct sctp_association *asoc, __u16 flags, __u16 stream_num, | 849 | const struct sctp_association *asoc, __u16 flags, __u16 stream_num, |
850 | __u16 *stream_list, gfp_t gfp) | 850 | __be16 *stream_list, gfp_t gfp) |
851 | { | 851 | { |
852 | struct sctp_stream_reset_event *sreset; | 852 | struct sctp_stream_reset_event *sreset; |
853 | struct sctp_ulpevent *event; | 853 | struct sctp_ulpevent *event; |
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index d4ea46a5f233..c5fda15ba319 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c | |||
@@ -49,7 +49,7 @@ static void strp_abort_strp(struct strparser *strp, int err) | |||
49 | { | 49 | { |
50 | /* Unrecoverable error in receive */ | 50 | /* Unrecoverable error in receive */ |
51 | 51 | ||
52 | del_timer(&strp->msg_timer); | 52 | cancel_delayed_work(&strp->msg_timer_work); |
53 | 53 | ||
54 | if (strp->stopped) | 54 | if (strp->stopped) |
55 | return; | 55 | return; |
@@ -68,7 +68,7 @@ static void strp_abort_strp(struct strparser *strp, int err) | |||
68 | static void strp_start_timer(struct strparser *strp, long timeo) | 68 | static void strp_start_timer(struct strparser *strp, long timeo) |
69 | { | 69 | { |
70 | if (timeo) | 70 | if (timeo) |
71 | mod_timer(&strp->msg_timer, timeo); | 71 | mod_delayed_work(strp_wq, &strp->msg_timer_work, timeo); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* Lower lock held */ | 74 | /* Lower lock held */ |
@@ -319,7 +319,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
319 | eaten += (cand_len - extra); | 319 | eaten += (cand_len - extra); |
320 | 320 | ||
321 | /* Hurray, we have a new message! */ | 321 | /* Hurray, we have a new message! */ |
322 | del_timer(&strp->msg_timer); | 322 | cancel_delayed_work(&strp->msg_timer_work); |
323 | strp->skb_head = NULL; | 323 | strp->skb_head = NULL; |
324 | STRP_STATS_INCR(strp->stats.msgs); | 324 | STRP_STATS_INCR(strp->stats.msgs); |
325 | 325 | ||
@@ -450,9 +450,10 @@ static void strp_work(struct work_struct *w) | |||
450 | do_strp_work(container_of(w, struct strparser, work)); | 450 | do_strp_work(container_of(w, struct strparser, work)); |
451 | } | 451 | } |
452 | 452 | ||
453 | static void strp_msg_timeout(unsigned long arg) | 453 | static void strp_msg_timeout(struct work_struct *w) |
454 | { | 454 | { |
455 | struct strparser *strp = (struct strparser *)arg; | 455 | struct strparser *strp = container_of(w, struct strparser, |
456 | msg_timer_work.work); | ||
456 | 457 | ||
457 | /* Message assembly timed out */ | 458 | /* Message assembly timed out */ |
458 | STRP_STATS_INCR(strp->stats.msg_timeouts); | 459 | STRP_STATS_INCR(strp->stats.msg_timeouts); |
@@ -505,9 +506,7 @@ int strp_init(struct strparser *strp, struct sock *sk, | |||
505 | strp->cb.read_sock_done = cb->read_sock_done ? : default_read_sock_done; | 506 | strp->cb.read_sock_done = cb->read_sock_done ? : default_read_sock_done; |
506 | strp->cb.abort_parser = cb->abort_parser ? : strp_abort_strp; | 507 | strp->cb.abort_parser = cb->abort_parser ? : strp_abort_strp; |
507 | 508 | ||
508 | setup_timer(&strp->msg_timer, strp_msg_timeout, | 509 | INIT_DELAYED_WORK(&strp->msg_timer_work, strp_msg_timeout); |
509 | (unsigned long)strp); | ||
510 | |||
511 | INIT_WORK(&strp->work, strp_work); | 510 | INIT_WORK(&strp->work, strp_work); |
512 | 511 | ||
513 | return 0; | 512 | return 0; |
@@ -532,7 +531,7 @@ void strp_done(struct strparser *strp) | |||
532 | { | 531 | { |
533 | WARN_ON(!strp->stopped); | 532 | WARN_ON(!strp->stopped); |
534 | 533 | ||
535 | del_timer_sync(&strp->msg_timer); | 534 | cancel_delayed_work_sync(&strp->msg_timer_work); |
536 | cancel_work_sync(&strp->work); | 535 | cancel_work_sync(&strp->work); |
537 | 536 | ||
538 | if (strp->skb_head) { | 537 | if (strp->skb_head) { |
diff --git a/net/unix/diag.c b/net/unix/diag.c index 4d9679701a6d..384c84e83462 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c | |||
@@ -257,6 +257,8 @@ static int unix_diag_get_exact(struct sk_buff *in_skb, | |||
257 | err = -ENOENT; | 257 | err = -ENOENT; |
258 | if (sk == NULL) | 258 | if (sk == NULL) |
259 | goto out_nosk; | 259 | goto out_nosk; |
260 | if (!net_eq(sock_net(sk), net)) | ||
261 | goto out; | ||
260 | 262 | ||
261 | err = sock_diag_check_cookie(sk, req->udiag_cookie); | 263 | err = sock_diag_check_cookie(sk, req->udiag_cookie); |
262 | if (err) | 264 | if (err) |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0a49b88070d0..b6533ecbf5b1 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -522,11 +522,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, | |||
522 | return -EOPNOTSUPP; | 522 | return -EOPNOTSUPP; |
523 | 523 | ||
524 | if (wdev->current_bss) { | 524 | if (wdev->current_bss) { |
525 | if (!prev_bssid) | ||
526 | return -EALREADY; | ||
527 | if (prev_bssid && | ||
528 | !ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) | ||
529 | return -ENOTCONN; | ||
530 | cfg80211_unhold_bss(wdev->current_bss); | 525 | cfg80211_unhold_bss(wdev->current_bss); |
531 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | 526 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
532 | wdev->current_bss = NULL; | 527 | wdev->current_bss = NULL; |
@@ -1063,11 +1058,35 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
1063 | 1058 | ||
1064 | ASSERT_WDEV_LOCK(wdev); | 1059 | ASSERT_WDEV_LOCK(wdev); |
1065 | 1060 | ||
1066 | if (WARN_ON(wdev->connect_keys)) { | 1061 | /* |
1067 | kzfree(wdev->connect_keys); | 1062 | * If we have an ssid_len, we're trying to connect or are |
1068 | wdev->connect_keys = NULL; | 1063 | * already connected, so reject a new SSID unless it's the |
1064 | * same (which is the case for re-association.) | ||
1065 | */ | ||
1066 | if (wdev->ssid_len && | ||
1067 | (wdev->ssid_len != connect->ssid_len || | ||
1068 | memcmp(wdev->ssid, connect->ssid, wdev->ssid_len))) | ||
1069 | return -EALREADY; | ||
1070 | |||
1071 | /* | ||
1072 | * If connected, reject (re-)association unless prev_bssid | ||
1073 | * matches the current BSSID. | ||
1074 | */ | ||
1075 | if (wdev->current_bss) { | ||
1076 | if (!prev_bssid) | ||
1077 | return -EALREADY; | ||
1078 | if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) | ||
1079 | return -ENOTCONN; | ||
1069 | } | 1080 | } |
1070 | 1081 | ||
1082 | /* | ||
1083 | * Reject if we're in the process of connecting with WEP, | ||
1084 | * this case isn't very interesting and trying to handle | ||
1085 | * it would make the code much more complex. | ||
1086 | */ | ||
1087 | if (wdev->connect_keys) | ||
1088 | return -EINPROGRESS; | ||
1089 | |||
1071 | cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, | 1090 | cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, |
1072 | rdev->wiphy.ht_capa_mod_mask); | 1091 | rdev->wiphy.ht_capa_mod_mask); |
1073 | 1092 | ||
@@ -1118,7 +1137,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
1118 | 1137 | ||
1119 | if (err) { | 1138 | if (err) { |
1120 | wdev->connect_keys = NULL; | 1139 | wdev->connect_keys = NULL; |
1121 | wdev->ssid_len = 0; | 1140 | /* |
1141 | * This could be reassoc getting refused, don't clear | ||
1142 | * ssid_len in that case. | ||
1143 | */ | ||
1144 | if (!wdev->current_bss) | ||
1145 | wdev->ssid_len = 0; | ||
1122 | return err; | 1146 | return err; |
1123 | } | 1147 | } |
1124 | 1148 | ||
@@ -1145,6 +1169,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
1145 | else if (wdev->ssid_len) | 1169 | else if (wdev->ssid_len) |
1146 | err = rdev_disconnect(rdev, dev, reason); | 1170 | err = rdev_disconnect(rdev, dev, reason); |
1147 | 1171 | ||
1172 | /* | ||
1173 | * Clear ssid_len unless we actually were fully connected, | ||
1174 | * in which case cfg80211_disconnected() will take care of | ||
1175 | * this later. | ||
1176 | */ | ||
1177 | if (!wdev->current_bss) | ||
1178 | wdev->ssid_len = 0; | ||
1179 | |||
1148 | return err; | 1180 | return err; |
1149 | } | 1181 | } |
1150 | 1182 | ||
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f06253969972..2746b62a8944 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1573,6 +1573,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1573 | goto put_states; | 1573 | goto put_states; |
1574 | } | 1574 | } |
1575 | 1575 | ||
1576 | if (!dst_prev) | ||
1577 | dst0 = dst1; | ||
1578 | else | ||
1579 | /* Ref count is taken during xfrm_alloc_dst() | ||
1580 | * No need to do dst_clone() on dst1 | ||
1581 | */ | ||
1582 | dst_prev->child = dst1; | ||
1583 | |||
1576 | if (xfrm[i]->sel.family == AF_UNSPEC) { | 1584 | if (xfrm[i]->sel.family == AF_UNSPEC) { |
1577 | inner_mode = xfrm_ip2inner_mode(xfrm[i], | 1585 | inner_mode = xfrm_ip2inner_mode(xfrm[i], |
1578 | xfrm_af2proto(family)); | 1586 | xfrm_af2proto(family)); |
@@ -1584,14 +1592,6 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1584 | } else | 1592 | } else |
1585 | inner_mode = xfrm[i]->inner_mode; | 1593 | inner_mode = xfrm[i]->inner_mode; |
1586 | 1594 | ||
1587 | if (!dst_prev) | ||
1588 | dst0 = dst1; | ||
1589 | else | ||
1590 | /* Ref count is taken during xfrm_alloc_dst() | ||
1591 | * No need to do dst_clone() on dst1 | ||
1592 | */ | ||
1593 | dst_prev->child = dst1; | ||
1594 | |||
1595 | xdst->route = dst; | 1595 | xdst->route = dst; |
1596 | dst_copy_metrics(dst1, dst); | 1596 | dst_copy_metrics(dst1, dst); |
1597 | 1597 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b997f1395357..e44a0fed48dd 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1693,32 +1693,34 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1693 | 1693 | ||
1694 | static int xfrm_dump_policy_done(struct netlink_callback *cb) | 1694 | static int xfrm_dump_policy_done(struct netlink_callback *cb) |
1695 | { | 1695 | { |
1696 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; | 1696 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; |
1697 | struct net *net = sock_net(cb->skb->sk); | 1697 | struct net *net = sock_net(cb->skb->sk); |
1698 | 1698 | ||
1699 | xfrm_policy_walk_done(walk, net); | 1699 | xfrm_policy_walk_done(walk, net); |
1700 | return 0; | 1700 | return 0; |
1701 | } | 1701 | } |
1702 | 1702 | ||
1703 | static int xfrm_dump_policy_start(struct netlink_callback *cb) | ||
1704 | { | ||
1705 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; | ||
1706 | |||
1707 | BUILD_BUG_ON(sizeof(*walk) > sizeof(cb->args)); | ||
1708 | |||
1709 | xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); | ||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1703 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | 1713 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) |
1704 | { | 1714 | { |
1705 | struct net *net = sock_net(skb->sk); | 1715 | struct net *net = sock_net(skb->sk); |
1706 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; | 1716 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; |
1707 | struct xfrm_dump_info info; | 1717 | struct xfrm_dump_info info; |
1708 | 1718 | ||
1709 | BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > | ||
1710 | sizeof(cb->args) - sizeof(cb->args[0])); | ||
1711 | |||
1712 | info.in_skb = cb->skb; | 1719 | info.in_skb = cb->skb; |
1713 | info.out_skb = skb; | 1720 | info.out_skb = skb; |
1714 | info.nlmsg_seq = cb->nlh->nlmsg_seq; | 1721 | info.nlmsg_seq = cb->nlh->nlmsg_seq; |
1715 | info.nlmsg_flags = NLM_F_MULTI; | 1722 | info.nlmsg_flags = NLM_F_MULTI; |
1716 | 1723 | ||
1717 | if (!cb->args[0]) { | ||
1718 | cb->args[0] = 1; | ||
1719 | xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); | ||
1720 | } | ||
1721 | |||
1722 | (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); | 1724 | (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); |
1723 | 1725 | ||
1724 | return skb->len; | 1726 | return skb->len; |
@@ -2474,6 +2476,7 @@ static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { | |||
2474 | 2476 | ||
2475 | static const struct xfrm_link { | 2477 | static const struct xfrm_link { |
2476 | int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); | 2478 | int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); |
2479 | int (*start)(struct netlink_callback *); | ||
2477 | int (*dump)(struct sk_buff *, struct netlink_callback *); | 2480 | int (*dump)(struct sk_buff *, struct netlink_callback *); |
2478 | int (*done)(struct netlink_callback *); | 2481 | int (*done)(struct netlink_callback *); |
2479 | const struct nla_policy *nla_pol; | 2482 | const struct nla_policy *nla_pol; |
@@ -2487,6 +2490,7 @@ static const struct xfrm_link { | |||
2487 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 2490 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
2488 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, | 2491 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, |
2489 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, | 2492 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, |
2493 | .start = xfrm_dump_policy_start, | ||
2490 | .dump = xfrm_dump_policy, | 2494 | .dump = xfrm_dump_policy, |
2491 | .done = xfrm_dump_policy_done }, | 2495 | .done = xfrm_dump_policy_done }, |
2492 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, | 2496 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, |
@@ -2539,6 +2543,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2539 | 2543 | ||
2540 | { | 2544 | { |
2541 | struct netlink_dump_control c = { | 2545 | struct netlink_dump_control c = { |
2546 | .start = link->start, | ||
2542 | .dump = link->dump, | 2547 | .dump = link->dump, |
2543 | .done = link->done, | 2548 | .done = link->done, |
2544 | }; | 2549 | }; |
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 24b35a1fd4d6..c174971afbe6 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -787,8 +787,8 @@ struct xdp_md { | |||
787 | }; | 787 | }; |
788 | 788 | ||
789 | enum sk_action { | 789 | enum sk_action { |
790 | SK_ABORTED = 0, | 790 | SK_DROP = 0, |
791 | SK_DROP, | 791 | SK_PASS, |
792 | SK_REDIRECT, | 792 | SK_REDIRECT, |
793 | }; | 793 | }; |
794 | 794 | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json index c727b96a59b0..5fa02d86b35f 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json | |||
@@ -17,5 +17,26 @@ | |||
17 | "teardown": [ | 17 | "teardown": [ |
18 | "$TC qdisc del dev $DEV1 ingress" | 18 | "$TC qdisc del dev $DEV1 ingress" |
19 | ] | 19 | ] |
20 | }, | ||
21 | { | ||
22 | "id": "d052", | ||
23 | "name": "Add 1M filters with the same action", | ||
24 | "category": [ | ||
25 | "filter", | ||
26 | "flower" | ||
27 | ], | ||
28 | "setup": [ | ||
29 | "$TC qdisc add dev $DEV2 ingress", | ||
30 | "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000" | ||
31 | ], | ||
32 | "cmdUnderTest": "$TC -b $BATCH_FILE", | ||
33 | "expExitCode": "0", | ||
34 | "verifyCmd": "$TC actions list action gact", | ||
35 | "matchPattern": "action order 0: gact action drop.*index 1 ref 1000000 bind 1000000", | ||
36 | "matchCount": "1", | ||
37 | "teardown": [ | ||
38 | "$TC qdisc del dev $DEV2 ingress", | ||
39 | "/bin/rm $BATCH_FILE" | ||
40 | ] | ||
20 | } | 41 | } |
21 | ] \ No newline at end of file | 42 | ] |
diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index cd61b7844c0d..5f11f5d7456e 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py | |||
@@ -88,7 +88,7 @@ def prepare_env(cmdlist): | |||
88 | exit(1) | 88 | exit(1) |
89 | 89 | ||
90 | 90 | ||
91 | def test_runner(filtered_tests): | 91 | def test_runner(filtered_tests, args): |
92 | """ | 92 | """ |
93 | Driver function for the unit tests. | 93 | Driver function for the unit tests. |
94 | 94 | ||
@@ -105,6 +105,8 @@ def test_runner(filtered_tests): | |||
105 | for tidx in testlist: | 105 | for tidx in testlist: |
106 | result = True | 106 | result = True |
107 | tresult = "" | 107 | tresult = "" |
108 | if "flower" in tidx["category"] and args.device == None: | ||
109 | continue | ||
108 | print("Test " + tidx["id"] + ": " + tidx["name"]) | 110 | print("Test " + tidx["id"] + ": " + tidx["name"]) |
109 | prepare_env(tidx["setup"]) | 111 | prepare_env(tidx["setup"]) |
110 | (p, procout) = exec_cmd(tidx["cmdUnderTest"]) | 112 | (p, procout) = exec_cmd(tidx["cmdUnderTest"]) |
@@ -152,6 +154,10 @@ def ns_create(): | |||
152 | exec_cmd(cmd, False) | 154 | exec_cmd(cmd, False) |
153 | cmd = 'ip -s $NS link set $DEV1 up' | 155 | cmd = 'ip -s $NS link set $DEV1 up' |
154 | exec_cmd(cmd, False) | 156 | exec_cmd(cmd, False) |
157 | cmd = 'ip link set $DEV2 netns $NS' | ||
158 | exec_cmd(cmd, False) | ||
159 | cmd = 'ip -s $NS link set $DEV2 up' | ||
160 | exec_cmd(cmd, False) | ||
155 | 161 | ||
156 | 162 | ||
157 | def ns_destroy(): | 163 | def ns_destroy(): |
@@ -211,7 +217,8 @@ def set_args(parser): | |||
211 | help='Execute the single test case with specified ID') | 217 | help='Execute the single test case with specified ID') |
212 | parser.add_argument('-i', '--id', action='store_true', dest='gen_id', | 218 | parser.add_argument('-i', '--id', action='store_true', dest='gen_id', |
213 | help='Generate ID numbers for new test cases') | 219 | help='Generate ID numbers for new test cases') |
214 | return parser | 220 | parser.add_argument('-d', '--device', |
221 | help='Execute the test case in flower category') | ||
215 | return parser | 222 | return parser |
216 | 223 | ||
217 | 224 | ||
@@ -225,6 +232,8 @@ def check_default_settings(args): | |||
225 | 232 | ||
226 | if args.path != None: | 233 | if args.path != None: |
227 | NAMES['TC'] = args.path | 234 | NAMES['TC'] = args.path |
235 | if args.device != None: | ||
236 | NAMES['DEV2'] = args.device | ||
228 | if not os.path.isfile(NAMES['TC']): | 237 | if not os.path.isfile(NAMES['TC']): |
229 | print("The specified tc path " + NAMES['TC'] + " does not exist.") | 238 | print("The specified tc path " + NAMES['TC'] + " does not exist.") |
230 | exit(1) | 239 | exit(1) |
@@ -381,14 +390,17 @@ def set_operation_mode(args): | |||
381 | if (len(alltests) == 0): | 390 | if (len(alltests) == 0): |
382 | print("Cannot find a test case with ID matching " + target_id) | 391 | print("Cannot find a test case with ID matching " + target_id) |
383 | exit(1) | 392 | exit(1) |
384 | catresults = test_runner(alltests) | 393 | catresults = test_runner(alltests, args) |
385 | print("All test results: " + "\n\n" + catresults) | 394 | print("All test results: " + "\n\n" + catresults) |
386 | elif (len(target_category) > 0): | 395 | elif (len(target_category) > 0): |
396 | if (target_category == "flower") and args.device == None: | ||
397 | print("Please specify a NIC device (-d) to run category flower") | ||
398 | exit(1) | ||
387 | if (target_category not in ucat): | 399 | if (target_category not in ucat): |
388 | print("Specified category is not present in this file.") | 400 | print("Specified category is not present in this file.") |
389 | exit(1) | 401 | exit(1) |
390 | else: | 402 | else: |
391 | catresults = test_runner(testcases[target_category]) | 403 | catresults = test_runner(testcases[target_category], args) |
392 | print("Category " + target_category + "\n\n" + catresults) | 404 | print("Category " + target_category + "\n\n" + catresults) |
393 | 405 | ||
394 | ns_destroy() | 406 | ns_destroy() |
diff --git a/tools/testing/selftests/tc-testing/tdc_batch.py b/tools/testing/selftests/tc-testing/tdc_batch.py new file mode 100755 index 000000000000..707c6bfef689 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tdc_batch.py | |||
@@ -0,0 +1,62 @@ | |||
1 | #!/usr/bin/python3 | ||
2 | |||
3 | """ | ||
4 | tdc_batch.py - a script to generate TC batch file | ||
5 | |||
6 | Copyright (C) 2017 Chris Mi <chrism@mellanox.com> | ||
7 | """ | ||
8 | |||
9 | import argparse | ||
10 | |||
11 | parser = argparse.ArgumentParser(description='TC batch file generator') | ||
12 | parser.add_argument("device", help="device name") | ||
13 | parser.add_argument("file", help="batch file name") | ||
14 | parser.add_argument("-n", "--number", type=int, | ||
15 | help="how many lines in batch file") | ||
16 | parser.add_argument("-o", "--skip_sw", | ||
17 | help="skip_sw (offload), by default skip_hw", | ||
18 | action="store_true") | ||
19 | parser.add_argument("-s", "--share_action", | ||
20 | help="all filters share the same action", | ||
21 | action="store_true") | ||
22 | parser.add_argument("-p", "--prio", | ||
23 | help="all filters have different prio", | ||
24 | action="store_true") | ||
25 | args = parser.parse_args() | ||
26 | |||
27 | device = args.device | ||
28 | file = open(args.file, 'w') | ||
29 | |||
30 | number = 1 | ||
31 | if args.number: | ||
32 | number = args.number | ||
33 | |||
34 | skip = "skip_hw" | ||
35 | if args.skip_sw: | ||
36 | skip = "skip_sw" | ||
37 | |||
38 | share_action = "" | ||
39 | if args.share_action: | ||
40 | share_action = "index 1" | ||
41 | |||
42 | prio = "prio 1" | ||
43 | if args.prio: | ||
44 | prio = "" | ||
45 | if number > 0x4000: | ||
46 | number = 0x4000 | ||
47 | |||
48 | index = 0 | ||
49 | for i in range(0x100): | ||
50 | for j in range(0x100): | ||
51 | for k in range(0x100): | ||
52 | mac = ("%02x:%02x:%02x" % (i, j, k)) | ||
53 | src_mac = "e4:11:00:" + mac | ||
54 | dst_mac = "e4:12:00:" + mac | ||
55 | cmd = ("filter add dev %s %s protocol ip parent ffff: flower %s " | ||
56 | "src_mac %s dst_mac %s action drop %s" % | ||
57 | (device, prio, skip, src_mac, dst_mac, share_action)) | ||
58 | file.write("%s\n" % cmd) | ||
59 | index += 1 | ||
60 | if index >= number: | ||
61 | file.close() | ||
62 | exit(0) | ||
diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py index 01087375a7c3..b6352515c1b5 100644 --- a/tools/testing/selftests/tc-testing/tdc_config.py +++ b/tools/testing/selftests/tc-testing/tdc_config.py | |||
@@ -12,6 +12,8 @@ NAMES = { | |||
12 | # Name of veth devices to be created for the namespace | 12 | # Name of veth devices to be created for the namespace |
13 | 'DEV0': 'v0p0', | 13 | 'DEV0': 'v0p0', |
14 | 'DEV1': 'v0p1', | 14 | 'DEV1': 'v0p1', |
15 | 'DEV2': '', | ||
16 | 'BATCH_FILE': './batch.txt', | ||
15 | # Name of the namespace to use | 17 | # Name of the namespace to use |
16 | 'NS': 'tcut' | 18 | 'NS': 'tcut' |
17 | } | 19 | } |