aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c91
1 files changed, 80 insertions, 11 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index b65a5051361f..cf8a95f48cff 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2587,13 +2587,19 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
2587 return harmonize_features(skb, features); 2587 return harmonize_features(skb, features);
2588 } 2588 }
2589 2589
2590 features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | 2590 features = netdev_intersect_features(features,
2591 NETIF_F_HW_VLAN_STAG_TX); 2591 skb->dev->vlan_features |
2592 NETIF_F_HW_VLAN_CTAG_TX |
2593 NETIF_F_HW_VLAN_STAG_TX);
2592 2594
2593 if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) 2595 if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD))
2594 features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | 2596 features = netdev_intersect_features(features,
2595 NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | 2597 NETIF_F_SG |
2596 NETIF_F_HW_VLAN_STAG_TX; 2598 NETIF_F_HIGHDMA |
2599 NETIF_F_FRAGLIST |
2600 NETIF_F_GEN_CSUM |
2601 NETIF_F_HW_VLAN_CTAG_TX |
2602 NETIF_F_HW_VLAN_STAG_TX);
2597 2603
2598 return harmonize_features(skb, features); 2604 return harmonize_features(skb, features);
2599} 2605}
@@ -4803,9 +4809,14 @@ static void netdev_adjacent_sysfs_del(struct net_device *dev,
4803 sysfs_remove_link(&(dev->dev.kobj), linkname); 4809 sysfs_remove_link(&(dev->dev.kobj), linkname);
4804} 4810}
4805 4811
4806#define netdev_adjacent_is_neigh_list(dev, dev_list) \ 4812static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev,
4807 (dev_list == &dev->adj_list.upper || \ 4813 struct net_device *adj_dev,
4808 dev_list == &dev->adj_list.lower) 4814 struct list_head *dev_list)
4815{
4816 return (dev_list == &dev->adj_list.upper ||
4817 dev_list == &dev->adj_list.lower) &&
4818 net_eq(dev_net(dev), dev_net(adj_dev));
4819}
4809 4820
4810static int __netdev_adjacent_dev_insert(struct net_device *dev, 4821static int __netdev_adjacent_dev_insert(struct net_device *dev,
4811 struct net_device *adj_dev, 4822 struct net_device *adj_dev,
@@ -4835,7 +4846,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
4835 pr_debug("dev_hold for %s, because of link added from %s to %s\n", 4846 pr_debug("dev_hold for %s, because of link added from %s to %s\n",
4836 adj_dev->name, dev->name, adj_dev->name); 4847 adj_dev->name, dev->name, adj_dev->name);
4837 4848
4838 if (netdev_adjacent_is_neigh_list(dev, dev_list)) { 4849 if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) {
4839 ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list); 4850 ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list);
4840 if (ret) 4851 if (ret)
4841 goto free_adj; 4852 goto free_adj;
@@ -4856,7 +4867,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
4856 return 0; 4867 return 0;
4857 4868
4858remove_symlinks: 4869remove_symlinks:
4859 if (netdev_adjacent_is_neigh_list(dev, dev_list)) 4870 if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))
4860 netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); 4871 netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
4861free_adj: 4872free_adj:
4862 kfree(adj); 4873 kfree(adj);
@@ -4889,7 +4900,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
4889 if (adj->master) 4900 if (adj->master)
4890 sysfs_remove_link(&(dev->dev.kobj), "master"); 4901 sysfs_remove_link(&(dev->dev.kobj), "master");
4891 4902
4892 if (netdev_adjacent_is_neigh_list(dev, dev_list)) 4903 if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))
4893 netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); 4904 netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
4894 4905
4895 list_del_rcu(&adj->list); 4906 list_del_rcu(&adj->list);
@@ -5159,11 +5170,65 @@ void netdev_upper_dev_unlink(struct net_device *dev,
5159} 5170}
5160EXPORT_SYMBOL(netdev_upper_dev_unlink); 5171EXPORT_SYMBOL(netdev_upper_dev_unlink);
5161 5172
5173void netdev_adjacent_add_links(struct net_device *dev)
5174{
5175 struct netdev_adjacent *iter;
5176
5177 struct net *net = dev_net(dev);
5178
5179 list_for_each_entry(iter, &dev->adj_list.upper, list) {
5180 if (!net_eq(net,dev_net(iter->dev)))
5181 continue;
5182 netdev_adjacent_sysfs_add(iter->dev, dev,
5183 &iter->dev->adj_list.lower);
5184 netdev_adjacent_sysfs_add(dev, iter->dev,
5185 &dev->adj_list.upper);
5186 }
5187
5188 list_for_each_entry(iter, &dev->adj_list.lower, list) {
5189 if (!net_eq(net,dev_net(iter->dev)))
5190 continue;
5191 netdev_adjacent_sysfs_add(iter->dev, dev,
5192 &iter->dev->adj_list.upper);
5193 netdev_adjacent_sysfs_add(dev, iter->dev,
5194 &dev->adj_list.lower);
5195 }
5196}
5197
5198void netdev_adjacent_del_links(struct net_device *dev)
5199{
5200 struct netdev_adjacent *iter;
5201
5202 struct net *net = dev_net(dev);
5203
5204 list_for_each_entry(iter, &dev->adj_list.upper, list) {
5205 if (!net_eq(net,dev_net(iter->dev)))
5206 continue;
5207 netdev_adjacent_sysfs_del(iter->dev, dev->name,
5208 &iter->dev->adj_list.lower);
5209 netdev_adjacent_sysfs_del(dev, iter->dev->name,
5210 &dev->adj_list.upper);
5211 }
5212
5213 list_for_each_entry(iter, &dev->adj_list.lower, list) {
5214 if (!net_eq(net,dev_net(iter->dev)))
5215 continue;
5216 netdev_adjacent_sysfs_del(iter->dev, dev->name,
5217 &iter->dev->adj_list.upper);
5218 netdev_adjacent_sysfs_del(dev, iter->dev->name,
5219 &dev->adj_list.lower);
5220 }
5221}
5222
5162void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) 5223void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
5163{ 5224{
5164 struct netdev_adjacent *iter; 5225 struct netdev_adjacent *iter;
5165 5226
5227 struct net *net = dev_net(dev);
5228
5166 list_for_each_entry(iter, &dev->adj_list.upper, list) { 5229 list_for_each_entry(iter, &dev->adj_list.upper, list) {
5230 if (!net_eq(net,dev_net(iter->dev)))
5231 continue;
5167 netdev_adjacent_sysfs_del(iter->dev, oldname, 5232 netdev_adjacent_sysfs_del(iter->dev, oldname,
5168 &iter->dev->adj_list.lower); 5233 &iter->dev->adj_list.lower);
5169 netdev_adjacent_sysfs_add(iter->dev, dev, 5234 netdev_adjacent_sysfs_add(iter->dev, dev,
@@ -5171,6 +5236,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
5171 } 5236 }
5172 5237
5173 list_for_each_entry(iter, &dev->adj_list.lower, list) { 5238 list_for_each_entry(iter, &dev->adj_list.lower, list) {
5239 if (!net_eq(net,dev_net(iter->dev)))
5240 continue;
5174 netdev_adjacent_sysfs_del(iter->dev, oldname, 5241 netdev_adjacent_sysfs_del(iter->dev, oldname,
5175 &iter->dev->adj_list.upper); 5242 &iter->dev->adj_list.upper);
5176 netdev_adjacent_sysfs_add(iter->dev, dev, 5243 netdev_adjacent_sysfs_add(iter->dev, dev,
@@ -6773,6 +6840,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
6773 6840
6774 /* Send a netdev-removed uevent to the old namespace */ 6841 /* Send a netdev-removed uevent to the old namespace */
6775 kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); 6842 kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE);
6843 netdev_adjacent_del_links(dev);
6776 6844
6777 /* Actually switch the network namespace */ 6845 /* Actually switch the network namespace */
6778 dev_net_set(dev, net); 6846 dev_net_set(dev, net);
@@ -6787,6 +6855,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
6787 6855
6788 /* Send a netdev-add uevent to the new namespace */ 6856 /* Send a netdev-add uevent to the new namespace */
6789 kobject_uevent(&dev->dev.kobj, KOBJ_ADD); 6857 kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
6858 netdev_adjacent_add_links(dev);
6790 6859
6791 /* Fixup kobjects */ 6860 /* Fixup kobjects */
6792 err = device_rename(&dev->dev, dev->name); 6861 err = device_rename(&dev->dev, dev->name);