]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/net/team/team.c
net: better IFF_XMIT_DST_RELEASE support
[mirror_ubuntu-bionic-kernel.git] / drivers / net / team / team.c
index ef10302ec936ee5969001bb9da484b80d573c1ee..a94a9df3e6bd241319afbf8c3105a25fced323b4 100644 (file)
@@ -970,7 +970,8 @@ static void __team_compute_features(struct team *team)
        struct team_port *port;
        u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL;
        unsigned short max_hard_header_len = ETH_HLEN;
-       unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
+       unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
+                                       IFF_XMIT_DST_RELEASE_PERM;
 
        list_for_each_entry(port, &team->port_list, list) {
                vlan_features = netdev_increment_features(vlan_features,
@@ -985,8 +986,9 @@ static void __team_compute_features(struct team *team)
        team->dev->vlan_features = vlan_features;
        team->dev->hard_header_len = max_hard_header_len;
 
-       flags = team->dev->priv_flags & ~IFF_XMIT_DST_RELEASE;
-       team->dev->priv_flags = flags | dst_release_flag;
+       team->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+       if (dst_release_flag == (IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM))
+               team->dev->priv_flags |= IFF_XMIT_DST_RELEASE;
 
        netdev_change_features(team->dev);
 }
@@ -1003,7 +1005,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
        int err = 0;
 
        dev_hold(team->dev);
-       port->dev->priv_flags |= IFF_TEAM_PORT;
        if (team->ops.port_enter) {
                err = team->ops.port_enter(team, port);
                if (err) {
@@ -1016,7 +1017,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
        return 0;
 
 err_port_enter:
-       port->dev->priv_flags &= ~IFF_TEAM_PORT;
        dev_put(team->dev);
 
        return err;
@@ -1026,7 +1026,6 @@ static void team_port_leave(struct team *team, struct team_port *port)
 {
        if (team->ops.port_leave)
                team->ops.port_leave(team, port);
-       port->dev->priv_flags &= ~IFF_TEAM_PORT;
        dev_put(team->dev);
 }
 
@@ -1075,6 +1074,25 @@ static void team_port_disable_netpoll(struct team_port *port)
 }
 #endif
 
+static int team_upper_dev_link(struct net_device *dev,
+                              struct net_device *port_dev)
+{
+       int err;
+
+       err = netdev_master_upper_dev_link(port_dev, dev);
+       if (err)
+               return err;
+       port_dev->priv_flags |= IFF_TEAM_PORT;
+       return 0;
+}
+
+static void team_upper_dev_unlink(struct net_device *dev,
+                                 struct net_device *port_dev)
+{
+       netdev_upper_dev_unlink(port_dev, dev);
+       port_dev->priv_flags &= ~IFF_TEAM_PORT;
+}
+
 static void __team_port_change_port_added(struct team_port *port, bool linkup);
 static int team_dev_type_check_change(struct net_device *dev,
                                      struct net_device *port_dev);
@@ -1161,13 +1179,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_enable_netpoll;
        }
 
-       err = netdev_master_upper_dev_link(port_dev, dev);
-       if (err) {
-               netdev_err(dev, "Device %s failed to set upper link\n",
-                          portname);
-               goto err_set_upper_link;
-       }
-
        err = netdev_rx_handler_register(port_dev, team_handle_frame,
                                         port);
        if (err) {
@@ -1176,6 +1187,13 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_handler_register;
        }
 
+       err = team_upper_dev_link(dev, port_dev);
+       if (err) {
+               netdev_err(dev, "Device %s failed to set upper link\n",
+                          portname);
+               goto err_set_upper_link;
+       }
+
        err = __team_option_inst_add_port(team, port);
        if (err) {
                netdev_err(dev, "Device %s failed to add per-port options\n",
@@ -1195,12 +1213,12 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
        return 0;
 
 err_option_port_add:
+       team_upper_dev_unlink(dev, port_dev);
+
+err_set_upper_link:
        netdev_rx_handler_unregister(port_dev);
 
 err_handler_register:
-       netdev_upper_dev_unlink(port_dev, dev);
-
-err_set_upper_link:
        team_port_disable_netpoll(port);
 
 err_enable_netpoll:
@@ -1239,8 +1257,8 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
 
        team_port_disable(team, port);
        list_del_rcu(&port->list);
+       team_upper_dev_unlink(dev, port_dev);
        netdev_rx_handler_unregister(port_dev);
-       netdev_upper_dev_unlink(port_dev, dev);
        team_port_disable_netpoll(port);
        vlan_vids_del_by_dev(port_dev, dev);
        dev_uc_unsync(port_dev, dev);