LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (https://www.linuxquestions.org/questions/slackware-14/)
-   -   Why MAXNICS=${MAXNICS:-6} in rc.inet1.conf? (https://www.linuxquestions.org/questions/slackware-14/why-maxnics%3D%24%7Bmaxnics-6%7D-in-rc-inet1-conf-4175485819/)

slackcode 11-25-2013 07:57 AM

Why MAXNICS=${MAXNICS:-6} in rc.inet1.conf?
 
Code:

############################
# DETERMINE INTERFACE LIST #
############################

# Compose a list of interfaces from /etc/rc.d/rc.inet1.conf (with a maximum
# of 6 interfaces, but you can easily enlarge the interface limit
# - send me a picture of such a box :-).
# If a value for IFNAME[n] is not set, we assume it is an eth'n' interface.
# This way, the new script is compatible with older rc.inet1.conf files.
# The IFNAME array will be used to determine which interfaces to bring up/down.
MAXNICS=${MAXNICS:-6}
i=0
while [ $i -lt $MAXNICS ];
do
  IFNAME[$i]=${IFNAME[$i]:=eth${i}}
  i=$(($i+1))
done
if [ "$DEBUG_ETH_UP" = "yes" ]; then
  echo "/etc/rc.d/rc.inet1:  List of interfaces: '${IFNAME[@]}'" | $LOGGER
fi

I have a situation that need more than 6 (Maybe 7).
I set an ip address and it can't be valid until I ifconfig that.

Finally, I found this code in rc.inet1.
I want to know why the number is 6? Is it about the performance or any other reason?
Thx.

guanx 11-25-2013 08:14 AM

Pre-vacuum-tube computers take a lot of time to loop through large number of empty setups. This is the evidence of slackware being the oldest surviving Linux distribution.

slackcode 11-25-2013 08:22 AM

Quote:

Originally Posted by guanx (Post 5070322)
Pre-vacuum-tube computers take a lot of time to loop through large number of empty setups. This is the evidence of slackware being the oldest surviving Linux distribution.

Yes, I agree. Maybe I can cut some IPs : )

Didier Spaier 11-25-2013 08:29 AM

However high the limit, someone will find it too low.

GazL 11-25-2013 09:17 AM

... which is reason to avoid having a arbitrary limit. ;)

A long while ago I wrote myself an rc.inet1 replacement modeled on the OpenBSD approach.

It cycles through the interfaces listed on it's args, or if none, the interfaces it finds in /proc/net/dev and if it finds a corresponding /etc/hostname.<interface> file uses that to configure the interface. I find this much easier to work with than the stock rc.inet1 + rc.inet1.conf approach, which has always seemed a little unwieldy to me.

The config files looks like this:
Code:

root@ws1:~# cat /etc/hostname.eth0
inet 192.168.0.2
!route add default gw 192.168.0.1
root@ws1:~#

As you can see, it also allows static routes to be kept with the associated interface config, which keeps things nice and tidy. To use dhclient, the file simply needs contain the word 'dhcp'. I've not fleshed it out to support wifi yet, but a "!wpa_supplicant blah blah...." line before a "dhcp" line ought to do the job.

slackcode 11-25-2013 09:46 AM

Quote:

Originally Posted by GazL (Post 5070348)
... which is reason to avoid having a arbitrary limit. ;)

It cycles through the interfaces listed on it's args, or if none, the interfaces it finds in /proc/net/dev and if it finds a corresponding /etc/hostname.<interface> file uses that to configure the interface. I find this much easier to work with than the stock rc.inet1 + rc.inet1.conf approach, which has always seemed a little unwieldy to me.

As you can see, it also allows static routes to be kept with the associated interface config, which keeps things nice and tidy. To use dhclient, the file simply needs contain the word 'dhcp'. I've not fleshed it out to support wifi yet, but a "!wpa_supplicant blah blah...." line before a "dhcp" line ought to do the job.

Normally, I think it is simple if I configure all interfaces in one file. If move the interfaces to multiple files, I need to configure them in multiple place.
I think rc.inet1.conf can be scanned to summate amout of the interfaces, but it seems ugly and not KISS.

gnashley 11-25-2013 11:33 AM

GazL, can you post your replacement for rc.inet1?

GazL 11-25-2013 12:34 PM

I can remember we've talked about this sort of thing in the past, so I suspect you may have already seen it, but I'll attach it here anyway. It's not particularly sophisticated, but that's why I like it ;)


