aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q/vlan_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r--net/8021q/vlan_dev.c161
1 files changed, 104 insertions, 57 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 52984267781..3d59c9bf8fe 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -142,6 +142,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
142{ 142{
143 struct vlan_hdr *vhdr; 143 struct vlan_hdr *vhdr;
144 struct vlan_rx_stats *rx_stats; 144 struct vlan_rx_stats *rx_stats;
145 struct net_device *vlan_dev;
145 u16 vlan_id; 146 u16 vlan_id;
146 u16 vlan_tci; 147 u16 vlan_tci;
147 148
@@ -157,53 +158,71 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
157 vlan_id = vlan_tci & VLAN_VID_MASK; 158 vlan_id = vlan_tci & VLAN_VID_MASK;
158 159
159 rcu_read_lock(); 160 rcu_read_lock();
160 skb->dev = __find_vlan_dev(dev, vlan_id); 161 vlan_dev = __find_vlan_dev(dev, vlan_id);
161 if (!skb->dev) {
162 pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
163 __func__, vlan_id, dev->name);
164 goto err_unlock;
165 }
166
167 rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
168 smp_processor_id());
169 rx_stats->rx_packets++;
170 rx_stats->rx_bytes += skb->len;
171
172 skb_pull_rcsum(skb, VLAN_HLEN);
173
174 skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
175
176 pr_debug("%s: priority: %u for TCI: %hu\n",
177 __func__, skb->priority, vlan_tci);
178
179 switch (skb->pkt_type) {
180 case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
181 /* stats->broadcast ++; // no such counter :-( */
182 break;
183 162
184 case PACKET_MULTICAST: 163 /* If the VLAN device is defined, we use it.
185 rx_stats->multicast++; 164 * If not, and the VID is 0, it is a 802.1p packet (not
186 break; 165 * really a VLAN), so we will just netif_rx it later to the
166 * original interface, but with the skb->proto set to the
167 * wrapped proto: we do nothing here.
168 */
187 169
188 case PACKET_OTHERHOST: 170 if (!vlan_dev) {
189 /* Our lower layer thinks this is not local, let's make sure. 171 if (vlan_id) {
190 * This allows the VLAN to have a different MAC than the 172 pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
191 * underlying device, and still route correctly. 173 __func__, vlan_id, dev->name);
192 */ 174 goto err_unlock;
193 if (!compare_ether_addr(eth_hdr(skb)->h_dest, 175 }
194 skb->dev->dev_addr)) 176 rx_stats = NULL;
195 skb->pkt_type = PACKET_HOST; 177 } else {
196 break; 178 skb->dev = vlan_dev;
197 default: 179
198 break; 180 rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
181 smp_processor_id());
182 u64_stats_update_begin(&rx_stats->syncp);
183 rx_stats->rx_packets++;
184 rx_stats->rx_bytes += skb->len;
185
186 skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
187
188 pr_debug("%s: priority: %u for TCI: %hu\n",
189 __func__, skb->priority, vlan_tci);
190
191 switch (skb->pkt_type) {
192 case PACKET_BROADCAST:
193 /* Yeah, stats collect these together.. */
194 /* stats->broadcast ++; // no such counter :-( */
195 break;
196
197 case PACKET_MULTICAST:
198 rx_stats->rx_multicast++;
199 break;
200
201 case PACKET_OTHERHOST:
202 /* Our lower layer thinks this is not local, let's make
203 * sure.
204 * This allows the VLAN to have a different MAC than the
205 * underlying device, and still route correctly.
206 */
207 if (!compare_ether_addr(eth_hdr(skb)->h_dest,
208 skb->dev->dev_addr))
209 skb->pkt_type = PACKET_HOST;
210 break;
211 default:
212 break;
213 }
214 u64_stats_update_end(&rx_stats->syncp);
199 } 215 }
200 216
217 skb_pull_rcsum(skb, VLAN_HLEN);
201 vlan_set_encap_proto(skb, vhdr); 218 vlan_set_encap_proto(skb, vhdr);
202 219
203 skb = vlan_check_reorder_header(skb); 220 if (vlan_dev) {
204 if (!skb) { 221 skb = vlan_check_reorder_header(skb);
205 rx_stats->rx_errors++; 222 if (!skb) {
206 goto err_unlock; 223 rx_stats->rx_errors++;
224 goto err_unlock;
225 }
207 } 226 }
208 227
209 netif_rx(skb); 228 netif_rx(skb);
@@ -801,37 +820,65 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev)
801 return dev_ethtool_get_flags(vlan->real_dev); 820 return dev_ethtool_get_flags(vlan->real_dev);
802} 821}
803 822
804static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev) 823static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
805{ 824{
806 struct net_device_stats *stats = &dev->stats;
807
808 dev_txq_stats_fold(dev, stats); 825 dev_txq_stats_fold(dev, stats);
809 826
810 if (vlan_dev_info(dev)->vlan_rx_stats) { 827 if (vlan_dev_info(dev)->vlan_rx_stats) {
811 struct vlan_rx_stats *p, rx = {0}; 828 struct vlan_rx_stats *p, accum = {0};
812 int i; 829 int i;
813 830
814 for_each_possible_cpu(i) { 831 for_each_possible_cpu(i) {
832 u64 rxpackets, rxbytes, rxmulticast;
833 unsigned int start;
834
815 p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i); 835 p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i);
816 rx.rx_packets += p->rx_packets; 836 do {
817 rx.rx_bytes += p->rx_bytes; 837 start = u64_stats_fetch_begin_bh(&p->syncp);
818 rx.rx_errors += p->rx_errors; 838 rxpackets = p->rx_packets;
819 rx.multicast += p->multicast; 839 rxbytes = p->rx_bytes;
840 rxmulticast = p->rx_multicast;
841 } while (u64_stats_fetch_retry_bh(&p->syncp, start));
842 accum.rx_packets += rxpackets;
843 accum.rx_bytes += rxbytes;
844 accum.rx_multicast += rxmulticast;
845 /* rx_errors is an ulong, not protected by syncp */
846 accum.rx_errors += p->rx_errors;
820 } 847 }
821 stats->rx_packets = rx.rx_packets; 848 stats->rx_packets = accum.rx_packets;
822 stats->rx_bytes = rx.rx_bytes; 849 stats->rx_bytes = accum.rx_bytes;
823 stats->rx_errors = rx.rx_errors; 850 stats->rx_errors = accum.rx_errors;
824 stats->multicast = rx.multicast; 851 stats->multicast = accum.rx_multicast;
825 } 852 }
826 return stats; 853 return stats;
827} 854}
828 855
856static int vlan_ethtool_set_tso(struct net_device *dev, u32 data)
857{
858 if (data) {
859 struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
860
861 /* Underlying device must support TSO for VLAN-tagged packets
862 * and must have TSO enabled now.
863 */
864 if (!(real_dev->vlan_features & NETIF_F_TSO))
865 return -EOPNOTSUPP;
866 if (!(real_dev->features & NETIF_F_TSO))
867 return -EINVAL;
868 dev->features |= NETIF_F_TSO;
869 } else {
870 dev->features &= ~NETIF_F_TSO;
871 }
872 return 0;
873}
874
829static const struct ethtool_ops vlan_ethtool_ops = { 875static const struct ethtool_ops vlan_ethtool_ops = {
830 .get_settings = vlan_ethtool_get_settings, 876 .get_settings = vlan_ethtool_get_settings,
831 .get_drvinfo = vlan_ethtool_get_drvinfo, 877 .get_drvinfo = vlan_ethtool_get_drvinfo,
832 .get_link = ethtool_op_get_link, 878 .get_link = ethtool_op_get_link,
833 .get_rx_csum = vlan_ethtool_get_rx_csum, 879 .get_rx_csum = vlan_ethtool_get_rx_csum,
834 .get_flags = vlan_ethtool_get_flags, 880 .get_flags = vlan_ethtool_get_flags,
881 .set_tso = vlan_ethtool_set_tso,
835}; 882};
836 883
837static const struct net_device_ops vlan_netdev_ops = { 884static const struct net_device_ops vlan_netdev_ops = {
@@ -848,7 +895,7 @@ static const struct net_device_ops vlan_netdev_ops = {
848 .ndo_change_rx_flags = vlan_dev_change_rx_flags, 895 .ndo_change_rx_flags = vlan_dev_change_rx_flags,
849 .ndo_do_ioctl = vlan_dev_ioctl, 896 .ndo_do_ioctl = vlan_dev_ioctl,
850 .ndo_neigh_setup = vlan_dev_neigh_setup, 897 .ndo_neigh_setup = vlan_dev_neigh_setup,
851 .ndo_get_stats = vlan_dev_get_stats, 898 .ndo_get_stats64 = vlan_dev_get_stats64,
852#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) 899#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
853 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, 900 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
854 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, 901 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
@@ -872,7 +919,7 @@ static const struct net_device_ops vlan_netdev_accel_ops = {
872 .ndo_change_rx_flags = vlan_dev_change_rx_flags, 919 .ndo_change_rx_flags = vlan_dev_change_rx_flags,
873 .ndo_do_ioctl = vlan_dev_ioctl, 920 .ndo_do_ioctl = vlan_dev_ioctl,
874 .ndo_neigh_setup = vlan_dev_neigh_setup, 921 .ndo_neigh_setup = vlan_dev_neigh_setup,
875 .ndo_get_stats = vlan_dev_get_stats, 922 .ndo_get_stats64 = vlan_dev_get_stats64,
876#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) 923#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
877 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, 924 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
878 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, 925 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
@@ -897,7 +944,7 @@ static const struct net_device_ops vlan_netdev_ops_sq = {
897 .ndo_change_rx_flags = vlan_dev_change_rx_flags, 944 .ndo_change_rx_flags = vlan_dev_change_rx_flags,
898 .ndo_do_ioctl = vlan_dev_ioctl, 945 .ndo_do_ioctl = vlan_dev_ioctl,
899 .ndo_neigh_setup = vlan_dev_neigh_setup, 946 .ndo_neigh_setup = vlan_dev_neigh_setup,
900 .ndo_get_stats = vlan_dev_get_stats, 947 .ndo_get_stats64 = vlan_dev_get_stats64,
901#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) 948#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
902 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, 949 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
903 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, 950 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
@@ -922,7 +969,7 @@ static const struct net_device_ops vlan_netdev_accel_ops_sq = {
922 .ndo_change_rx_flags = vlan_dev_change_rx_flags, 969 .ndo_change_rx_flags = vlan_dev_change_rx_flags,
923 .ndo_do_ioctl = vlan_dev_ioctl, 970 .ndo_do_ioctl = vlan_dev_ioctl,
924 .ndo_neigh_setup = vlan_dev_neigh_setup, 971 .ndo_neigh_setup = vlan_dev_neigh_setup,
925 .ndo_get_stats = vlan_dev_get_stats, 972 .ndo_get_stats64 = vlan_dev_get_stats64,
926#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) 973#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
927 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, 974 .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
928 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, 975 .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,