5

we are trying to add a static ARP entry to a FreeBSD system. This works well with, for example,

arp -S 172.16.16.9 11:54:33:A8:B2:6B

. We have added this to a startup script to survive a reboot. So far so good.

However, if the physical link is cycled, the permanent ARP entry is flushed, too. Does anybody know of

a. A good way to prevent this or

b. A good way to re-add on link-up or

c. A better way altogether?

4
  • 2
    You didn't need to write a startup script. This is what static_arp_pairs in /etc/rc.conf is for.
    – JdeBP
    Mar 19, 2018 at 22:53
  • 2
    in /etc/rc.conf just add the arp pair you want? static_arp_pairs="foo" and static_arp_foo="1.2.3.4 11:22:33:44:55:66"
    – ColtonCat
    Mar 20, 2018 at 4:00
  • I came across this; the documentation was sparse on this. It it possible to use this in a script in /etc/rc.conf.d/* also?
    – namezero
    Mar 20, 2018 at 6:56
  • Do static_arp_pairs survive link cycles?
    – namezero
    Mar 20, 2018 at 16:24

1 Answer 1

6

Becoming friends with FreeBSD

You seem to be on a partially correct path. I presume you have a lot of knowledge on Unix but not so much an actual FreeBSD system. The reason I am guessing this is you have approached it in a slightly different way than the typical user of rc.d in FreeBSD.

I find the question a bit thin as I personally would rather chase why the arp goes missing. But we are given precious little information. Instead we jump to conclusions. They do however pose some interesting questions on how to do stuff on FreeBSD. Just bear in mind the huge caveat emptor that we might end up using a wrench as a hammer.

Writing rc scripts

The FreeBSD startup scripts live in /etc/rc.d but you should never create anything there but leave that directory to the Operating System. Otherwise you risk having your things overwritten during an update. If you want to write your own startup/daemon/service scripts then the best location would be in /usr/local/etc/rc.d

Recommended file locations are documented in hier

And rather than writing everything from scratch you can get a lot of helper functions by reading Practical rc.d scripting in BSD

/etc/rc.conf.d/*

You ask in a comment if you can use it in a script in /etc/rc.conf.d/*. Please please do not do this. Files from here are sourced at startup - but the purpose for this directory is to have small snippets with configuration settings (see rc.conf). Most people simply use the file /etc/rc.conf to configure the system options - but you can split these into small segments and put them into /etc/rc.conf.d even though it is not as common.

It would be better to put your more generic statup script in /etc/rc.local which is still supported. But I would still recommend creating a proper rc script and put it in /usr/local/etc/rc.d

If you want to ignore rc scripts altogether another common way to start a generic script at boot is to use the @reboot keyword in crontab

I would however say that you do not need to create a new rc script as the functionality is already there.

static_arp

Static arp is actually well documented - it is however very simple. The "missing" documentation might be how rc scripts are handled. It is documented in rc.conf:

 static_arp_pairs
     (str) Set to the list of static ARP pairs that are to be
     added at system boot time.  For each whitespace separated
     element in the value, a static_arp_<element> variable is
     assumed to exist whose contents will later be passed to a
     ``arp -S'' operation.  For example

     static_arp_pairs="gw"
     static_arp_gw="192.168.1.1 00:01:02:03:04:05"

This means that you can add 3 static arp entries which will survive reboot by adding these lines to /etc/rc.conf (I recommend using the sysrc command):

static_arp_pairs="a b c"
static_arp_a="1.2.3.4 11:22:33:44:55:66"
static_arp_b="1.2.3.5 22:33:44:55:66:77"
static_arp_c="1.2.3.6 33:44:55:66:77:88"

Or in your specific case:

static_arp_pairs="myarp"
static_arp_myarp="172.16.16.9 11:54:33:A8:B2:6B"

The script handling this is part of the OS and is placed in /etc/rc.d/static_arp and is very simple. It only supports "start" and "stop" commands.

You can call it from anywhere using:

/etc/rc.d/static_arp start

But I would prefer using the service command:

service static_arp start

If for some reason you feel tempted to edit/change /etc/rc.d/static_arp then please do not! Root is omnipotent and you can do what you want - but you risk it will be replaced. What you should do is cp /etc/rc.d/static_arp /usr/local/etc/rc.d/mystatic_arp and have the modified version live there. Notice the name change and make sure it is reflected within the script!

Recycling physical link

If you are used to other systems you might simply be taking the interface up/down using ifconfig. But on FreeBSD you should consider using:

service netif restart <interface>

I have honestly not tested if this brings the static_arp along as well. Or something along the lines of:

service netif stop <interface>
...
service netif start <interface>
service routing restart
service static_arp start

But cycling the physical link could be (un)plugging the cable? Again I am not sure what happens to the arp table then. I would expect it to still be in place as we have not put down the interface administratively.

UPDATE: @namezero has confirmed in a comment that arp entires set with static_arp do survive physical disconnects.

But we should examine this a little further to fully understand your case. This is then as close as I can get to answer "a. A good way to prevent this"

cron

If we get no notification of the physical link - then I do not see a better way than monitoring it. If we keep the script simple - then we can leave it to a regular cron.

devd to the rescue

If we are able to see the change from the OS then we have a nice path forward. The device state change daemon devd comes in handy. Your description is lacking so I will then assume that we either have a LINK_UP or a LINK_DOWN to act on.

Create the file /etc/devd/interface.conf with the content:

notify 0 {
    match "system"        "IFNET";
    match "subsystem"     "(em0|em1)";
    match "type"          "LINK_DOWN";
    action "/usr/local/sbin/alertme.sh $subsystem"
}

This will notify you for the network interfaces em0 and em1.

So it could be as simple as:

notify 0 {
    match "system"        "IFNET";
    match "subsystem"     "(em0|em1)";
    match "type"          "LINK_UP";
    action "/etc/rc.d/static_arp start"
}

This does however feel a bit of a kludge to me as I would spend more time discovering why the arp entries are missing. But I hope these different pointers can get you in "some" direction.

Summary

This brings us to this shortlist which outlines how you can live a happier life with FreeBSD:

  • System settings should live in /etc/rc.conf
  • If you want your own rc scripts put them in /usr/local/etc/rc.d
  • If you want a simple startup script put it in /etc/rc.local (you can source rc if you want)
  • If you want a truly generic script at startup use @reboot with crontab
  • Use sysrc when editing /etc/rc.conf
  • Use service when interacting with rc scripts
  • Use devd acting on device state changes
3
  • Excellent answer, thank you! I was also just now reading about the devd part, was about to post this as the solution to re-adding on physical link failure. Note that this usually shouldn't be an issue on a VM guest, but if for some reason this ever happens and then the ARP entry is missing someone will take their sweet time to debug the issue!
    – namezero
    Mar 20, 2018 at 16:44
  • And thank you for the excellent summary on how to handle rc scripts (locations) in FreeBSD!
    – namezero
    Mar 20, 2018 at 16:47
  • I'd like to add that using static_arp_pairs survives a physical link cycle (well, connect/disconnect on VMWare anyway :} ), unlike arp -S that are manually added which do not.
    – namezero
    Mar 21, 2018 at 11:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .