forked from mirrors/linux
		
	[IPV4]: Fix secondary IP addresses after promotion
This patch fixes the problem with promoting aliases when: a) a single primary and > 1 secondary addresses b) multiple primary addresses each with at least one secondary address Based on earlier efforts from Brian Pomerantz <bapper@piratehaven.org>, Patrick McHardy <kaber@trash.net> and Thomas Graf <tgraf@suug.ch> Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c27bd492fd
								
							
						
					
					
						commit
						0ff60a4567
					
				
					 3 changed files with 34 additions and 11 deletions
				
			
		|  | @ -126,6 +126,9 @@ extern int		ip_rt_ioctl(unsigned int cmd, void __user *arg); | |||
| extern void		ip_rt_get_source(u8 *src, struct rtable *rt); | ||||
| extern int		ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb); | ||||
| 
 | ||||
| struct in_ifaddr; | ||||
| extern void fib_add_ifaddr(struct in_ifaddr *); | ||||
| 
 | ||||
| static inline void ip_rt_put(struct rtable * rt) | ||||
| { | ||||
| 	if (rt) | ||||
|  |  | |||
|  | @ -234,7 +234,10 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 			 int destroy) | ||||
| { | ||||
| 	struct in_ifaddr *promote = NULL; | ||||
| 	struct in_ifaddr *ifa1 = *ifap; | ||||
| 	struct in_ifaddr *ifa, *ifa1 = *ifap; | ||||
| 	struct in_ifaddr *last_prim = in_dev->ifa_list; | ||||
| 	struct in_ifaddr *prev_prom = NULL; | ||||
| 	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); | ||||
| 
 | ||||
| 	ASSERT_RTNL(); | ||||
| 
 | ||||
|  | @ -243,18 +246,22 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 	 **/ | ||||
| 
 | ||||
| 	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { | ||||
| 		struct in_ifaddr *ifa; | ||||
| 		struct in_ifaddr **ifap1 = &ifa1->ifa_next; | ||||
| 
 | ||||
| 		while ((ifa = *ifap1) != NULL) { | ||||
| 			if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&  | ||||
| 			    ifa1->ifa_scope <= ifa->ifa_scope) | ||||
| 				last_prim = ifa; | ||||
| 
 | ||||
| 			if (!(ifa->ifa_flags & IFA_F_SECONDARY) || | ||||
| 			    ifa1->ifa_mask != ifa->ifa_mask || | ||||
| 			    !inet_ifa_match(ifa1->ifa_address, ifa)) { | ||||
| 				ifap1 = &ifa->ifa_next; | ||||
| 				prev_prom = ifa; | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) { | ||||
| 			if (!do_promote) { | ||||
| 				*ifap1 = ifa->ifa_next; | ||||
| 
 | ||||
| 				rtmsg_ifa(RTM_DELADDR, ifa); | ||||
|  | @ -283,19 +290,32 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 	 */ | ||||
| 	rtmsg_ifa(RTM_DELADDR, ifa1); | ||||
| 	notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); | ||||
| 
 | ||||
| 	if (promote) { | ||||
| 
 | ||||
| 		if (prev_prom) { | ||||
| 			prev_prom->ifa_next = promote->ifa_next; | ||||
| 			promote->ifa_next = last_prim->ifa_next; | ||||
| 			last_prim->ifa_next = promote; | ||||
| 		} | ||||
| 
 | ||||
| 		promote->ifa_flags &= ~IFA_F_SECONDARY; | ||||
| 		rtmsg_ifa(RTM_NEWADDR, promote); | ||||
| 		notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); | ||||
| 		for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { | ||||
| 			if (ifa1->ifa_mask != ifa->ifa_mask || | ||||
| 			    !inet_ifa_match(ifa1->ifa_address, ifa)) | ||||
| 					continue; | ||||
| 			fib_add_ifaddr(ifa); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 	if (destroy) { | ||||
| 		inet_free_ifa(ifa1); | ||||
| 
 | ||||
| 		if (!in_dev->ifa_list) | ||||
| 			inetdev_destroy(in_dev); | ||||
| 	} | ||||
| 
 | ||||
| 	if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) { | ||||
| 		/* not sure if we should send a delete notify first? */ | ||||
| 		promote->ifa_flags &= ~IFA_F_SECONDARY; | ||||
| 		rtmsg_ifa(RTM_NEWADDR, promote); | ||||
| 		notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int inet_insert_ifa(struct in_ifaddr *ifa) | ||||
|  |  | |||
|  | @ -407,7 +407,7 @@ static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr | |||
| 		tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL); | ||||
| } | ||||
| 
 | ||||
| static void fib_add_ifaddr(struct in_ifaddr *ifa) | ||||
| void fib_add_ifaddr(struct in_ifaddr *ifa) | ||||
| { | ||||
| 	struct in_device *in_dev = ifa->ifa_dev; | ||||
| 	struct net_device *dev = in_dev->dev; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jamal Hadi Salim
						Jamal Hadi Salim