# how to get notified when an interface goes down !



## bsd_newbie (Feb 23, 2009)

In my C program I keep a linked list of interfaces which are up...
I need a way to get notified when an interface goes down, so that I can delete the interface from this list.

Is there anyway to do this, without having to maintain messy linked lists in the code itself...

-newbie


----------



## crsd (Feb 24, 2009)

just an idea: devd forwards all device events to /var/run/devd.pipe UNIX socket, you could try reading and parsing events from there. check devctl(4) also


----------



## Mel_Flynn (Feb 27, 2009)

check kqueue(2), specifically EVFILT_NETDEV.


----------



## bsd_newbie (Feb 28, 2009)

Okay, so I have the following program, that means I will have to issue kqueue for each and every interface on the system ?
Other thing is I will have to know the exact location of the device file that corresponds to my network interface...it would
be nice to be just able to give a bunch of interfaces like ipw0,
em0 etc...

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>

int
main(void)
{
   int f, kq, nev;
   struct kevent change;
   struct kevent event;

   kq = kqueue();
   if (kq == -1)
       perror("kqueue");

   f = open("/dev/net/ipw0", O_RDONLY);
   if (f == -1)
       perror("open");
   EV_SET(&change, f, EVFILT_NETDEV,
          EV_ADD | EV_ENABLE | EV_ONESHOT,
          NOTE_LINKUP | NOTE_LINKDOWN | NOTE_LINKINV,
          0, 0);

   for (; {
       nev = kevent(kq, &change, 1, &event, 1, NULL);
       if (nev == -1)
           perror("kevent");
       else if (nev > 0) {
           if (event.fflags & NOTE_LINKUP)
               printf("link up\n");
           if (event.fflags & NOTE_LINKDOWN)
               printf("Link down\n");
       }
   }

   close(kq);
   close(f);
   return EXIT_SUCCESS;
}


----------



## trev (Feb 28, 2009)

bsd_newbie said:
			
		

> Other thing is I will have to know the exact location of the device file that corresponds to my network interface...it would be nice to be just able to give a bunch of interfaces like ipw0,em0 etc...



You could hard code the interface/driver value pairs in a header file, but I would think it'd be more elegant and extensible to parse a text configuration file.


----------



## bsd_newbie (Feb 28, 2009)

Thanks trev.

Okay, so this way I guess I can watch multiple interfaces.

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>

int
main(void)
{
   int fd[2], kq, nev;
   struct kevent change[2];
   struct kevent event[2];
   int i;

   kq = kqueue();
   if (kq == -1)
       perror("kqueue");

   fd[0] = open("/dev/net/ipw0", O_RDONLY);
   if (fd[0] == -1)
       perror("open");

   fd[1] = open("/dev/net/em0", O_RDONLY);
   if (fd[1] == -1)
       perror("open");

   for (i = 0; i < 2; i++) {
      EV_SET(&change_, fd, EVFILT_NETDEV,
             EV_ADD | EV_ENABLE | EV_ONESHOT,
             NOTE_LINKUP | NOTE_LINKDOWN | NOTE_LINKINV,
             0, 0);
    }


   while (1) {
       nev = kevent(kq, change, 2, event, 2, NULL);
       if (nev == -1)
           perror("kevent");
       else if (nev > 0) {
           for (i = 0; i < nev; i++) {
               if (event.fflags & NOTE_LINKUP)
                   printf("link up\n");
               if (event.fflags & NOTE_LINKDOWN)
                   printf("Link down\n");
           }
       }
   }

   close(kq);
   return EXIT_SUCCESS;
}_


----------



## trev (Feb 28, 2009)

You are missing 
	
	



```
#include <unistd.h>
```
 for close() and also the event for NOTE_LINKINV.


```
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <unistd.h>

int
main(void)
{
int fd, kq, nev;
struct kevent change, event;

kq = kqueue();
if (kq == -1)
        perror("kqueue");

fd = open("/dev/net/re0", O_RDONLY);
if (fd == -1)
        perror("open");

EV_SET(&change, fd, EVFILT_NETDEV,
        EV_ADD | EV_ENABLE | EV_ONESHOT,
        NOTE_LINKUP | NOTE_LINKDOWN | NOTE_LINKINV,
        0, 0);

for (;;) 
        {
        nev = kevent(kq, &change, 1, &event, 1, NULL);
        if (nev < 0)
                perror("kevent");
        else if (nev >= 0) 
                {
                        if (event.fflags & NOTE_LINKUP)
                                printf("Link up\n");
                      
                        if (event.fflags & NOTE_LINKDOWN)
                                printf("Link down\n");

                        if (event.fflags & NOTE_LINKINV)
                                {
                                printf("Link state invalid: %i\n", event.fflags);
                                sleep(3);
                                }
                }
        }

close(kq);
return EXIT_SUCCESS;
}
```

The only problem with this approach is that, at least on my system, marking an interface as down, is not detected. Marking an interface as up is detected as a link down followed by a link up.

Watching the port on the switch, when an interface is marked as down, the link and speed LEDs do not go out, but when marking it up, they do go out just before returning.

Hmmmm.


----------



## bsd_newbie (Mar 3, 2009)

Mel_Flynn said:
			
		

> check kqueue(2), specifically EVFILT_NETDEV.



It seems this kqueue and evflt_netdev mechanism does not work for virtual interfaces - I had couple of tunnel interfaces and when I did a ifconfig down and up on them, no notification was received.

This is so in 6.2, not sure about other releases.


----------

