Bug 81147

Summary: [net] [patch] em0 reinitialization while adding aliases to interface
Product: Base System Reporter: Dmitry Sergienko <dmitry>
Component: kernAssignee: Eric Joyner <erj>
Status: Closed Unable to Reproduce    
Severity: Affects Only Me CC: linimon, sbruno, shurd
Priority: Normal Keywords: IntelNetworking
Version: 5.4-RELEASE   
Hardware: Any   
OS: Any   

Description Dmitry Sergienko 2005-05-17 11:00:25 UTC
Network card loses link while adding an alias to interface em0.
This affects only em0 - neither vlans with vlandev em0, nor fxp0.
Problem was detected on two different machines with the same netcards

Fix: 

No fix currently found.
How-To-Repeat: 
Initial state:

root@www:/home/trooper# ifconfig em0
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=4b<RXCSUM,TXCSUM,VLAN_MTU,POLLING>
        inet 195.24.128.164 netmask 0xfffffff0 broadcast 195.24.128.175
        inet 195.24.128.72 netmask 0xffffffe0 broadcast 195.24.128.95
        ether 00:0e:0c:33:c7:a8
        media: Ethernet autoselect (1000baseTX <full-duplex>)
        status: active

root@www:/home/trooper# dmesg
root@www:/home/trooper#

Now let's add an alias to interface em0:

root@www:/home/trooper# ifconfig em0 alias 85.198.128.1/24 ; while true; do
date +%H:%M:%S; ifconfig em0 | egrep '(media|status)' ; sleep 1s; done
15:44:14
        media: Ethernet autoselect
        status: no carrier
15:44:15
        media: Ethernet autoselect
        status: no carrier
15:44:16
        media: Ethernet autoselect
        status: no carrier
15:44:17
        media: Ethernet autoselect (1000baseTX <full-duplex>)
        status: active

root@www:/home/trooper# ifconfig em0
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=4b<RXCSUM,TXCSUM,VLAN_MTU,POLLING>
        inet 195.24.128.164 netmask 0xfffffff0 broadcast 195.24.128.175
        inet 195.24.128.72 netmask 0xffffffe0 broadcast 195.24.128.95
        inet 85.198.128.1 netmask 0xffffff00 broadcast 85.198.128.255
        ether 00:0e:0c:33:c7:a8
        media: Ethernet autoselect (1000baseTX <full-duplex>)
        status: active

root@www:/home/trooper# dmesg
em0: Link is up 1000 Mbps Full Duplex
root@www:/home/trooper# 

Alias has been added, but interface was reinitialized.
Comment 1 ru freebsd_committer freebsd_triage 2005-05-17 13:06:56 UTC
On Tue, May 17, 2005 at 12:55:57PM +0300, Dmitry Sergienko wrote:
> Network card looses link while adding an alias to interface em0.
> This affects only em0 - neither vlans with vlandev em0, nor fxp0.
> Problem was detected on two different machines with the same netcards
> 
This simple patch works for me:

%%%
Index: if_em.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/em/if_em.c,v
retrieving revision 1.63
diff -u -p -r1.63 if_em.c
--- if_em.c	5 Apr 2005 07:06:47 -0000	1.63
+++ if_em.c	14 Apr 2005 19:03:36 -0000
@@ -832,12 +832,14 @@ em_init_locked(struct adapter * adapter)
         bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
               ETHER_ADDR_LEN);
 
+#if 0
 	/* Initialize the hardware */
 	if (em_hardware_init(adapter)) {
 		printf("em%d: Unable to initialize the hardware\n", 
 		       adapter->unit);
 		return;
 	}
+#endif
 
 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
 		em_enable_vlans(adapter);
%%%


-- 
Ruslan Ermilov
ru@FreeBSD.org
FreeBSD committer
Comment 2 ru freebsd_committer freebsd_triage 2005-05-17 13:10:32 UTC
Responsible Changed
From-To: freebsd-bugs->tackerman

Pass the PR and patch over to an official maintainer.
Comment 3 Dmitry Sergienko 2005-05-17 15:29:55 UTC
Thanks, this patch solved my problem on 5.4-RELEASE. Will also try on 4.10 later.
Hope it will be committed ASAP.

-- 
Best wishes,
Dmitry Sergienko (SDA104-RIPE)
Trifle Co., Ltd.
Comment 4 belaid.aitdahmane 2006-01-19 17:51:43 UTC
The problem seems to be at a higher level : ether_ioctl (net/if_ethersubr.c)

