diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index cfb91570cdddccdfc02f9b860d1bf26d8b836b48..24ea994b6274c324143973a74aeedf78088ffc74 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -120,7 +120,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev = vlan->dev; if (local) - return vlan->forward(dev, skb); + return dev_forward_skb(dev, skb); skb->dev = dev; if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) @@ -128,7 +128,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, else skb->pkt_type = PACKET_MULTICAST; - return vlan->receive(skb); + return netif_rx(skb); } static u32 macvlan_hash_mix(const struct macvlan_dev *vlan) @@ -251,7 +251,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) skb->dev = dev; skb->pkt_type = PACKET_HOST; - ret = vlan->receive(skb); + ret = netif_rx(skb); out: macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0); @@ -803,10 +803,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) } int macvlan_common_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - int (*receive)(struct sk_buff *skb), - int (*forward)(struct net_device *dev, - struct sk_buff *skb)) + struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_port *port; @@ -848,8 +845,6 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, vlan->lowerdev = lowerdev; vlan->dev = dev; vlan->port = port; - vlan->receive = receive; - vlan->forward = forward; vlan->set_features = MACVLAN_FEATURES; vlan->mode = MACVLAN_MODE_VEPA; @@ -894,9 +889,7 @@ EXPORT_SYMBOL_GPL(macvlan_common_newlink); static int macvlan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - return macvlan_common_newlink(src_net, dev, tb, data, - netif_rx, - dev_forward_skb); + return macvlan_common_newlink(src_net, dev, tb, data); } void macvlan_dellink(struct net_device *dev, struct list_head *head) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 4a34bcb6549f7eadd05c63288eae252f7c277452..64409af0da3185fd050cbbc34d7c615c84c11b0d 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -70,6 +70,11 @@ static const struct proto_ops macvtap_socket_ops; #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) #define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG) +static struct macvlan_dev *macvtap_get_vlan_rcu(const struct net_device *dev) +{ + return rcu_dereference(dev->rx_handler_data); +} + /* * RCU usage: * The macvtap_queue and the macvlan_dev are loosely coupled, the @@ -271,24 +276,27 @@ static void macvtap_del_queues(struct net_device *dev) sock_put(&qlist[j]->sk); } -/* - * Forward happens for data that gets sent from one macvlan - * endpoint to another one in bridge mode. We just take - * the skb and put it into the receive queue. - */ -static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) +static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb) { - struct macvlan_dev *vlan = netdev_priv(dev); - struct macvtap_queue *q = macvtap_get_queue(dev, skb); + struct sk_buff *skb = *pskb; + struct net_device *dev = skb->dev; + struct macvlan_dev *vlan; + struct macvtap_queue *q; netdev_features_t features = TAP_FEATURES; + vlan = macvtap_get_vlan_rcu(dev); + if (!vlan) + return RX_HANDLER_PASS; + + q = macvtap_get_queue(dev, skb); if (!q) - goto drop; + return RX_HANDLER_PASS; if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len) goto drop; - skb->dev = dev; + skb_push(skb, ETH_HLEN); + /* Apply the forward feature mask so that we perform segmentation * according to users wishes. This only works if VNET_HDR is * enabled. @@ -320,22 +328,13 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) wake_up: wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND); - return NET_RX_SUCCESS; + return RX_HANDLER_CONSUMED; drop: + /* Count errors/drops only here, thus don't care about args. */ + macvlan_count_rx(vlan, 0, 0, 0); kfree_skb(skb); - return NET_RX_DROP; -} - -/* - * Receive is for data from the external interface (lowerdev), - * in case of macvtap, we can treat that the same way as - * forward, which macvlan cannot. - */ -static int macvtap_receive(struct sk_buff *skb) -{ - skb_push(skb, ETH_HLEN); - return macvtap_forward(skb->dev, skb); + return RX_HANDLER_CONSUMED; } static int macvtap_get_minor(struct macvlan_dev *vlan) @@ -385,6 +384,8 @@ static int macvtap_newlink(struct net *src_net, struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); + int err; + INIT_LIST_HEAD(&vlan->queue_list); /* Since macvlan supports all offloads by default, make @@ -392,16 +393,20 @@ static int macvtap_newlink(struct net *src_net, */ vlan->tap_features = TUN_OFFLOADS; + err = netdev_rx_handler_register(dev, macvtap_handle_frame, vlan); + if (err) + return err; + /* Don't put anything that may fail after macvlan_common_newlink * because we can't undo what it does. */ - return macvlan_common_newlink(src_net, dev, tb, data, - macvtap_receive, macvtap_forward); + return macvlan_common_newlink(src_net, dev, tb, data); } static void macvtap_dellink(struct net_device *dev, struct list_head *head) { + netdev_rx_handler_unregister(dev); macvtap_del_queues(dev); macvlan_dellink(dev, head); } @@ -725,9 +730,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; } if (vlan) { - local_bh_disable(); - macvlan_start_xmit(skb, vlan->dev); - local_bh_enable(); + skb->dev = vlan->dev; + dev_queue_xmit(skb); } else { kfree_skb(skb); } diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 84ba5ac39e039f80da563305155800cd1332782c..ea22721ba269e6d49611fd8ad745ffc363e57ad0 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -69,8 +69,6 @@ struct macvlan_dev { netdev_features_t set_features; enum macvlan_mode mode; u16 flags; - int (*receive)(struct sk_buff *skb); - int (*forward)(struct net_device *dev, struct sk_buff *skb); /* This array tracks active taps. */ struct macvtap_queue __rcu *taps[MAX_MACVTAP_QUEUES]; /* This list tracks all taps (both enabled and disabled) */ @@ -103,10 +101,7 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan, extern void macvlan_common_setup(struct net_device *dev); extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - int (*receive)(struct sk_buff *skb), - int (*forward)(struct net_device *dev, - struct sk_buff *skb)); + struct nlattr *tb[], struct nlattr *data[]); extern void macvlan_count_rx(const struct macvlan_dev *vlan, unsigned int len, bool success,