BTW, if anyone tries it out, don't forget to create a /etc/hostname.lo containing "inet 127.0.0.1" ;)

wildwizard 11-26-2013 03:10 PM

Quote:

Originally Posted by slackcode (Post 5070324)
Yes, I agree. Maybe I can cut some IPs : )

If the problem originates from having extra IP's and not actual interfaces then I think I can help.

I have below rc.inet1 and rc.inet1.conf that I use, the IP addresses used are in CIDR notation and the setup no longer uses net masks (ignore the ones in the conf they are not used.)

To add extra IP's on an interface you simply separate them with spaces so you could have the following :-

Code:

IPADDR[0]="192.168.10.10/24 192.168.10.11/24 192.168.10.12/24 192.168.10.13/24 10.0.0.1/24"
and the first interface would have 5 IP's.

http://wildwizard.abnormalpenguin.co...lackware/rc.d/

WiseDraco 11-29-2013 07:52 AM

Quote:

Originally Posted by guanx (Post 5070322)
Pre-vacuum-tube computers take a lot of time to loop through large number of empty setups. This is the evidence of slackware being the oldest surviving Linux distribution.

if i remember correctly, about a years 2003 - 2005 i have linux slackware ( 10.0 or so on version) based firewall \ router with 7 NIC. i do not change anything in rc.inetd1 - maybe then there are not that string?

eduardr 03-26-2022 08:11 PM

Suggest to increase to 10 at least, in the default config
 
It took me almost an hour to again figure out the solution to this problem (previously I knew about this but forgot years ago).

Had to uncomment and set MAXNICS="8" in /etc/rc.d/rc.inet1.conf

