91855c47a665fd659bd562e00ce9125470a67469
[sliver-openvswitch.git] / datapath / linux / compat / netdevice.c
1 #include <linux/if_link.h>
2 #include <linux/netdevice.h>
3 #include <linux/if_vlan.h>
4
5 /* Linux 2.6.28 introduced dev_get_stats():
6  * const struct net_device_stats *dev_get_stats(struct net_device *dev);
7  *
8  * Linux 2.6.36 changed dev_get_stats() to:
9  * struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
10  *                                         struct rtnl_link_stats64 *storage);
11  */
12 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
13 struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
14                                         struct rtnl_link_stats64 *storage)
15 {
16         const struct net_device_stats *stats;
17
18 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
19         stats = dev->get_stats(dev);
20 #else  /* 2.6.28 < kernel version < 2.6.36 */
21         stats = (dev_get_stats)(dev);
22 #endif /* 2.6.28 < kernel version < 2.6.36 */
23
24         storage->rx_packets = stats->rx_packets;
25         storage->tx_packets = stats->tx_packets;
26         storage->rx_bytes = stats->rx_bytes;
27         storage->tx_bytes = stats->tx_bytes;
28         storage->rx_errors = stats->rx_errors;
29         storage->tx_errors = stats->tx_errors;
30         storage->rx_dropped = stats->rx_dropped;
31         storage->tx_dropped = stats->tx_dropped;
32         storage->multicast = stats->multicast;
33         storage->collisions = stats->collisions;
34         storage->rx_length_errors = stats->rx_length_errors;
35         storage->rx_over_errors = stats->rx_over_errors;
36         storage->rx_crc_errors = stats->rx_crc_errors;
37         storage->rx_frame_errors = stats->rx_frame_errors;
38         storage->rx_fifo_errors = stats->rx_fifo_errors;
39         storage->rx_missed_errors = stats->rx_missed_errors;
40         storage->tx_aborted_errors = stats->tx_aborted_errors;
41         storage->tx_carrier_errors = stats->tx_carrier_errors;
42         storage->tx_fifo_errors = stats->tx_fifo_errors;
43         storage->tx_heartbeat_errors = stats->tx_heartbeat_errors;
44         storage->tx_window_errors = stats->tx_window_errors;
45         storage->rx_compressed = stats->rx_compressed;
46         storage->tx_compressed = stats->tx_compressed;
47
48         return storage;
49 }
50 #endif  /* kernel version < 2.6.36 */
51
52 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
53 static bool can_checksum_protocol(unsigned long features, __be16 protocol)
54 {
55         return  ((features & NETIF_F_GEN_CSUM) ||
56                 ((features & NETIF_F_V4_CSUM) &&
57                                 protocol == htons(ETH_P_IP)) ||
58                 ((features & NETIF_F_V6_CSUM) &&
59                                 protocol == htons(ETH_P_IPV6)) ||
60                 ((features & NETIF_F_FCOE_CRC) &&
61                                 protocol == htons(ETH_P_FCOE)));
62 }
63
64 static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
65 {
66 #ifdef CONFIG_HIGHMEM
67         int i;
68
69         if (dev->features & NETIF_F_HIGHDMA)
70                 return 0;
71
72         for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
73                 if (PageHighMem(skb_shinfo(skb)->frags[i].page))
74                         return 1;
75
76 #endif
77         return 0;
78 }
79
80 static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features)
81 {
82         if (!can_checksum_protocol(features, protocol)) {
83                 features &= ~NETIF_F_ALL_CSUM;
84                 features &= ~NETIF_F_SG;
85         } else if (illegal_highdma(skb->dev, skb)) {
86                 features &= ~NETIF_F_SG;
87         }
88
89         return features;
90 }
91
92 u32 rpl_netif_skb_features(struct sk_buff *skb)
93 {
94 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
95         unsigned long vlan_features = 0;
96 #else
97         unsigned long vlan_features = skb->dev->vlan_features;
98 #endif /* kernel version < 2.6.26 */
99
100         __be16 protocol = skb->protocol;
101         u32 features = skb->dev->features;
102
103         if (protocol == htons(ETH_P_8021Q)) {
104                 struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
105                 protocol = veh->h_vlan_encapsulated_proto;
106         } else if (!vlan_tx_tag_present(skb)) {
107                 return harmonize_features(skb, protocol, features);
108         }
109
110         features &= (vlan_features | NETIF_F_HW_VLAN_TX);
111
112         if (protocol != htons(ETH_P_8021Q)) {
113                 return harmonize_features(skb, protocol, features);
114         } else {
115                 features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
116                         NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX;
117                 return harmonize_features(skb, protocol, features);
118         }
119 }
120
121 struct sk_buff *rpl_skb_gso_segment(struct sk_buff *skb, u32 features)
122 {
123         int vlan_depth = ETH_HLEN;
124         __be16 type = skb->protocol;
125         __be16 skb_proto;
126         struct sk_buff *skb_gso;
127
128         while (type == htons(ETH_P_8021Q)) {
129                 struct vlan_hdr *vh;
130
131                 if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
132                         return ERR_PTR(-EINVAL);
133
134                 vh = (struct vlan_hdr *)(skb->data + vlan_depth);
135                 type = vh->h_vlan_encapsulated_proto;
136                 vlan_depth += VLAN_HLEN;
137         }
138
139         /* this hack needed to get regular skb_gso_segment() */
140 #undef skb_gso_segment
141         skb_proto = skb->protocol;
142         skb->protocol = type;
143
144         skb_gso = skb_gso_segment(skb, features);
145         skb->protocol = skb_proto;
146         return skb_gso;
147 }
148 #endif  /* kernel version < 2.6.38 */