diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 161 |
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 | ||
804 | static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev) | 823 | static 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 | ||
856 | static 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 | |||
829 | static const struct ethtool_ops vlan_ethtool_ops = { | 875 | static 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 | ||
837 | static const struct net_device_ops vlan_netdev_ops = { | 884 | static 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, |