OpenBSD Journal

User Stories: ifstated & !carp

Contributed by sean on from the laziness is a noble virtue dept.

A long while ago I found myself wondering if I could make my OpenBSD laptop just up and grab an IP whenever I plugged the damned ethernet in.

Most of the time the machine just sits in the basement plugged in and either is building a kernel from the -current tree or the corresponding user land. Occasionally I unplug it to test out something, play with some Soekris boxes or even do actual work. In the event that I unplug the ethernet, I didn't want to have to deal running dhclient manually or at all.

The following is my solution (using ifstated) and how I came by it.

It turns out the solution to my problem is a utility called ifstated which is typically used in CARP situations where you watch when one interface fails, and swap over to another. A bit of example reading (for which there is a dearth on Google), some man page reading and a bit of thinking, I scraped up the following configuration (and put it in /etc/ifstated.conf):

ethernet_up = "xl0.link.up"
ethernet_down = "!xl0.link.up"

state auto {
        if $ethernet_up
                set-state main
}

state main {
        init { # do any network detection you care for here.
                run "dhclient xl0"
        }
        if $ethernet_down {
                run "ifconfig xl0 delete ; route flush >/dev/null"
                set-state auto
        }
}

init-state auto

This is about as simple as I can make it. The first two lines are macros/variables which are not all that necessary in this case but make things a tad more readable. I'm not sure if they can be nested (if so then I could make things easier and note the interface only once).

Then I define the two possible states I wish to handle. The first (auto) is a priming state where I either start out or return to on link failure. All this state does is wait for the interface to come back up so it can switch over to the second state (namely main). This second state can only be reached on a link coming up so we start out by grabbing a dhcp lease. At this state you can do some funky magic (arping et al.) and figure out 'where you are' and setup accordingly, but for my purposes simply running dhclient is sufficient. From this point we stick around in this state until the link fails. Then we reset the interface and go back into the auto state for waitin on another link. This completes the loop and now I don't have to do anything but plug and unplug the cable.

Now that we have a configuration we should probably just use it. This is really easy to as we just invoke ifstated -f /etc/ifstated.conf and we're good to go. A nice way to enable ifstated on boot up is to just add the following to rc.local:

if [ X"${ifstated_flags}" != X"NO" ]; then 
        /usr/sbin/ifstated $ifstated_flags
fi

Then pop the following line in /etc/rc.conf.local

ifstated_flags="-f /etc/ifstated.conf"

At this point you can either reboot or just run ifstated and be up and running.

There are a few things you can do to make this a bit snazzier.
  1. Use the -D flag to set a macro for the relevant interface. Makes things a lot more generic and I would even like to see a similar setup when you install the OS from CD (grab yours in N.A. or world-wide) but that is neither here or there.
  2. Since I also have a wireless card, (whose MAC is used to give it the same IP as the wired NIC) I could setup a more complicated state such that I would flip flop between either NIC based on the link state of the wired ethernet adapter.
  3. Find a way to try using my home wireless AP by default but fall back on a 'scan for open APs' and then connect to the first open AP with the best signal (if there are multiples).

ifstated is a very useful tool, even outside of the typical CARP scenario.

What have use used ifstated for?
How would you improve on my solution?

(Comments are closed)