There are many servers out there which come standard with more than 6 built-in ports. Even my little server (https://www.supermicro.com/en/produc...YS-E300-8D.cfm) has 8 built-in network interfaces.

Ideal solution would be for rc.inet1 to deal with any # of interfaces, without having to hardcode a specific #.

Failing that, would suggest Slackware to default to 10 interfaces, instead of 6 - that would cover many more servers by default, without "new players" (and old players) falling into this very difficult-to-debug trap. Really got lucky here that I was able to drag out this knowledge from my head that I forgot so long ago.

tadgy 03-26-2022 11:23 PM

This question has come up before.

The problem with trying to handle any number of interfaces is that bash does not have an expansion for providing the highest indices of an array.

You can easily determine the number of elements of an array in bash (${#ARRAY[*]}), but lets say you define your interfaces as follows:
Code:

IFNAME[0]="eth0"
IPADDRS[0]="192.168.1.1"
IFNAME[1024]="eth1"
IPADDRS[1024]="10.0.0.1"

(note the array indices numbers)
which is perfectly legal syntax in both bash and the rc.inet1.conf file.

In order to make sure both the interfaces get assigned, you need to know the highest indices in order to know when to stop processing. You can't just look for an empty definition for IPADDRS and stop there as there are 'holes' in the array where that indices is not defined. You also cannot loop forever just in case someone defined a stupidly high number. And every iteration of the loop costs real time, which undoubtedly slows down rc.inet1 to a point where people would complain that their system takes longer to boot.

So, we need somewhere to stop the loop. Historically this was after 6 iterations. When I re-wrote rc.inet1 for 15.0, I kept that "tradition", as is the Slackware way. I also kept in Pat's original comment regarding sending him a picture for the same reason :)

I agree that a lot of systems these days are going to have more than 6 interfaces (or more than 6 interface definitions, as virtual interfaces and bonds also count in rc.inet1.conf) and MAXNICS could realistically be set higher these days - Pat may even accept a patch to raise it if you submit one.

I kept the tradition of 6. It's really as simple as that. But, setting it too high is going to slow down processing of rc.inet1 during boot. Also, where do you set the value? Everyone and their dog is going to have an opinion on what the value should be - and have arguments as to why it should be that high because their server has X interfaces, when yours only has X-1.

So, that's it really. That's the rationale as to why I kept it at 6 - but try your luck with a patch to Pat...

Sorry for the long post, but I thought it worthwhile to put this issue to bed once and for all :)

allend 03-27-2022 09:38 AM

Quote:

bash does not have an expansion for providing the highest indices of an array
You can use the ${!IFNAME[@]} construction to get a list of the indices and assign that to an array.
My suggestion for this.
Code:

# diff -u3 a/rc.inet1 b/rc.inet1
--- a/rc.inet1  2022-03-28 01:10:55.693900246 +1100
+++ b/rc.inet1  2022-03-28 01:31:22.430882036 +1100
@@ -49,11 +49,13 @@
 # If a value for IFNAME[n] is not set, we assume it is an eth'n' interface.
 # This way, the new script is compatible with older rc.inet1.conf files.
 # The IFNAME array will be used to determine which interfaces to bring up/down.
-MAXNICS=${MAXNICS:-6}
+MAXNICS=${#IFNAME[@]}
+NICINDEX=( ${!IFNAME[@]} )
 i=0
 while [ $i -lt $MAXNICS ];
 do
-  IFNAME[$i]=${IFNAME[$i]:=eth${i}}
+  j=${NICINDEX[$i]}
+  IFNAME[$j]=${IFNAME[$j]:=eth${j}}
  i=$((i+1))
 done
 debug_log "List of interfaces: ${IFNAME[*]}"
@@ -245,7 +247,7 @@
  # Determine position 'i' of this interface in the IFNAME array:
  i=0
  while [ $i -lt $MAXNICS ]; do
-    [ "${IFNAME[$i]}" = "${1}" ] && break
+    [ "${IFNAME[${NICINDEX[$i]}]}" = "${1}" ] && break
    i=$((i+1))
  done
  # If "i" is greater or equal to "MAXNICS" at this point, it means we didn't
@@ -539,7 +541,7 @@
  # Determine position 'i' of this interface in the IFNAME array:
  i=0
  while [ $i -lt $MAXNICS ]; do
-    [ "${IFNAME[$i]}" = "${1}" ] && break
+    [ "${IFNAME[${NICINDEX[$i]}]}" = "${1}" ] && break
    i=$((i+1))
  done
  if [ $i -ge $MAXNICS ]; then


tadgy 03-27-2022 12:29 PM

Nice, that'll work :)

I'll create a full patch to do as you suggest and remove the MAXNICS setting from rc.inet1.conf. Hopefully Pat won't mind such a minor change.

Markus Wiesner 03-27-2022 01:34 PM

Quote:

Originally Posted by allend (Post 6341877)
You can use the ${!IFNAME[@]} construction to get a list of the indices and assign that to an array.

Currently IFNAME[X] is not empty but unset by default. So you could use that only after IFNAME[X] has been initialized to "ethX" (where required).

Quote:

Originally Posted by allend (Post 6341877)
MAXNICS=${#IFNAME[@]}

This will unfortunately also fail when the array has gaps because "#" does not count unset indexes:

Code:

$ unset IFNAME
$ IFNAME[8]="foo"
$ echo "${IFNAME[@]@A}"
declare -a IFNAME=([8]="foo")
$ echo "${#IFNAME[@]}"
1


tadgy 03-27-2022 06:32 PM

Good points.

I didn't check the patch in the context of the full rc.inet1, which I really should have done and spotted the same problems.

I knew there were reasons it wasn't as simple as it seemed :)

luvr 03-28-2022 04:36 AM

Quote:

Originally Posted by Markus Wiesner (Post 6341951)
This will unfortunately also fail when the array has gaps because "#" does not count unset indexes:

I think I’m missing the point here. Isn’t that the whole point of this exercise in the first place? You want to obtain the list (or, actually the array) of indexes of the initialized array elements, so that you can loop through them and process those elements that were set up, don’t you?
I must be missing something blatantly obvious that’s probably immediately clear to more intelligent people than me, as I’m known to do at times. :confused: Please enlighten me.

GazL 03-28-2022 05:11 AM

Using associative arrays would make this a whole lot nicer and avoids the "index gaps" issue completely:
Code:

declare -A address netmask
address[eth0]=192.168.0.1
netmask[eth0]=255.255.255.0
address[eth1]=10.0.0.1
netmask[eth1]=255.0.0.0

for interface in ${!address[@]}
do
  echo ifconfig $interface ${address[$interface]} netmask ${netmask[$interface]}
done


Markus Wiesner 03-28-2022 06:30 AM

Quote:

Originally Posted by luvr (Post 6342079)
I think I’m missing the point here. Isn’t that the whole point of this exercise in the first place? You want to obtain the list (or, actually the array) of indexes of the initialized array elements, so that you can loop through them and process those elements that were set up, don’t you?

But IFNAME[] is by default not initialized, that's currently done with

Code:

MAXNICS=${MAXNICS:-6}
i=0
while [ $i -lt $MAXNICS ];
do
  IFNAME[$i]=${IFNAME[$i]:=eth${i}}
  i=$((i+1))
done

Setting MAXNICS=${#IFNAME[@]} won't work at that point because ${#IFNAME[@]} is still 0 (unless you manually set it for some interfaces). You would have to add IFNAME[X]="" (an empty value would also be overwritten with ethX) for every interface in /etc/rc.d/rc.inet1.conf – and even then ${#IFNAME[@]} is still error-prone because you will get the wrong number if you accidentally leave a gap somewhere.

tadgy 03-28-2022 08:27 AM

Quote:

Originally Posted by GazL (Post 6342087)
Using associative arrays would make this a whole lot nicer and avoids the "index gaps" issue completely:
Code:

declare -A address netmask
address[eth0]=192.168.0.1
netmask[eth0]=255.255.255.0
address[eth1]=10.0.0.1
netmask[eth1]=255.0.0.0

for interface in ${!address[@]}
do
  echo ifconfig $interface ${address[$interface]} netmask ${netmask[$interface]}
done


This would have required a major - non backwards compatible - change to the format of rc.inet1.conf, which I'm pretty sure wouldn't have made it past Pat :)

I agree that the newer features of bash can be used to make things a lot simpler in rc.inet1, and everyone probably has ideas on how to change it - but backwards compatibility was key when re-writing things. A pre-15.0 rc.inet1.conf will still work without any changes if you don't want to use any of the new features I added; but to use the new post-15.0 feature set you need to re-run netconfig.

tadgy 03-28-2022 08:31 AM

Quote:

Originally Posted by Markus Wiesner (Post 6342099)
But IFNAME[] is by default not initialized, that's currently done with

Code:

MAXNICS=${MAXNICS:-6}
i=0
while [ $i -lt $MAXNICS ];
do
  IFNAME[$i]=${IFNAME[$i]:=eth${i}}
  i=$((i+1))
done

Setting MAXNICS=${#IFNAME[@]} won't work at that point because ${#IFNAME[@]} is still 0 (unless you manually set it for some interfaces). You would have to add IFNAME[X]="" (an empty value would also be overwritten with ethX) for every interface in /etc/rc.d/rc.inet1.conf – and even then ${#IFNAME[@]} is still error-prone because you will get the wrong number if you accidentally leave a gap somewhere.

Yes, I recall now that this was the issue with removal of MAXNICS.

In order to check that an indices doesn't contain any sort of interface definition, you have to check every possible variable that might be used to configure some sort of interface - IPADDR, IPADDRS, IP6ADDRS, BRNICS, BONDNICS, etc, etc. That would be really messy and prone to errors should any new arrays be added to the rc.inet1.conf syntax.

ozanbaba 03-28-2022 08:36 AM

Don't forget to send the picture of the box to Pat.

eduardr 03-28-2022 08:14 PM

If all else fails
 
1 Attachment(s)
Quote:

Originally Posted by ozanbaba (Post 6342126)
Don't forget to send the picture of the box to Pat.

(attached - it doesn't have to be a 100 kg 10U server to have so many net ports any more)


If all else fails, moving `# MAXNICS="SOMETHING"` to the TOP, instead of the BOTTOM, of /etc/rc.d/rc.inet1.conf, would go a looooong way to giving users a tiny bit of a fighting chance to get interface 7, or 8, or 9, up and running, instead of being hopelessly confused about what the problem is (could also be included as a config item in `netconfig` but I'd guess that much less likely to happen than a change to the config file template).

tadgy 03-28-2022 10:01 PM

Quote:

Originally Posted by eduardr (Post 6342297)
If all else fails, moving `# MAXNICS="SOMETHING"` to the TOP, instead of the BOTTOM, of /etc/rc.d/rc.inet1.conf, would go a looooong way to giving users a tiny bit of a fighting chance to get interface 7, or 8, or 9, up and running, instead of being hopelessly confused about what the problem is

Um, what sort of user doesn't read the entire configuration file if they are manually applying settings?

Sure, you've got an excuse if you're just relying on netconfig to set up the one interface, but if you are going in to manually add more you should also be reading the entire file... that's just common sense, really :)

eduardr 03-28-2022 10:18 PM

This sort
 
Quote:

Originally Posted by tadgy (Post 6342307)
Um, what sort of user doesn't read the entire configuration file if they are manually applying settings?

The sort that replies to this message :).

I always use netconfig, then I always check the first few ethX sections if anything doesn't work.

I never go to the bottom (and the bottom 3/4 of the file are commented out stuff). I've been using Slackware for 15 years. That's not to brag. That's to say even after all this time, this particular MAXNICS setting is hidden and very hard to find and very hard to debug when exceeding the default value.

Putting it to the TOP would be a big benefit - it's impossible to miss there, and it clearly says to any user "hey dummy, here's how many nics rc.inet1 will look for".

I don't think the rc script will change, and I don't think netconfig will change. The easiest suggestion is to move this setting to the TOP. Thanks!

tadgy 03-28-2022 11:02 PM

You may be right... :)

I'll add it to my mental TODO list!

karlmag 03-30-2022 06:03 PM

How about this one?
(against today's -current64 rc.inet1)

Code:

bash-5.1$ cat rc.inet1-unlimited-maxnics-current-20220330.patch
--- rc.inet1    2022-03-31 00:15:54.375308718 +0200
+++ rc.inet1.karlmag        2022-03-31 00:21:48.299410504 +0200
@@ -42,7 +42,17 @@ debug_log() {
 # If a value for IFNAME[n] is not set, we assume it is an eth'n' interface.
 # This way, the new script is compatible with older rc.inet1.conf files.
 # The IFNAME array will be used to determine which interfaces to bring up/down.
-MAXNICS=${MAXNICS:-6}
+#MAXNICS=${MAXNICS:-6}
+#NUMNICS=      # length of array      ${#elem[@]}
+#LASTNIC=      # last element in array ${elem[-1]}
+LAST=$(ip -br link|grep eth|sort -n |tail -1|sed -e 's/^eth//')
+LASTNIC=${LAST%% *}
+LASTIF=${#IFNAME[@]}
+if [ $(LASTNIC) -gt $(LASTIF) ]; then
+  MAXNICS=$(LASTNIC)
+else
+  MAXNICS=$(LASTIF)
+fi
 i=0
 while [ $i -lt $MAXNICS ];
 do

I made this like 2.5 years ago, but Pat wasn't particularly keen on taking it back then.
Maybe testing and vetting by others might help?
Code could just be dumped straight into the new rc.inet1 too, so that was a bonus :)


Thanks
--
KarlMag

tadgy 03-30-2022 06:16 PM

It wouldn't work.

It doesn't take into account virtual interfaces like tun/tap, bonds and bridges which could be configured in rc.inet1.conf with holes between them and/or real interfaces.

I have an idea of how to remove MAXNICS, but it's messy as hell, error prone and wouldn't make it past Robby even before it got to Pat :)

karlmag 03-31-2022 06:47 PM

Quote:

Originally Posted by tadgy (Post 6342852)
It wouldn't work.

It doesn't take into account virtual interfaces like tun/tap, bonds and bridges which could be configured in rc.inet1.conf with holes between them and/or real interfaces.

I have an idea of how to remove MAXNICS, but it's messy as hell, error prone and wouldn't make it past Robby even before it got to Pat :)


Are you 100% sure about that? Because I am not quite in either direction right now. (I know, the burden of "proof" is on me, but...)

eth<interface> is assumed if IFNAME[interface] is unset or empty.

For bond<interface>, IFNAME<interface> is used.
(NOTE! BONDNICS listed does *not* need to be configured elsewhere.)
As far as I know you put config the bonded interface and don't really care about the underlaying interfaces in that regard.

For VLAN config IFNAME<interface> seems to be used.
I am not sure if you can have a DHCP server give you VLAN config and how that might work if so. (I.e possible spanner in the works)

For virtual interfaces (tun/tap) VIRTIFNAME[interface] is used.
These are set up independently by the rc.inet1 code.
(VIRTIFNAME is *not* a sparse array by definition/requirement either.)

For bridge (br<interface>) IFNAME<interface> is used.
I have not touched bridges for years, but I am wondering if they're set up in a somewhat similar fashion as bonds are.
I.e the config is put on the bridge interface, not on the underlaying interfaces.



So... the original code will work even if there is a mix of ethX and other interface names used, and also if some interfaces inbetween are not put config on.
The only difference between that and my code should be that instead of checking for 6 interfaces, it will continue up to whatever is the last entry of the IFNAME-array (or at least the last physical interface found on the box).


Am I missing something really obvious now (or again)?


Thanks
--
KarlMag


All times are GMT -5. The time now is 09:39 PM.