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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
|
#!/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
;;
* )
orig_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 the Vyatta config file by looking
# for entries formatted as follows:
#
# interface {
# ...
# ethernet eth# {
# ...
# hw-id XX:XX:XX:XX:XX:XX
# ...
# }
# }
#
# The result is an array named "cfg_net_hwid". Each element of the
# array is formatted like this:
#
# 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}.*NAME/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
}
#
# Main Section
#
# Run with lock held to protect atomicity of access to assigned ethn file
( flock 200
touch $log_file
echo "`date`: vyatta_net_name $orig_kname $attr_address" >> $log_file
# The biosdevname program determines the "recommended" name for the NIC
# based on information such its place in the bus topology, and whether it
# resides on the motherboard or not. The ensures deterministic NIC naming.
#
if [ ! -z "$orig_kname" ]; then
if [ -e /sbin/biosdevname ]; then
kname=`/sbin/biosdevname -i $orig_kname`
echo "`date`: /sbin/biosdevname maps $orig_kname to $kname" >> $log_file
else
echo "`date`: /sbin/biosdevname is not present on this system" >> $log_file
kname=$orig_kname
fi
else
kname=""
fi
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
echo "`date`: Error: interface name not specified by caller" >> $log_file
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 is not
# 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:
|