summaryrefslogtreecommitdiff
path: root/scripts/vyatta_net_name
blob: 54f91f0444819a399a4ff005cbc290aab6c3e0f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/bin/bash
# **** License ****
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# This code was originally developed by Vyatta, Inc.
# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
# All Rights Reserved.
#
# Authors:      Tom Grennan <tgrennan@vyatta.com>
#               Bob Gilligan <gilligan@vyatta.com>
# Description:	search Vyatta config for interface name given address
#
# **** End License ****

progname=${0##*/}
debug=
match=
attr_address=0:0:0:0:0:0
declare -i ethn=0
udev_persistent_net_rules_file="/etc/udev/rules.d/70-persistent-net.rules"

# Set log_file to "/dev/null" to turn off debugging
log_file="/tmp/vnn_log"

test -r /etc/default/vyatta && source /etc/default/vyatta

# process command line variable overrides

for arg ; do
    case "$arg" in
    --debug )
	debug=echo
	;;
    --*=* )
	arg=${arg#--}
	eval ${arg%=*}=\"${arg#*=}\"
	;;
    *=* )
	eval ${arg%=*}=\"${arg#*=}\"
	;;
    *:*:*:*:*:* )
	attr_address=$arg
	;;
    * )
	kname=$arg
	;;
    esac
done

: ${vyatta_prefix:=/opt/vyatta}
: ${vyatta_sbindir:=${vyatta_prefix}/sbin}
: ${vyatta_sysconfdir:=${vyatta_prefix}/etc}
: ${BOOTFILE:=${vyatta_sysconfdir:-/opt/vyatta/etc}/config/config.boot}
: ${DEFAULT_BOOTFILE:=${vyatta_sysconfdir:-/opt/vyatta/etc}/config.boot.default}

shopt -s extglob nullglob

# load cfg_eth_hwid array from config file as follows
# interface {
# ...
#     ethernet eth# {
#     ...
#	 hw-id XX:XX:XX:XX:XX:XX
#     ...
#     }
# }
#
# cfg_eth_hwid=( "eth#=xx:xx:xx:xx:xx:xx" ... )

