diff options
Diffstat (limited to 'net/ipv4/devinet.c')
| -rw-r--r-- | net/ipv4/devinet.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3cc96730c4ed..478a30179a52 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -233,11 +233,14 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) | |||
| 233 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 233 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
| 234 | int destroy) | 234 | int destroy) |
| 235 | { | 235 | { |
| 236 | struct in_ifaddr *promote = NULL; | ||
| 236 | struct in_ifaddr *ifa1 = *ifap; | 237 | struct in_ifaddr *ifa1 = *ifap; |
| 237 | 238 | ||
| 238 | ASSERT_RTNL(); | 239 | ASSERT_RTNL(); |
| 239 | 240 | ||
| 240 | /* 1. Deleting primary ifaddr forces deletion all secondaries */ | 241 | /* 1. Deleting primary ifaddr forces deletion all secondaries |
| 242 | * unless alias promotion is set | ||
| 243 | **/ | ||
| 241 | 244 | ||
| 242 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { | 245 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { |
| 243 | struct in_ifaddr *ifa; | 246 | struct in_ifaddr *ifa; |
| @@ -251,11 +254,16 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 251 | continue; | 254 | continue; |
| 252 | } | 255 | } |
| 253 | 256 | ||
| 254 | *ifap1 = ifa->ifa_next; | 257 | if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) { |
| 258 | *ifap1 = ifa->ifa_next; | ||
| 255 | 259 | ||
| 256 | rtmsg_ifa(RTM_DELADDR, ifa); | 260 | rtmsg_ifa(RTM_DELADDR, ifa); |
| 257 | notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); | 261 | notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); |
| 258 | inet_free_ifa(ifa); | 262 | inet_free_ifa(ifa); |
| 263 | } else { | ||
| 264 | promote = ifa; | ||
| 265 | break; | ||
| 266 | } | ||
| 259 | } | 267 | } |
| 260 | } | 268 | } |
| 261 | 269 | ||
| @@ -281,6 +289,13 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 281 | if (!in_dev->ifa_list) | 289 | if (!in_dev->ifa_list) |
| 282 | inetdev_destroy(in_dev); | 290 | inetdev_destroy(in_dev); |
| 283 | } | 291 | } |
| 292 | |||
| 293 | if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) { | ||
| 294 | /* not sure if we should send a delete notify first? */ | ||
| 295 | promote->ifa_flags &= ~IFA_F_SECONDARY; | ||
| 296 | rtmsg_ifa(RTM_NEWADDR, promote); | ||
| 297 | notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); | ||
| 298 | } | ||
| 284 | } | 299 | } |
| 285 | 300 | ||
| 286 | static int inet_insert_ifa(struct in_ifaddr *ifa) | 301 | static int inet_insert_ifa(struct in_ifaddr *ifa) |
| @@ -1384,6 +1399,15 @@ static struct devinet_sysctl_table { | |||
| 1384 | .proc_handler = &ipv4_doint_and_flush, | 1399 | .proc_handler = &ipv4_doint_and_flush, |
| 1385 | .strategy = &ipv4_doint_and_flush_strategy, | 1400 | .strategy = &ipv4_doint_and_flush_strategy, |
| 1386 | }, | 1401 | }, |
| 1402 | { | ||
| 1403 | .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES, | ||
| 1404 | .procname = "promote_secondaries", | ||
| 1405 | .data = &ipv4_devconf.promote_secondaries, | ||
| 1406 | .maxlen = sizeof(int), | ||
| 1407 | .mode = 0644, | ||
| 1408 | .proc_handler = &ipv4_doint_and_flush, | ||
| 1409 | .strategy = &ipv4_doint_and_flush_strategy, | ||
| 1410 | }, | ||
| 1387 | }, | 1411 | }, |
| 1388 | .devinet_dev = { | 1412 | .devinet_dev = { |
| 1389 | { | 1413 | { |