The process when alias is added :

1) in_control (netinet/in.c) :

int
in_control(so, cmd, data, ifp, td)
	struct socket *so;
	u_long cmd;
	caddr_t data;
	register struct ifnet *ifp;
	struct thread *td;
{
...

case SIOCAIFADDR:
...
		if (ifra->ifra_addr.sin_family == AF_INET &&
		    (hostIsNew || maskIsNew))
			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);



2) in_ifinit (netinet/in.c) :

static int
in_ifinit(ifp, ia, sin, scrub)
	register struct ifnet *ifp;
	register struct in_ifaddr *ia;
	struct sockaddr_in *sin;
	int scrub;
{
...
	/*
	 * Give the interface a chance to initialize
	 * if this is its first address,
	 * and to validate the address if necessary.
	 */
	if (ifp->if_ioctl) {
		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);


3) em_ioctl (dev/em/if_em.c) :

static int
em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
...
	case SIOCSIFADDR:
	case SIOCGIFADDR:
		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
		ether_ioctl(ifp, command, data);
		break;


4) ether_ioctl (net/f_ethersubr.c) :

int
ether_ioctl(struct ifnet *ifp, int command, caddr_t data)
{
...
#ifdef INET
		case AF_INET:
			ifp->if_init(ifp->if_softc);	/* before arpwhohas */
			arp_ifinit(ifp, ifa);
			break;
#endif



At this step, the interface is reinitialized  by the driver (em_init is 
registered as the interface init function).

The question is : why do we need to reinitialize the hardware when the 
interface is up and running ?

This behaviour seems to be transparent on some drivers (fxp, bge etc.) 
but certainly not with em.

The patch that follows is inspired by NetBSD code :

*** sys/net/if_ethersubr.c.gen    Thu Jan 19 17:29:40 2006
--- sys/net/if_ethersubr.c    Thu Jan 19 18:17:02 2006
***************
*** 1057,1063 ****
          switch (ifa->ifa_addr->sa_family) {
  #ifdef INET
          case AF_INET:
!             ifp->if_init(ifp->if_softc);    /* before arpwhohas */
              arp_ifinit(ifp, ifa);
              break;
  #endif
--- 1057,1065 ----
          switch (ifa->ifa_addr->sa_family) {
  #ifdef INET
          case AF_INET:
!             /* init only if not running */
!             if ((ifp->if_flags & IFF_RUNNING) == 0)
!                 ifp->if_init(ifp->if_softc);    /* before arpwhohas */
              arp_ifinit(ifp, ifa);
              break;
  #endif


This patch has been tested and is functionnal with fxp, em, bge on 
5.4-STABLE / i386.

It could be applied on 5.x and 6.x (not looked at 4.x).

Belaid Aitdahmane.
Comment 5 Mark Linimon freebsd_committer freebsd_triage 2006-04-05 01:40:15 UTC
State Changed
From-To: open->feedback

Is this still a problem with current versions of FreeBSD? 


Comment 6 Mark Linimon freebsd_committer freebsd_triage 2006-04-05 01:40:15 UTC
Responsible Changed
From-To: tackerman->linimon

Reset PR assigned to inactive committer. 

Hat:	gnats-admin
Comment 7 Mark Linimon freebsd_committer freebsd_triage 2006-09-04 17:31:11 UTC
State Changed
From-To: feedback->suspended

Feedback timeout.  Set to suspended since it contains a patch.
Comment 8 Mark Linimon freebsd_committer freebsd_triage 2007-05-06 01:46:55 UTC
Responsible Changed
From-To: linimon->freebsd-bugs

Return this one to the pool.
Comment 9 Mark Linimon freebsd_committer freebsd_triage 2007-05-08 23:30:12 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

I'm going to reclassify this one.  The original submitter did indeed 
submit a patch, which was kind of hacky; I got no response when asking 
for feedback.  However, a later correspondant noted that this was more of 
a general problem, and submitted a patch against sys/net/if_ethersubr.c. 
Since that patch may need to be evaluated, I'll reassign this to -net.
Comment 10 Andre Oppermann freebsd_committer freebsd_triage 2010-08-23 19:21:16 UTC
Responsible Changed
From-To: freebsd-net->jfv

Over to maintainer.
Comment 11 Mark Linimon freebsd_committer freebsd_triage 2015-11-12 07:42:29 UTC
Reassign to erj@ for triage.  To submitter: is this issue still relevant?