declare -a cfg_net_hwid=( $( sed -ne '
    /^interfaces {/,/^}/ {
	/^ *ethernet eth[0-9]* {/,/^    $/ {
	    /^ *ethernet/ {
		s/\r//
		s/.* eth\([0-9]\+\) {$/ eth\1=/
# hold interface name
		h
	    }
	    /^.*hw-id:\?/ {
# translate field name
		s/\r//
		s/.*hw-id:\? *//
# tolower hex mac address
		y/ABCDEF/abcdef/
# exchange hold and pattern space
		x
# concatenate hold and pattern
		G
		s/\n//p
	    }
	}
    }' $BOOTFILE ))

finish ()
{
    local cmd=$1 name=$2 address=$3

    # The output from this program tells udev what name to give this device
    echo $name

    # This file tells rl_system startup script how to update the Vyatta
    # config file.
    touch /tmp/${progname}_${cmd}_${name}_${address} &> /dev/null

    # Remove entry for this MAC addr from the standard udev generated
    # config file, if it exists, so it doesn't rename the interface
    # out from under us.  Remove the subject line plus the comment
    # line above it
    if [ -e  $udev_persistent_net_rules_file ]; then
	sed -i -e "/^#/N;/${address}/d" $udev_persistent_net_rules_file
    fi

    exit $?
}

# Determine whether variable "ethn" conflicts with an ethernet unit
# number that was assigned in previous runs of this script
ethn_conflicts()
{
    # Return value 1 (failure) means no conflicts found.
    # Return value 0 (success) means conflicts were found.
    conflicts=1

    echo "`date`: ethn_conflicts is checking if $ethn has conflicts" >> $log_file
    # Generate list of ethernet unit numbers assigned previously by this script
    used_ethn=""
    for filename in /tmp/vyatta_net_name* ; do
	if [ -e $filename ]; then
	    # strip off everything before the unit number
	    unit=${filename##*vyatta_net_name_*_eth}
	    # strip off everything after the unit number
	    unit=${unit%%_*}
	    # add unit number from this file to the list
	    used_ethn="$used_ethn $unit"
	fi
    done

    echo "`date`: ethn_conflicts: about to run check" >> $log_file

    for this_ethn in $used_ethn ; do
	if [ $ethn -eq $this_ethn ]; then
	    echo "`date`: ethn $ethn conflicts with previously configured $this_ethn" >> $log_file
	    conflicts=0
	    break
	fi
    done

    echo "`date`: ethn_conflicts for ethn $ethn returns $conflicts" >> $log_file
    # return value (exit status) is true, i.e. 0, if there is a conflict
    return $conflicts
}


#
# Find an ethernet unit number that is neither listed in the config
# file nor assigned by this script in earlier runs.
get_free_ethn()
{
    # list of ethernet unit numbers assigned previously by this script
    used_ethn=""
    for filename in /tmp/vyatta_net_name* ; do
	if [ -e $filename ]; then
	    # strip off everything before the unit number
	    unit=${filename##*vyatta_net_name_*_eth}
	    # strip off everything after the unit number
	    unit=${unit%%_*}
	    # add unit number from this file to the list
	    used_ethn="$used_ethn $unit"
	fi
    done

    # Counting up from 0, try to find a free ethernet unit number
    found=0
    for ((ethn_to_use=0 ;  ; ethn_to_use+=1)) ; do
	found=1
	# Check to see if this one is in the config file

	echo "`date`: get_free_ethn: cfg_net_hwid is ${cfg_net_hwid[@]}" >> $log_file

	for name_hwid in ${cfg_net_hwid[@]} ; do
	    name=${name_hwid%=*}
            this_ethn=${name/eth/}
	    echo "`date`: get_free_ethn 1 comparing $ethn_to_use vs $this_ethn" >> $log_file
	    if [ $ethn_to_use -eq $this_ethn ]; then
		found=0
		break
	    fi
	done

	if [ $found -eq 0 ]; then
	    continue
	fi

	echo "`date`: get_free_ethn: used_ethn is $used_ethn" >> $log_file

	# Check to see if this script has assigned this unit number already
	for this_ethn in $used_ethn ; do
	    echo "`date`: get_free_ethn 2 comparing $ethn_to_use vs $this_ethn" >> $log_file
	    if [ $ethn_to_use -eq $this_ethn ]; then
		found=0
		break
	    fi
	done

	if [ $found -eq 1 ]; then
	    break
	fi
    done

    # The return value
    ethn=$ethn_to_use

    echo "`date`: get_free_ethn found $ethn_to_use" >> $log_file
}

# Run with lock held to protect atomicity of access to assigned ethn file
( flock 200

touch $log_file

echo "`date`: vyatta_net_name $kname $attr_address" >> $log_file

if [ ! -f $BOOTFILE ] ; then
    cp $DEFAULT_BOOTFILE $BOOTFILE
    chgrp vyattacfg $BOOTFILE 
    chmod 660 $BOOTFILE
fi

for name_hwid in ${cfg_net_hwid[@]} ; do
    name=${name_hwid%=*}
    hwid=${name_hwid#*=}
    ethn=${name/eth/}
    echo "`date`: Checking $name_hwid against $kname $attr_address" >> $log_file

    if [ "$hwid" == "$attr_address" ] ; then
	# The MAC addr of this interface matches an entry in the config
	# file.  We mod the config file interface sub-block in case it
	# is missing.

	echo "`date`: finish 1: mod $name $attr_address" >> $log_file

	finish mod $name $attr_address
    fi

    if [ "$name" = "$kname" ]; then
	# The kernel name matches an entry in the config file.  Save the
        # config file entry for later examination.
	
	match=$name_hwid
    fi
done

if [ -z "$kname" ]; then
    exit 1
fi

# We have not found a matching hwid in the config file.  See if we can use
# the kernel name.

if [ -z "$match" ] ; then
    # The kernel interface name is not listed in the config file.
    # If the kernel's name is in the standard "ethN" format, and doesn't
    # conflict with any other name we've used, then
    # we can just go ahead and use the kernel's name.  If not, then
    # we will generate a name in the standard format that does not
    # conflict with any names in the config file, or any other names
    # that we have seen.

    non_std_kname=${kname##eth+([0-9])}
    if [ -z "$non_std_kname" ]; then
	# kname is in standard format, so we get the unit number from it.
	ethn=${kname/eth/}

	# We can use this unit number unless it happens to conflict
	# with one we have already assigned.
	if ethn_conflicts ; then
	    echo "`date`: kname $kname conflicts with already assigned unit" >> $log_file
	    get_free_ethn
	fi
    else
	# kname is not in standard format, so we have to generate
	# a unit number
	echo "`date`: kname $kname is non-standard format" >> $log_file
	get_free_ethn
    fi

    echo "`date`: finish 2: add eth$ethn $attr_address" >> $log_file

    finish add eth$ethn $attr_address

elif [ -z "${match#*=}" ] ; then
    # The config file has this interface but the sub-block is missing the hwid
    # field, so we use the kernel name.  In this case, we know that the
    # kernel name is in the standard format because it matched an entry
    # in the config file, and all entries in the config file are in standard
    # format.  This will cause the hwid for this NIC to be added to the
    # entry in the config file.

    echo "`date`: finish 3: mod $kname $attr_address" >> $log_file

    finish mod $kname $attr_address

else
    # The config file has this interface name, but the mac address
    # that of this NIC.  This indicates that the device is either a
    # replacement or new NIC that is being detected earlier than the device
    # configured with this name. Since we don't know which case it is,
    # we must generate a new unit number.
    get_free_ethn
    
    echo "`date`: finish 4: add eth$ethn $attr_address" >> $log_file

    finish add eth$ethn $attr_address
fi

# Should never get here.  If this shows up in the log file, something
# is wrong!
echo "`date`: no finish: kname = $kname, attr_attr = $attr_address, match = $match" >> $log_file

) 200> /tmp/vnn_lock

# Local Variables:
# mode: shell-script
# sh-indentation: 4
# End: