diff options
-rw-r--r-- | include/linux/netdevice.h | 68 | ||||
-rw-r--r-- | net/core/dev.c | 55 |
2 files changed, 122 insertions, 1 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 68a4627b74f5..371fa8839d51 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -646,6 +646,14 @@ struct xps_dev_maps { | |||
646 | (nr_cpu_ids * sizeof(struct xps_map *))) | 646 | (nr_cpu_ids * sizeof(struct xps_map *))) |
647 | #endif /* CONFIG_XPS */ | 647 | #endif /* CONFIG_XPS */ |
648 | 648 | ||
649 | #define TC_MAX_QUEUE 16 | ||
650 | #define TC_BITMASK 15 | ||
651 | /* HW offloaded queuing disciplines txq count and offset maps */ | ||
652 | struct netdev_tc_txq { | ||
653 | u16 count; | ||
654 | u16 offset; | ||
655 | }; | ||
656 | |||
649 | /* | 657 | /* |
650 | * This structure defines the management hooks for network devices. | 658 | * This structure defines the management hooks for network devices. |
651 | * The following hooks can be defined; unless noted otherwise, they are | 659 | * The following hooks can be defined; unless noted otherwise, they are |
@@ -756,6 +764,11 @@ struct xps_dev_maps { | |||
756 | * int (*ndo_set_vf_port)(struct net_device *dev, int vf, | 764 | * int (*ndo_set_vf_port)(struct net_device *dev, int vf, |
757 | * struct nlattr *port[]); | 765 | * struct nlattr *port[]); |
758 | * int (*ndo_get_vf_port)(struct net_device *dev, int vf, struct sk_buff *skb); | 766 | * int (*ndo_get_vf_port)(struct net_device *dev, int vf, struct sk_buff *skb); |
767 | * int (*ndo_setup_tc)(struct net_device *dev, u8 tc) | ||
768 | * Called to setup 'tc' number of traffic classes in the net device. This | ||
769 | * is always called from the stack with the rtnl lock held and netif tx | ||
770 | * queues stopped. This allows the netdevice to perform queue management | ||
771 | * safely. | ||
759 | */ | 772 | */ |
760 | #define HAVE_NET_DEVICE_OPS | 773 | #define HAVE_NET_DEVICE_OPS |
761 | struct net_device_ops { | 774 | struct net_device_ops { |
@@ -814,6 +827,7 @@ struct net_device_ops { | |||
814 | struct nlattr *port[]); | 827 | struct nlattr *port[]); |
815 | int (*ndo_get_vf_port)(struct net_device *dev, | 828 | int (*ndo_get_vf_port)(struct net_device *dev, |
816 | int vf, struct sk_buff *skb); | 829 | int vf, struct sk_buff *skb); |
830 | int (*ndo_setup_tc)(struct net_device *dev, u8 tc); | ||
817 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 831 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
818 | int (*ndo_fcoe_enable)(struct net_device *dev); | 832 | int (*ndo_fcoe_enable)(struct net_device *dev); |
819 | int (*ndo_fcoe_disable)(struct net_device *dev); | 833 | int (*ndo_fcoe_disable)(struct net_device *dev); |
@@ -1146,6 +1160,9 @@ struct net_device { | |||
1146 | /* Data Center Bridging netlink ops */ | 1160 | /* Data Center Bridging netlink ops */ |
1147 | const struct dcbnl_rtnl_ops *dcbnl_ops; | 1161 | const struct dcbnl_rtnl_ops *dcbnl_ops; |
1148 | #endif | 1162 | #endif |
1163 | u8 num_tc; | ||
1164 | struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE]; | ||
1165 | u8 prio_tc_map[TC_BITMASK + 1]; | ||
1149 | 1166 | ||
1150 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 1167 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
1151 | /* max exchange id for FCoE LRO by ddp */ | 1168 | /* max exchange id for FCoE LRO by ddp */ |
@@ -1165,6 +1182,57 @@ struct net_device { | |||
1165 | #define NETDEV_ALIGN 32 | 1182 | #define NETDEV_ALIGN 32 |
1166 | 1183 | ||
1167 | static inline | 1184 | static inline |
1185 | int netdev_get_prio_tc_map(const struct net_device *dev, u32 prio) | ||
1186 | { | ||
1187 | return dev->prio_tc_map[prio & TC_BITMASK]; | ||
1188 | } | ||
1189 | |||
1190 | static inline | ||
1191 | int netdev_set_prio_tc_map(struct net_device *dev, u8 prio, u8 tc) | ||
1192 | { | ||
1193 | if (tc >= dev->num_tc) | ||
1194 | return -EINVAL; | ||
1195 | |||
1196 | dev->prio_tc_map[prio & TC_BITMASK] = tc & TC_BITMASK; | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static inline | ||
1201 | void netdev_reset_tc(struct net_device *dev) | ||
1202 | { | ||
1203 | dev->num_tc = 0; | ||
1204 | memset(dev->tc_to_txq, 0, sizeof(dev->tc_to_txq)); | ||
1205 | memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map)); | ||
1206 | } | ||
1207 | |||
1208 | static inline | ||
1209 | int netdev_set_tc_queue(struct net_device *dev, u8 tc, u16 count, u16 offset) | ||
1210 | { | ||
1211 | if (tc >= dev->num_tc) | ||
1212 | return -EINVAL; | ||
1213 | |||
1214 | dev->tc_to_txq[tc].count = count; | ||
1215 | dev->tc_to_txq[tc].offset = offset; | ||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | static inline | ||
1220 | int netdev_set_num_tc(struct net_device *dev, u8 num_tc) | ||
1221 | { | ||
1222 | if (num_tc > TC_MAX_QUEUE) | ||
1223 | return -EINVAL; | ||
1224 | |||
1225 | dev->num_tc = num_tc; | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static inline | ||
1230 | int netdev_get_num_tc(struct net_device *dev) | ||
1231 | { | ||
1232 | return dev->num_tc; | ||
1233 | } | ||
1234 | |||
1235 | static inline | ||
1168 | struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, | 1236 | struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, |
1169 | unsigned int index) | 1237 | unsigned int index) |
1170 | { | 1238 | { |
diff --git a/net/core/dev.c b/net/core/dev.c index 2b85d4ae981f..8b1d886ed23b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1593,6 +1593,48 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) | |||
1593 | rcu_read_unlock(); | 1593 | rcu_read_unlock(); |
1594 | } | 1594 | } |
1595 | 1595 | ||
1596 | /* netif_setup_tc - Handle tc mappings on real_num_tx_queues change | ||
1597 | * @dev: Network device | ||
1598 | * @txq: number of queues available | ||
1599 | * | ||
1600 | * If real_num_tx_queues is changed the tc mappings may no longer be | ||
1601 | * valid. To resolve this verify the tc mapping remains valid and if | ||
1602 | * not NULL the mapping. With no priorities mapping to this | ||
1603 | * offset/count pair it will no longer be used. In the worst case TC0 | ||
1604 | * is invalid nothing can be done so disable priority mappings. If is | ||
1605 | * expected that drivers will fix this mapping if they can before | ||
1606 | * calling netif_set_real_num_tx_queues. | ||
1607 | */ | ||
1608 | void netif_setup_tc(struct net_device *dev, unsigned int txq) | ||
1609 | { | ||
1610 | int i; | ||
1611 | struct netdev_tc_txq *tc = &dev->tc_to_txq[0]; | ||
1612 | |||
1613 | /* If TC0 is invalidated disable TC mapping */ | ||
1614 | if (tc->offset + tc->count > txq) { | ||
1615 | pr_warning("Number of in use tx queues changed " | ||
1616 | "invalidating tc mappings. Priority " | ||
1617 | "traffic classification disabled!\n"); | ||
1618 | dev->num_tc = 0; | ||
1619 | return; | ||
1620 | } | ||
1621 | |||
1622 | /* Invalidated prio to tc mappings set to TC0 */ | ||
1623 | for (i = 1; i < TC_BITMASK + 1; i++) { | ||
1624 | int q = netdev_get_prio_tc_map(dev, i); | ||
1625 | |||
1626 | tc = &dev->tc_to_txq[q]; | ||
1627 | if (tc->offset + tc->count > txq) { | ||
1628 | pr_warning("Number of in use tx queues " | ||
1629 | "changed. Priority %i to tc " | ||
1630 | "mapping %i is no longer valid " | ||
1631 | "setting map to 0\n", | ||
1632 | i, q); | ||
1633 | netdev_set_prio_tc_map(dev, i, 0); | ||
1634 | } | ||
1635 | } | ||
1636 | } | ||
1637 | |||
1596 | /* | 1638 | /* |
1597 | * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues | 1639 | * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues |
1598 | * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. | 1640 | * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. |
@@ -1612,6 +1654,9 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) | |||
1612 | if (rc) | 1654 | if (rc) |
1613 | return rc; | 1655 | return rc; |
1614 | 1656 | ||
1657 | if (dev->num_tc) | ||
1658 | netif_setup_tc(dev, txq); | ||
1659 | |||
1615 | if (txq < dev->real_num_tx_queues) | 1660 | if (txq < dev->real_num_tx_queues) |
1616 | qdisc_reset_all_tx_gt(dev, txq); | 1661 | qdisc_reset_all_tx_gt(dev, txq); |
1617 | } | 1662 | } |
@@ -2161,6 +2206,8 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | |||
2161 | unsigned int num_tx_queues) | 2206 | unsigned int num_tx_queues) |
2162 | { | 2207 | { |
2163 | u32 hash; | 2208 | u32 hash; |
2209 | u16 qoffset = 0; | ||
2210 | u16 qcount = num_tx_queues; | ||
2164 | 2211 | ||
2165 | if (skb_rx_queue_recorded(skb)) { | 2212 | if (skb_rx_queue_recorded(skb)) { |
2166 | hash = skb_get_rx_queue(skb); | 2213 | hash = skb_get_rx_queue(skb); |
@@ -2169,13 +2216,19 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | |||
2169 | return hash; | 2216 | return hash; |
2170 | } | 2217 | } |
2171 | 2218 | ||
2219 | if (dev->num_tc) { | ||
2220 | u8 tc = netdev_get_prio_tc_map(dev, skb->priority); | ||
2221 | qoffset = dev->tc_to_txq[tc].offset; | ||
2222 | qcount = dev->tc_to_txq[tc].count; | ||
2223 | } | ||
2224 | |||
2172 | if (skb->sk && skb->sk->sk_hash) | 2225 | if (skb->sk && skb->sk->sk_hash) |
2173 | hash = skb->sk->sk_hash; | 2226 | hash = skb->sk->sk_hash; |
2174 | else | 2227 | else |
2175 | hash = (__force u16) skb->protocol ^ skb->rxhash; | 2228 | hash = (__force u16) skb->protocol ^ skb->rxhash; |
2176 | hash = jhash_1word(hash, hashrnd); | 2229 | hash = jhash_1word(hash, hashrnd); |
2177 | 2230 | ||
2178 | return (u16) (((u64) hash * num_tx_queues) >> 32); | 2231 | return (u16) (((u64) hash * qcount) >> 32) + qoffset; |
2179 | } | 2232 | } |
2180 | EXPORT_SYMBOL(__skb_tx_hash); | 2233 | EXPORT_SYMBOL(__skb_tx_hash); |
2181 | 2234 | ||