Comments
  1. By Anonymous Coward (69.70.68.38) on

    I love ifstated!

    Comments
    1. By Anonymous Coward (69.70.68.38) on

      > I love ifstated!

      oops, meant to continue saying... Thanks for ifstated, I can use CARP properly with DHCP and other goodies. I'll try to post my files soon too if anyone wants?

      Comments
      1. By Sean Cody (sean) on I don't work here.

        >oops, meant to continue saying... Thanks for ifstated, I can use CARP
        >properly with DHCP and other goodies. I'll try to post my files soon 
        >too if anyone wants?
        

        Sure! More examples are always welcome.

  2. By Anonymous Coward (70.173.172.228) on

    why do you need the rc.local lines, they are already in rc (since 27-september-2006)?

    Comments
    1. By Xipher (12.219.27.151) on

      > why do you need the rc.local lines, they are already in rc (since 27-september-2006)?

      If you read the manuals you will notice that it is always advised to use rc.conf.local and leave rc.conf alone. This makes upgrades a lot simpler since rc.conf.local won't be touched when you merge the new files.

      Comments
      1. By James (jturner) on http://bsdgroup.org

        > > why do you need the rc.local lines, they are already in rc (since 27-september-2006)?
        >
        > If you read the manuals you will notice that it is always advised to use rc.conf.local and leave rc.conf alone. This makes upgrades a lot simpler since rc.conf.local won't be touched when you merge the new files.

        IF you read the comment you will notice he never once mentioned rc.conf or rc.conf.local. He was referring to the fact the code added to rc.local is already present in rc.

    2. By Kian Mohageri (76.28.214.5) kmuskrat@gmail.com on http://www.zampanosbits.com

      > why do you need the rc.local lines, they are already in rc (since 27-september-2006)?

      You're correct... you could just add:

      ifstated_flags=""

      to /etc/rc.conf.local.

  3. By Anonymous Coward (206.248.190.11) on

    Wasn't this given as an example use of ifstated when it was first introduced? I know I've been using it this way for a few years now and it was nothing new or interesting when I did it. I believe this even inspired the dhclient change that makes old dhclient processes exit when you run dhclient again.

    Comments
    1. By Sean Cody (sean) on I don't work here.

      >Wasn't this given as an example use of ifstated when it was first 
      >introduced?  I know I've been using it this way for a few years now and 
      >it was nothing new or interesting when I did it.  I believe this even 
      >inspired the dhclient change that makes old dhclient processes exit when
      >you run dhclient again.
      

      See the first line of the post, specifically "A long while ago." I didn't see this as an example way back when I dealt with the issue, but if you have a link to said example I'll be happy to add it to the article.

      If you search on Google for "ifstated laptop openbsd" you won't find anything useful (save the man pages which are) and what you do find is old configs with different macro syntax (I looked again before writing the article). This is the reason I wrote it.

      As well, it may not be 'new or interesting' to you but the article isn't targeted to you. It is targeted to those who might not have seen this before.

      Comments
      1. By Anonymous Coward (24.175.151.223) on

        > If you search on Google for "ifstated laptop openbsd" you won't find anything useful (save the man pages which are) and what you do find is old configs with different macro syntax (I looked again before writing the article). This is the reason I wrote it.

        Isn't "ifstated laptop openbsd" too strict of a search? Is this really specific to laptops? Why not just "ifstated openbsd dhclient" or "ifstated ethernet openbsd" or "ifstated \"physical interface\" openbsd"?

        Comments
        1. By sean (24.77.212.94) on


          > Isn't "ifstated laptop openbsd" too strict of a search? Is this really
          >specific to laptops? Why not just "ifstated openbsd dhclient" or
          >"ifstated ethernet openbsd" or "ifstated \"physical interface\" openbsd"?

          Yes, I tried other variants and key sets as well. This was only an example. But you are correct.


  4. By Anonymous Coward (204.80.187.5) on

    How do you kill dhclient when the ethernet port goes down? With the config you have now, if you unplugged/plugged 5 times, you would have 5 dhclient processes running, right ?

    Comments
    1. By Sean Cody (sean) on I don't work here.

      > How do you kill dhclient when the ethernet port goes down? With the > config you have now, if you unplugged/plugged 5 times, you would have 5 > dhclient processes running, right ?

      That used to be the case and you would have to kill it manually. Since then dhclient was modified to close on link down.

      Comments
      1. By Anonymous Coward (24.37.242.64) on

        >
        > How do you kill dhclient when the ethernet port goes down? With the
        > config you have now, if you unplugged/plugged 5 times, you would have 5
        > dhclient processes running, right ?
        >
        >
        > That used to be the case and you would have to kill it manually.
        > Since then dhclient was modified to close on link down.

        Cool, I never noticed that it does that.

        Also, if not, or for other scenarios that would need the process to be killed manually, there's always the 'pkill' option too that can be added to such a script. :-)

        Nice article btw...

        I guess this can also be easily extended for 'wired' and 'wireless' too so that when it's plugged into say the corporate network, it runs dhclient on the wired network, when at home with wireless detected, dhclient kicks in over the wireless link or such..

  5. By Anonymous Coward (63.163.107.100) on

    Total newbie question: looking at the example, it looks like the interface name is a prime candidate for factoring. Would the following (or something like it) work?
    if = "x10"
    ethernet_up = $if ".link.up"
    ethernet_down = "!" $if ".link.up"
    
    state auto {
            if $ethernet_up
                    set-state main
    }
    
    state main {
            init { # do any network detection you care for here.
                    run "dhclient " $if
            }
            if $ethernet_down {
                    run "ifconfig " $if " delete ; route flush >/dev/null"
                    set-state auto
            }
    }
    
    init-state auto
    

    Comments
    1. By sean (24.77.212.94) on

      > Total newbie question: looking at the example, it looks like the interface name is a prime candidate for factoring. Would the following (or something like it) work?
      >
      >
      Tried that initially and it didn't work. Frequent 'syntax errors.'

      Comments
      1. By Anonymous Coward (24.37.242.64) on

        > > Total newbie question: looking at the example, it looks like the interface name is a prime candidate for factoring. Would the following (or something like it) work?
        > >
        > >
        > Tried that initially and it didn't work. Frequent 'syntax errors.'
        >

        I think it's because they're macros in the .conf file (a non-shell script) instead of variables defined in a shell script, but there's ways around this too with the 'run' option...

  6. By Anonymous Coward (212.214.242.94) on

    >> Since I also have a wireless card, (whose MAC is used to give it the same IP as the wired NIC) I could setup a more complicated state such that I would flip flop between either NIC based on the link state of the wired ethernet adapter.

    How about using trunk(4) with failover for that?

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]