aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/devinet.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r--net/ipv4/devinet.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 3cc96730c4ed..650dcb12d9a1 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)
233static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, 233static 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
286static int inet_insert_ifa(struct in_ifaddr *ifa) 301static int inet_insert_ifa(struct in_ifaddr *ifa)
@@ -1015,14 +1030,13 @@ static struct notifier_block ip_netdev_notifier = {
1015}; 1030};
1016 1031
1017static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, 1032static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
1018 u32 pid, u32 seq, int event) 1033 u32 pid, u32 seq, int event, unsigned int flags)
1019{ 1034{
1020 struct ifaddrmsg *ifm; 1035 struct ifaddrmsg *ifm;
1021 struct nlmsghdr *nlh; 1036 struct nlmsghdr *nlh;
1022 unsigned char *b = skb->tail; 1037 unsigned char *b = skb->tail;
1023 1038
1024 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm)); 1039 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
1025 if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
1026 ifm = NLMSG_DATA(nlh); 1040 ifm = NLMSG_DATA(nlh);
1027 ifm->ifa_family = AF_INET; 1041 ifm->ifa_family = AF_INET;
1028 ifm->ifa_prefixlen = ifa->ifa_prefixlen; 1042 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
@@ -1075,7 +1089,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1075 continue; 1089 continue;
1076 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, 1090 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
1077 cb->nlh->nlmsg_seq, 1091 cb->nlh->nlmsg_seq,
1078 RTM_NEWADDR) <= 0) { 1092 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1079 rcu_read_unlock(); 1093 rcu_read_unlock();
1080 goto done; 1094 goto done;
1081 } 1095 }
@@ -1098,7 +1112,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa)
1098 1112
1099 if (!skb) 1113 if (!skb)
1100 netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS); 1114 netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS);
1101 else if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { 1115 else if (inet_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) {
1102 kfree_skb(skb); 1116 kfree_skb(skb);
1103 netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL); 1117 netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL);
1104 } else { 1118 } else {
@@ -1384,6 +1398,15 @@ static struct devinet_sysctl_table {
1384 .proc_handler = &ipv4_doint_and_flush, 1398 .proc_handler = &ipv4_doint_and_flush,
1385 .strategy = &ipv4_doint_and_flush_strategy, 1399 .strategy = &ipv4_doint_and_flush_strategy,
1386 }, 1400 },
1401 {
1402 .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES,
1403 .procname = "promote_secondaries",
1404 .data = &ipv4_devconf.promote_secondaries,
1405 .maxlen = sizeof(int),
1406 .mode = 0644,
1407 .proc_handler = &ipv4_doint_and_flush,
1408 .strategy = &ipv4_doint_and_flush_strategy,
1409 },
1387 }, 1410 },
1388 .devinet_dev = { 1411 .devinet_dev = {
1389 { 1412 {