Keep Ethernet Interfaces Down At Boot?

Hey gang -

I'm working on a little challenge here and my search-fu is failing me. The challenge: I want my machine's second Ethernet interface (em1) to stay down when I first boot. However, I do want it to have an IPv6 link_local at the ready. After the machine boots, I'll kick off a process that will do some checking and ifconfig the interface up; that's easy peazy. The thing I'm having trouble figuring out: is there an "ifconfig_em1" line I can add to the rc.conf file that will keep the interface DOWN? Or is that not doable?

I've tried:
Code:
ifconfig_em1_ipv6="inet6 -ifdisabled"
ifconfig_em1="down"

...and no love. The interface is UP when the machine boots. Any other ideas?

Thanks!
 
How can it have an IPv6 address if the interface is down? Can you explain what you mean with "have an IPv6 link-local at the ready"?
 
How can it have an IPv6 address if the interface is down? Can you explain what you mean with "have an IPv6 link-local at the ready"?

OK, long story longer:

The goal here is that I'm running Free Range Routing and doing an interface BGP peer with the upstream Cumulus switch. BGP unnumbered is all handled via the v6 link-local address, so a v4 address isn't required. What I specifically don't want happening is for the BGP peering to come up before other checking on the server has been performed. But it will if the interface is up; as soon as link is up, the peer will establish.

So, I'd like the server to boot, have interface em1 ready to go with a v6 link-local (only a link-local), but be shutdown via /etc/rc.conf. Is that even doable?
 
If you want to keep the BGP peering down till after some checks, you could indeed keep the interface down - but then it won't get an IPv6 address - or you could not auto-start your BGP daemon on boot-up and only start if after your checks completed successfully. Perhaps that is the better solution?
 
