diff options
Diffstat (limited to 'drivers/net/macvtap.c')
-rw-r--r-- | drivers/net/macvtap.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a98fb0ed6aef..ea53abb20988 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -68,6 +68,8 @@ static const struct proto_ops macvtap_socket_ops; | |||
68 | #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \ | 68 | #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \ |
69 | NETIF_F_TSO6 | NETIF_F_UFO) | 69 | NETIF_F_TSO6 | NETIF_F_UFO) |
70 | #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) | 70 | #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) |
71 | #define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG) | ||
72 | |||
71 | /* | 73 | /* |
72 | * RCU usage: | 74 | * RCU usage: |
73 | * The macvtap_queue and the macvlan_dev are loosely coupled, the | 75 | * The macvtap_queue and the macvlan_dev are loosely coupled, the |
@@ -278,7 +280,8 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) | |||
278 | { | 280 | { |
279 | struct macvlan_dev *vlan = netdev_priv(dev); | 281 | struct macvlan_dev *vlan = netdev_priv(dev); |
280 | struct macvtap_queue *q = macvtap_get_queue(dev, skb); | 282 | struct macvtap_queue *q = macvtap_get_queue(dev, skb); |
281 | netdev_features_t features; | 283 | netdev_features_t features = TAP_FEATURES; |
284 | |||
282 | if (!q) | 285 | if (!q) |
283 | goto drop; | 286 | goto drop; |
284 | 287 | ||
@@ -287,9 +290,11 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) | |||
287 | 290 | ||
288 | skb->dev = dev; | 291 | skb->dev = dev; |
289 | /* Apply the forward feature mask so that we perform segmentation | 292 | /* Apply the forward feature mask so that we perform segmentation |
290 | * according to users wishes. | 293 | * according to users wishes. This only works if VNET_HDR is |
294 | * enabled. | ||
291 | */ | 295 | */ |
292 | features = netif_skb_features(skb) & vlan->tap_features; | 296 | if (q->flags & IFF_VNET_HDR) |
297 | features |= vlan->tap_features; | ||
293 | if (netif_needs_gso(skb, features)) { | 298 | if (netif_needs_gso(skb, features)) { |
294 | struct sk_buff *segs = __skb_gso_segment(skb, features, false); | 299 | struct sk_buff *segs = __skb_gso_segment(skb, features, false); |
295 | 300 | ||
@@ -818,10 +823,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, | |||
818 | skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; | 823 | skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; |
819 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; | 824 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; |
820 | } | 825 | } |
821 | if (vlan) | 826 | if (vlan) { |
827 | local_bh_disable(); | ||
822 | macvlan_start_xmit(skb, vlan->dev); | 828 | macvlan_start_xmit(skb, vlan->dev); |
823 | else | 829 | local_bh_enable(); |
830 | } else { | ||
824 | kfree_skb(skb); | 831 | kfree_skb(skb); |
832 | } | ||
825 | rcu_read_unlock(); | 833 | rcu_read_unlock(); |
826 | 834 | ||
827 | return total_len; | 835 | return total_len; |
@@ -912,8 +920,11 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
912 | done: | 920 | done: |
913 | rcu_read_lock(); | 921 | rcu_read_lock(); |
914 | vlan = rcu_dereference(q->vlan); | 922 | vlan = rcu_dereference(q->vlan); |
915 | if (vlan) | 923 | if (vlan) { |
924 | preempt_disable(); | ||
916 | macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0); | 925 | macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0); |
926 | preempt_enable(); | ||
927 | } | ||
917 | rcu_read_unlock(); | 928 | rcu_read_unlock(); |
918 | 929 | ||
919 | return ret ? ret : copied; | 930 | return ret ? ret : copied; |
@@ -1058,8 +1069,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg) | |||
1058 | /* tap_features are the same as features on tun/tap and | 1069 | /* tap_features are the same as features on tun/tap and |
1059 | * reflect user expectations. | 1070 | * reflect user expectations. |
1060 | */ | 1071 | */ |
1061 | vlan->tap_features = vlan->dev->features & | 1072 | vlan->tap_features = feature_mask; |
1062 | (feature_mask | ~TUN_OFFLOADS); | ||
1063 | vlan->set_features = features; | 1073 | vlan->set_features = features; |
1064 | netdev_update_features(vlan->dev); | 1074 | netdev_update_features(vlan->dev); |
1065 | 1075 | ||
@@ -1155,10 +1165,6 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, | |||
1155 | TUN_F_TSO_ECN | TUN_F_UFO)) | 1165 | TUN_F_TSO_ECN | TUN_F_UFO)) |
1156 | return -EINVAL; | 1166 | return -EINVAL; |
1157 | 1167 | ||
1158 | /* TODO: only accept frames with the features that | ||
1159 | got enabled for forwarded frames */ | ||
1160 | if (!(q->flags & IFF_VNET_HDR)) | ||
1161 | return -EINVAL; | ||
1162 | rtnl_lock(); | 1168 | rtnl_lock(); |
1163 | ret = set_offload(q, arg); | 1169 | ret = set_offload(q, arg); |
1164 | rtnl_unlock(); | 1170 | rtnl_unlock(); |