#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
# All rights reserved.
#
NET_INADDR_ANY="0.0.0.0"
NET_IN6ADDR_ANY_INIT="::0"
# Print warnings to console
}
#
# shcat file
# Simulates cat in sh so it doesn't need to be on the root filesystem.
#
while [ $# -ge 1 ]; do
while read i; do
echo "$i"
done < $1
shift
done
}
{
message=$1
err=$2
fi
}
#
# inet_list list of IPv4 interfaces.
# inet6_list list of IPv6 interfaces.
# ipmp_list list of IPMP IPv4 interfaces.
# ipmp6_list list of IPMP IPv6 interfaces.
# inet_plumbed list of plumbed IPv4 interfaces.
# inet6_plumbed list of plumbed IPv6 interfaces.
# ipmp_created list of created IPMP IPv4 interfaces.
# ipmp6_created list of created IPMP IPv6 interfaces.
# inet_failed list of IPv4 interfaces that failed to plumb.
# inet6_failed list of IPv6 interfaces that failed to plumb.
# ipmp_failed list of IPMP IPv4 interfaces that failed to be created.
# ipmp6_failed list of IPMP IPv6 interfaces that failed to be created.
#
#
# get_physical interface
#
# Return physical interface corresponding to the given interface.
#
{
IFS="${IFS}:"
set -- $1
echo $1
}
#
# get_logical interface
#
# Return logical interface number. Zero will be returned
# if there is no explicit logical number.
#
{
IFS="${IFS}:"
set -- $1
if [ -z "$2" ]; then
echo 0
else
echo $2
fi
}
#
# if_comp if1 if2
#
# Compare interfaces. Do the physical interface names and logical interface
# numbers match?
#
{
}
#
# physical_comp if1 if2
#
# Do the two interfaces share a physical interface?
#
{
}
#
# in_list op item list
#
# Is "item" in the given list? Use "op" to do the test, applying it to
# "item" and each member of the list in turn until it returns success.
#
{
op=$1
item=$2
shift 2
while [ $# -gt 0 ]; do
shift
done
return 1
}
#
# get_groupifname groupname
#
# Return the IPMP meta-interface name for the group, if it exists.
#
{
echo "$ifname"
return
fi
done
}
#
# create_ipmp ifname groupname type
#
# Helper function for create_groupifname() that returns zero if it's able
# to create an IPMP interface of the specified type and place it in the
# specified group, or non-zero otherwise.
#
{
}
#
# create_groupifname groupname type
#
# Create an IPMP meta-interface name for the group. We only use this
# function if all of the interfaces in the group failed at boot and there
#
{
#
# This is a horrible way to count from 0 to 999, but in sh and
# without necessarily having /usr mounted, what else can we do?
#
for b in 0 1 2 3 4 5 6 7 8 9; do
for c in 0 1 2 3 4 5 6 7 8 9; do
# strip leading zeroes
[ "$a" = "" ] && [ "$b" = 0 ] && b=""
if create_ipmp ipmp$a$b$c $1 $2; then
echo ipmp$a$b$c
return
fi
done
done
done
}
#
# get_hostname_ipmpinfo interface type
#
# Return all requested IPMP keywords from hostname file for a given interface.
#
# Example:
# get_hostname_ipmpinfo hme0 inet keyword [ keyword ... ]
#
{
;;
;;
*)
return
;;
esac
type=$2
shift 2
#
# Read through the hostname file looking for the specified
# keywords. Since there may be several keywords that cancel
# each other out, the caller must post-process as appropriate.
#
while read line; do
done
done
}
#
# get_group_for_type interface type list
#
# Look through the set of hostname files associated with the same physical
# interface as "interface", and determine which group they would configure.
# Only hostname files associated with the physical interface or logical
# interface zero are allowed to set the group.
#
{
physical=`get_physical $1`
type=$2
group=""
#
# The last setting of the group is the one that counts, which is
# the reason for the second while loop.
#
shift 2
fi
done | while :; do
echo "$group"
break
}
done
}
#
# get_group interface
#
# If there is both an inet and inet6 version of an interface, the group
# could be set in either set of hostname files. Since inet6 is configured
# after inet, if there's a setting in both files, inet6 wins.
#
{
echo $group
}
#
# Given the interface name and the address family (inet or inet6), determine
# whether this is a VRRP VNIC.
#
# This is used to determine whether to bring the interface up
#
macaddrtype=`/sbin/dladm show-vnic $1 -o MACADDRTYPE -p 2>/dev/null`
;;
*) vrrp=0
;;
esac
return $vrrp
}
# doDHCPhostname interface
# Pass to this function the name of an interface. It will return
# true if one should enable the use of DHCP client-side host name
# requests on the interface, and false otherwise.
#
{
return $?
fi
return 1
}
#
# inet_process_hostname processor [ args ]
#
# Process an inet hostname file. The contents of the file
# are taken from standard input. Each line is passed
# on the command line to the "processor" command.
# Command line arguments can be passed to the processor.
#
# Examples:
# inet_process_hostname /sbin/ifconfig hme0 < /etc/hostname.hme0
#
# inet_process_hostname /sbin/ifparse -f < /etc/hostname.hme0
#
# If there is only line in an hostname file we assume it contains
# the old style address which results in the interface being brought up
# and the netmask and broadcast address being set ($inet_oneline_epilogue).
#
# Note that if the interface is a VRRP interface, do not bring the address
# up ($inet_oneline_epilogue_no_up).
#
# If there are multiple lines we assume the file contains a list of
# commands to the processor with neither the implied bringing up of the
# interface nor the setting of the default netmask and broadcast address.
#
# Return non-zero if any command fails so that the caller may alert
# users to errors in the configuration.
#
inet_oneline_epilogue_no_up="netmask + broadcast +"
inet_oneline_epilogue="netmask + broadcast + up"
{
if doDHCPhostname $2; then
:
else
#
# Redirecting input from a file results in a sub-shell being
# used, hence this outer loop surrounding the "multiple_lines"
# and "ifcmds" variables.
#
while :; do
multiple_lines=false
ifcmds=""
retval=0
#
# This handles the first N-1
# lines of a N-line hostname file.
#
multiple_lines=true
fi
#
# Strip out the "ipmp" keyword if it's the
# first token, since it's used to control
# interface creation, not configuration.
#
done
#
# If the hostname file is empty or consists of only
# blank lines, break out of the outer loop without
# configuring the newly plumbed interface.
#
if [ $multiple_lines = false ]; then
#
# The traditional one-line hostname file.
# Note that we only bring it up if the
# interface is not a VRRP VNIC.
#
if not_vrrp_interface $2 $3; then
else
fi
fi
#
# This handles either the single-line case or
# the last line of the N-line case.
#
$* $ifcmds || return $?
return $retval
done
fi
}
#
# inet6_process_hostname processor [ args ]
#
# Process an inet6 hostname file. The contents of the file
# are taken from standard input. Each line is passed
# on the command line to the "processor" command.
# Command line arguments can be passed to the processor.
#
# Examples:
# inet6_process_hostname /sbin/ifconfig hme0 inet6 < /etc/hostname6.hme0
#
# inet6_process_hostname /sbin/ifparse -f inet6 < /etc/hostname6.hme0
#
# Return non-zero if any of the commands fail so that the caller may alert
# users to errors in the configuration.
#
{
retval=0
#
# See comment in inet_process_hostname for details.
#
fi
done
return $retval
}
#
# Process interfaces that failed to plumb. Find the IPMP meta-interface
# that should host the addresses. For IPv6, only static addresses defined
# in hostname6 files are moved, autoconfigured addresses are not moved.
#
# Example:
# move_addresses inet6
#
{
type="$1"
eval "failed=\"\$${type}_failed\""
eval "list=\"\$${type}_list\""
process_func="${type}_process_hostname"
processed=""
typedesc="IPv4"
zaddr="0.0.0.0"
else
typedesc="IPv6"
zaddr="::"
fi
echo "Moving addresses from missing ${typedesc} interface(s):\c" \
in_list if_comp $ifname $processed && continue
}
continue
fi
#
# Lookup the IPMP meta-interface name. If one doesn't exist,
# create it.
#
#
# The hostname files are processed twice. In the first
# pass, we are looking for all commands that apply to the
# non-additional interface address. These may be
# scattered over several files. We won't know whether the
# address represents a failover address or not until we've
# read all the files associated with the interface.
#
# In the first pass through the hostname files, all
# additional logical interface commands are removed. The
# remaining commands are concatenated together and passed
# to ifparse to determine whether the non-additional
# logical interface address is a failover address. If it
# as a failover address, the address may not be the first
# item on the line, so we can't just substitute "addif"
# for "set". We prepend an "addif $zaddr" command, and
# let the embedded "set" command set the address later.
#
if_comp $ifname $item && $process_func \
continue
done
#
# In the second pass, look for the the "addif" commands
# that configure additional failover addresses. Addif
# commands are not valid in logical interface hostname
# files.
#
done
fi
}
done
}
#
# ipadm_from_gz_if ifname
#
# Return true if we are in a non-global zone and Layer-3 protection of
# IP addresses is being enforced on the interface by the global zone
#
{
if smf_is_globalzone || ![[ $pif == *4* || $pif == *6* ]]; then
return 1
else
#
# In the non-global zone, plumb the interface to show current
# flags and check if Layer-3 protection has been enforced by
# the global zone. Note that this function may return
# with a plumbed interface. Ideally, we would not have to
# plumb the interface to check l3protect, but since we
# the `allowed-ips' datalink property cannot currently be
# examined in any other way from the non-global zone, we
# resort to plumbing the interface
#
if [ $l3protect = 0 ]; then
return 1
else
return 0
fi
fi
}
#
# if_configure type class interface_list
#
# Configure all of the interfaces of type `type' (e.g., "inet6") in
# describes the class of interface (e.g., "IPMP"), as a diagnostic aid.
# For inet6 interfaces, the interface is also brought up.
#
{
fail=
type=$1
class=$2
process_func=${type}_process_hostname
shift 2
desc="IPv4"
else
desc="IPv6"
fi
echo "configuring $desc interfaces:\c"
while [ $# -gt 0 ]; do
if [ $? != 0 ]; then
if [ $? != 0 ]; then
fi
#
# only bring the interface up if it is not a
# VRRP VNIC
#
if not_vrrp_interface $1 $type; then
fi
fi
echo " $1\c"
shift
done
echo "."
}
#
# net-physical and net-nwam method scripts) to perform tasks that only
# need to be done during a reconfigure boot. This needs to be
# (default and nwam) that have distinct method scripts that each need
# to do these things.
#
{
#
# Is this a reconfigure boot? If not, then there's nothing
# for us to do.
#
reconfig=`svcprop -c -p system/reconfigure \
return 0
fi
#
# Ensure that the datalink-management service is running since
# manifest-import has not yet run for a first boot after
# upgrade. We wouldn't need to do that if manifest-import ran
# earlier in boot, since there is an explicit dependency
#
#
# There is a bug in SMF which causes the svcadm command above
# to exit prematurely (with an error code of 3) before having
# waited for the service to come online after having enabled
# it. Until that bug is fixed, we need to have the following
# loop to explicitly wait for the service to come online.
#
i=0
while [ $i -lt 30 ]; do
i=`expr $i + 1`
sleep 1
if [ $? -ne 0 ]; then
continue
break
fi
done
echo "The network/datalink-management service \c"
echo "did not come online."
return 1
fi
#
# Initialize the set of physical links, and validate and
# remove all the physical links which were removed during the
# system shutdown.
#
return 0
}
#
# Check for use of the default "Port VLAN Identifier" (PVID) -- VLAN 1.
# If there is one for a given interface, then warn the user and force the
# PVID to zero (if it's not already set). We do this by generating a list
# of interfaces with VLAN 1 in use first, and then parsing out the
# corresponding base datalink entries to check for ones without a
# "default_tag" property.
#
{
(
# Find datalinks using VLAN 1 explicitly
# configured by dladm
/^#/ || NF < 2 { next }
{ linkdata[$1]=$2; }
/;vid=int,1;/ {
sub(/.*;linkover=int,/, "", $2);
sub(/;.*/, "", $2);
link=linkdata[$2];
sub(/name=string,/, "", link);
sub(/;.*/, "", link);
print link;
}' $datalink
/^END$/ { state=1; }
state == 0 { usingpvid[++nusingpvid]=$1; next; }
/^#/ || NF < 2 { next; }
{
# If it is already present and has a tag set,
# then believe it.
if (!match($2, /;default_tag=/))
next;
sub(/name=string,/, "", $2);
sub(/;.*/, "", $2);
for (i = 1; i <= nusingpvid; i++) {
if (usingpvid[i] == $2)
usingpvid[i]="";
}
}
END {
for (i = 1; i <= nusingpvid; i++) {
if (usingpvid[i] != "") {
printf("Warning: default VLAN tag set to 0" \
" on %s\n", usingpvid[i]);
cmd=sprintf("dladm set-linkprop -p " \
"default_tag=0 %s\n", usingpvid[i]);
system(cmd);
}
}
}'
}
#
# service_exists fmri
#
# returns success (0) if the service exists, 1 otherwise.
#
{
if [ $? -eq 0 ]; then
return 0;
fi
return 1;
}
#
# service_is_enabled fmri
#
# returns success (0) if the service is enabled (permanently or
# temporarily), 1 otherwise.
#
{
#
# The -c option must be specified to use the composed view
# See Example 2 in svcprop(1).
#
# Look at the general_ovr/enabled (if it is present) first to
# determine the temporarily enabled state.
#
if [ $? -eq 0 ]; then
return 1
fi
return 1
}
#
# is_valid_v4addr addr
#
# Returns 0 if a valid IPv4 address is given, 1 otherwise.
#
{
$1 !~ /^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\
(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ \
{ exit 1 }'
return $?
}
#
# is_valid_v6addr addr
#
# Returns 0 if a valid IPv6 address is given, 1 otherwise.
#
{
# 1:2:3:4:5:6:7:8
$1 !~ /^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/ &&
# 1:2:3::6:7:8
$1 !~ /^([a-fA-F0-9]{1,4}:){0,6}:([a-fA-F0-9]{1,4}:){0,6}\
[a-fA-F0-9]{1,4}$/ &&
# 1:2:3::
$1 !~ /^([a-fA-F0-9]{1,4}:){0,7}:$/ &&
# ::7:8
$1 !~ /^:(:[a-fA-F0-9]{1,4}){0,6}:[a-fA-F0-9]{1,4}$/ &&
# ::f:1.2.3.4
$1 !~ /^:(:[a-fA-F0-9]{1,4}){0,5}:\
((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\
(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ &&
# a:b:c:d:e:f:1.2.3.4
$1 !~ /^([a-fA-F0-9]{1,4}:){6}\
((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\
(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ \
{ exit 1 }'
return $?
}
#
# is_valid_addr addr
#
# Returns 0 if a valid IPv4 or IPv6 address is given, 1 otherwise.
#
{
is_valid_v4addr $1 || is_valid_v6addr $1
}
#
# nwam_get_loc_prop location property
#
# echoes the value of the property for the given location
# return:
# 0 => property is set
# 1 => property is not set
#
{
rtn=$?
echo $value
return $rtn
}
#
# nwam_get_loc_list_prop location property
#
# echoes a space-separated list of the property values for the given location
# return:
# 0 => property is set
# 1 => property is not set
#
{
rtn=$?
#
# nwamcfg gives us a comma-separated list;
# need to convert commas to spaces.
#
echo $slist
return $rtn
}