is there an "ifconfig_em1" line I can add to the rc.conf file that will keep the interface DOWN?
Yes, you need to have the keyword `NOAUTO' in your ifconfig_<interface>. Read rc.conf() for more information.

I want my machine's second Ethernet interface (em1) to stay down when I first boot. However, I do want it to have an IPv6 link_local at the ready
How can the interface apply for an IP when it's down? It doesn't make sense - at least not to my knowledge.
 
If you want to keep the interface down you probably need to write a devd.conf.net file to exclude it.
devd(8) handles more of the 'Link Level" of the device.
Maybe you could disable the interface and then use a /etc/rc.local to bring it up last.
I recently used that method. ifconfig ix0 up && dhclient ix0
My device needed manual intervention to bring it up. Not sure about disabling the device.

You might want to checkout /etc/rc.d/netwait as well. I have modified that to fix my use case..
 
I've been thinking about another way to accomplish the same thing and that involves starting the interface with "inet6 ifdisabled". So it'll come up with no IPv4 or v6 address at all. Then once my healthchecking script kicks in from /etc/rc.local (which is after Apache is running, and the bgpd process is running) it'll go through a "first boot" function before it settles into its main health checking loop. The "first boot" thing will first verify that Apache is, indeed running and answering queries properly, and then it'll go through and set the interface "inet6 -ifdisabled". Once that's done, BGP unnumbered will kick in and the route will be announced.

From that point forward, "ifconfig down" and "ifconfig up" will withdraw or add the route as needed.

I'm going to hack away at that after I get some fud in me and see how far I get.
 
OK, I think I've got it. I've removed all of the interface lines in /etc/rc.conf for ints em1-4. The server boots and none of them have any IP addresses or are up. Apache starts, bgpd starts, and then the healthchecking script is kicked off from /etc/rc.local with a nohup:

Python:
# Loops forever, at an interval defined below, checking the health of the local
# Apache server.  If the server is up, the list of Ethernet interfaces defined
# below will be brought up.  If down, they'll be brought down.
#
# Best to start this with nohup.
#  nohup anycast_healthck.py &
#

import urllib3
import socket
import subprocess
import time

# Some variables we'll be using
server = "172.20.0.1"  # server's IP
httpport = "80"  # server's port (80 or 443)
index = "/index.html" # file we'll grab during the health check
url = "http://" + server + index # URL we'll be grabbing to health check
ifaces = ["em1", "em2", "em3", "em4"] # array of interfaces
service = "down" # we'll start assuming service is down
hc_interval = 5 # health check interval, in seconds

#
# isOpen(IP_addr, Port)
#
# Checks to see if it can open a TCP connection to IP:Port.
# Returns True if it can, False otherwise
def isOpen(ip, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((ip, int(port)))
        s.shutdown(2)
        return True
    except:
        return False

#
# ifUpDown(interfaces[], status)
#
# Loops through the array interfaces[] and enables or disables the int.
#
# status = True - will enable the interface
# status = False - will disable the interface
#
def ifUpDown(interfaces, status):
    if status:
        stat="up"
    else:
        stat="down"

    for iface in interfaces:
        ifconfig_call = "/sbin/ifconfig " + iface + " " + stat
        subprocess.call(ifconfig_call, shell=True)


#
# firstBoot(interfaces[])
#
# Checks to see if Apache is running and then adds IPv6 link-local addresses
# to each of the interfaces[]
#
def firstBoot(interfaces):
    flag = False
    while(not flag):    # Loop while Apache is *NOT* answering; do so every 3 seconds
        if isOpen(server, httpport) and urllib3.PoolManager().request('GET', url).status == 200:
            flag = True
          
        else:
            time.sleep(3)

    # Now that we're sure Apache is answering, add IPv6 to each interface
    for iface in interfaces:
        ifconfig_call = "/sbin/ifconfig " + iface + " inet6 -ifdisabled"
        subprocess.call(ifconfig_call, shell=True)


#
# Call firstBoot first
firstBoot(ifaces)

# Use our isOpen() function along with a URL request to see if:
# A) the server is accepting connections on its HTTP port
#   AND
# B) we can pull the HTML file successfully.
#
# A success on both will mean the server is healthy.
while(not time.sleep(hc_interval)):
    if isOpen(server, httpport) and urllib3.PoolManager().request('GET', url).status == 200:
        if service == "down":  # We currently think the service is down, so turn it up
            ifUpDown(ifaces, True)
            service = "up"
    else:
        if service == "up":  # We currently think the service is up, so turn it down.
            ifUpDown(ifaces, False)
            service = "down"

Yes, I'm the worst python coder in existence. But this does the trick.
 
Awful code. Awful. What a dumb move on my part, flipping interfaces up and down to inject and withdraw routes. Had I spent five minutes looking into FRR's vtysh, I would have found that it can run shell commands with the -c option, like any other shell can. Instead of redistributing connected routes in the static bgpd.conf file, I left the file devoid of any routes or network statements. So the peers will come up but nothing is announced at all.

The health checking script becomes a lot simpler because it just needs to execute a "vtysh -c ....." command to add the prefix if healthy, and withdraw the prefix if not.

Code:
#!/usr/local/bin/python

# Loops forever, at an interval defined below, checking the health of the local
# Apache server.  If the server is up, the list of Ethernet interfaces defined
# below will be brought up.  If down, they'll be brought down.
#
# Best to start this with nohup.
#  nohup anycast_healthck.py &
#
 
import urllib3
import socket
import subprocess
import time

# Some variables we'll be using
server = "172.20.0.1"  # server's IP
httpport = "80"  # server's port (80 or 443)
index = "/index.html" # file we'll grab during the health check
url = "http://" + server + index # URL we'll be grabbing to health check
service = "down" # we'll start assuming service is down
hc_interval = 5 # health check interval, in seconds
route_add = "/usr/local/bin/vtysh -c 'enable' -c 'config term' -c 'router bgp 65300' -c 'network 172.20.0.1/32' -c 'exit' -c 'exit'"
route_del = "/usr/local/bin/vtysh -c 'enable' -c 'config term' -c 'router bgp 65300' -c 'no network 172.20.0.1/32' -c 'exit' -c 'exit'"

#
# isOpen(IP_addr, Port)
#
# Checks to see if it can open a TCP connection to IP:Port.
# Returns True if it can, False otherwise
def isOpen(ip, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((ip, int(port)))
        s.shutdown(2)
        return True
    except:
        return False

# Use our isOpen() function along with a URL request to see if:
# A) the server is accepting connections on its HTTP port
#   AND
# B) we can pull the HTML file successfully.
#
# A success on both will mean the server is healthy.
while(not time.sleep(hc_interval)):
    if isOpen(server, httpport) and urllib3.PoolManager().request('GET', url).status == 200:
        if service == "down":  # We currently think the service is down, so turn it up
            subprocess.call(route_add, shell=True)
            service = "up"
    else:
        if service == "up":  # We currently think the service is up, so turn it down.
            subprocess.call(route_del, shell=True)
            service = "down"

Way better, but it was written by me. So it can probably still be optimized a lot more. :)
 
Back
Top