Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 16 Jun 2013 00:59:41 +0900 (JST)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        freebsd-rc@FreeBSD.org
Cc:        kpaasial@gmail.com
Subject:   range spec support in ifconfig_IF_aliasN
Message-ID:  <20130616.005941.1489449431438337467.hrs@allbsd.org>

next in thread | raw e-mail | index | archive | help
----Security_Multipart0(Sun_Jun_16_00_59_41_2013_553)--
Content-Type: Multipart/Mixed;
 boundary="--Next_Part(Sun_Jun_16_00_59_41_2013_325)--"
Content-Transfer-Encoding: 7bit

----Next_Part(Sun_Jun_16_00_59_41_2013_325)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi all,

 Can anyone test the attached patch?  It implements range
 specification for IPv6 address block like 2001:db8:1::1-5 in rc.conf
 $ifconfig* variable.  This arises as a feature request repeatedly
 (conf/174225, for example).

 Adding ipv6_addrs_IF similar to ipv4_addrs_IF is possible, but I
 think adding range spec support in ifconfig_IF_alisesN is easier for
 users to understand and we should not add new variables which are
 specific to an address family.  After applying the patch, all of the
 following will work:

 ifconfig_em0="inet 192.168.0.1"		# IPv4 configuration
 ifconfig_em0_ipv6="inet6 2001:db8::1/64"	# IPv6 configuration
 ipv4_addr_em0="10.2.1.1-10"			# IPv4 address range spec.  Now deprecated.
 ifconfig_em0_alias0="inet6 2001:db8:5::1 prefixlen 70" # IPv6 alias.
 ifconfig_em0_alias1="inet 10.2.2.1/24"		# IPv4 alias with range spec (backward compat).
 ifconfig_em0_alias2="10.3.1.1-10/32"		# IPv4 alias with range spec.
 ifconfig_em0_alias3="inet6 2001:db8:20-2f::1/64" # IPv6 alias with range spec.
	# ifconfig_IF_aliases is just like ifconfig_IF_aliasN.
	# It can have all of entries in one line.
 ifconfig_em0_aliases="inet 10.3.3.201-204/24 inet6 2001:db8:210-213::1/64 inet 10.1.1.1/24"
 ipv6_ifconfig_em0_alias0="inet6 2001:db8:f::1/64" # IPv6 alias (backward compat)
 ipv6_ifconfig_em0_alias1="2001:db8:f:1::1/64"	# IPv6 alias (backward compat)

 This example should include all possible combinations of the existing
 variables to configure IP aliases.  There should be no functional
 degradation.  The differences are:

 1. ifconfig_IF_aliasN supports address range specification.

 2. ifconfig_IF_aliases has been added.

 I think ipv4_addr_IF should be deprecated in favor of
 ifconfig_IF_aliaseN.

 The implementation includes re-factoring the alias handing in a
 address family independent manner and IPv6 DAD treatment due to
 multiple address configurations in a short period.  Also, range
 specification in IPv6 can generate a lot of addresses, so the number
 of expanded address is limited to 31 (set as _IPEXPANDMAX at the top
 of network.subr) per entry.

-- Hiroki

----Next_Part(Sun_Jun_16_00_59_41_2013_325)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="if_aliases_20130616-1.diff"

Index: etc/network.subr
===================================================================
--- etc/network.subr	(revision 251659)
+++ etc/network.subr	(working copy)
@@ -24,7 +24,11 @@
 #
 # $FreeBSD$
 #
+IFCONFIG_CMD="/sbin/ifconfig"

+# Maximum number of addresses expanded from a address range specification.
+_IPEXPANDMAX=31
+
 #
 # Subroutines commonly used from network startup scripts.
 # Requires that rc.conf be loaded first.
@@ -94,7 +98,7 @@
 	# ifconfig_IF
 	ifconfig_args=`ifconfig_getargs $1`
 	if [ -n "${ifconfig_args}" ]; then
-		eval ifconfig $1 ${ifconfig_args}
+		eval ${IFCONFIG_CMD} $1 ${ifconfig_args}
 		_cfg=0
 	fi

@@ -122,7 +126,7 @@
 		esac

 		if [ -n "${_ipv6_opts}" ]; then
-			ifconfig $1 inet6 ${_ipv6_opts}
+			${IFCONFIG_CMD} $1 inet6 ${_ipv6_opts}
 		fi

 		# ifconfig_IF_ipv6
@@ -136,8 +140,8 @@
 				ifconfig_args="inet6 ${ifconfig_args}"
 			;;
 			esac
-			ifconfig $1 inet6 -ifdisabled
-			eval ifconfig $1 ${ifconfig_args}
+			${IFCONFIG_CMD} $1 inet6 -ifdisabled
+			eval ${IFCONFIG_CMD} $1 ${ifconfig_args}
 			_cfg=0
 		fi

@@ -145,7 +149,7 @@
 		# ipv6_prefix_hostid_addr_common().
 		ifconfig_args=`get_if_var $1 ipv6_prefix_IF`
 		if [ -n "${ifconfig_args}" ]; then
-			ifconfig $1 inet6 -ifdisabled
+			${IFCONFIG_CMD} $1 inet6 -ifdisabled
 			_cfg=0
 		fi

@@ -154,14 +158,14 @@
 		if [ -n "${ifconfig_args}" ]; then
 			warn "\$ipv6_ifconfig_$1 is obsolete." \
 			    "  Use ifconfig_$1_ipv6 instead."
-			ifconfig $1 inet6 -ifdisabled
-			eval ifconfig $1 inet6 ${ifconfig_args}
+			${IFCONFIG_CMD} $1 inet6 -ifdisabled
+			eval ${IFCONFIG_CMD} $1 inet6 ${ifconfig_args}
 			_cfg=0
 		fi
 	fi

 	if [ ${_cfg} -eq 0 ]; then
-		ifconfig $1 up
+		${IFCONFIG_CMD} $1 up
 	fi

 	if wpaif $1; then
@@ -171,7 +175,7 @@

 	if dhcpif $1; then
 		if [ $_cfg -ne 0 ] ; then
-			ifconfig $1 up
+			${IFCONFIG_CMD} $1 up
 		fi
 		if syncdhcpif $1; then
 			/etc/rc.d/dhclient start $1
@@ -202,7 +206,7 @@
 	fi

 	if ifexists $1; then
-		ifconfig $1 down
+		${IFCONFIG_CMD} $1 down
 		_cfg=0
 	fi

@@ -539,7 +543,7 @@
 ifexists()
 {
 	[ -z "$1" ] && return 1
-	ifconfig -n $1 > /dev/null 2>&1
+	${IFCONFIG_CMD} -n $1 > /dev/null 2>&1
 }

 # ipv4_up if
@@ -554,11 +558,10 @@
 	if [ "${_if}" = "lo0" ]; then
 		ifconfig_args=`get_if_var ${_if} ifconfig_IF`
 		if [ -z "${ifconfig_args}" ]; then
-			ifconfig ${_if} inet 127.0.0.1/8 alias
+			${IFCONFIG_CMD} ${_if} inet 127.0.0.1/8 alias
 		fi
 	fi
-	ifalias_up ${_if} inet && _ret=0
-	ipv4_addrs_common ${_if} alias && _ret=0
+	ifalias ${_if} inet alias && _ret=0

 	return $_ret
 }
@@ -575,7 +578,7 @@
 		return 0
 	fi

-	ifalias_up ${_if} inet6 && _ret=0
+	ifalias ${_if} inet6 alias && _ret=0
 	ipv6_prefix_hostid_addr_common ${_if} alias && _ret=0
 	ipv6_accept_rtadv_up ${_if} && _ret=0

@@ -591,8 +594,10 @@
 	_ifs="^"
 	_ret=1

-	inetList="`ifconfig ${_if} | grep 'inet ' | tr "\n" "$_ifs"`"
+	ifalias ${_if} inet -alias && _ret=0

+	inetList="`${IFCONFIG_CMD} ${_if} | grep 'inet ' | tr "\n" "$_ifs"`"
+
 	oldifs="$IFS"
 	IFS="$_ifs"
 	for _inet in $inetList ; do
@@ -602,15 +607,12 @@
 		_inet=`expr "$_inet" : '.*\(inet \([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*'`

 		IFS="$oldifs"
-		ifconfig ${_if} ${_inet} delete
+		${IFCONFIG_CMD} ${_if} ${_inet} delete
 		IFS="$_ifs"
 		_ret=0
 	done
 	IFS="$oldifs"

-	ifalias_down ${_if} inet && _ret=0
-	ipv4_addrs_common ${_if} -alias && _ret=0
-
 	return $_ret
 }

@@ -629,9 +631,9 @@

 	ipv6_accept_rtadv_down ${_if} && _ret=0
 	ipv6_prefix_hostid_addr_common ${_if} -alias && _ret=0
-	ifalias_down ${_if} inet6 && _ret=0
+	ifalias ${_if} inet6 -alias && _ret=0

-	inetList="`ifconfig ${_if} | grep 'inet6 ' | tr "\n" "$_ifs"`"
+	inetList="`${IFCONFIG_CMD} ${_if} | grep 'inet6 ' | tr "\n" "$_ifs"`"

 	oldifs="$IFS"
 	IFS="$_ifs"
@@ -642,7 +644,7 @@
 		_inet6=`expr "$_inet6" : '.*\(inet6 \([0-9a-f:]*\)\).*'`

 		IFS="$oldifs"
-		ifconfig ${_if} ${_inet6} -alias
+		${IFCONFIG_CMD} ${_if} ${_inet6} -alias
 		IFS="$_ifs"
 		_ret=0
 	done
@@ -651,234 +653,349 @@
 	return $_ret
 }

-# ipv4_addrs_common if action
-#	Evaluate the ifconfig_if_ipv4 arguments for interface $if and
-#	use $action to add or remove IPv4 addresses from $if.
-ipv4_addrs_common()
-{
-	local _ret _if _action _cidr _cidr_addr
-	local _ipaddr _netmask _range _ipnet _iplow _iphigh _ipcount
-	_ret=1
-	_if=$1
-	_action=$2
-
-	# get ipv4-addresses
-	cidr_addr=`get_if_var $_if ipv4_addrs_IF`
-
-	for _cidr in ${cidr_addr}; do
-		_ipaddr=${_cidr%%/*}
-		_netmask="/"${_cidr##*/}
-		_range=${_ipaddr##*.}
-		_ipnet=${_ipaddr%.*}
-		_iplow=${_range%-*}
-		_iphigh=${_range#*-}
-
-		# clear netmask when removing aliases
-		if [ "${_action}" = "-alias" ]; then
-			_netmask=""
-		fi
-
-		_ipcount=${_iplow}
-		while [ "${_ipcount}" -le "${_iphigh}" ]; do
-			eval "ifconfig ${_if} ${_action} ${_ipnet}.${_ipcount}${_netmask}"
-			_ipcount=$((${_ipcount}+1))
-			_ret=0
-
-			# only the first ipaddr in a subnet need the real netmask
-			if [ "${_action}" != "-alias" ]; then
-				_netmask="/32"
-			fi
-		done
-	done
-
-	return $_ret
-}
-
-# ifalias_up if af
-#	Configure aliases for network interface $if.
+# ifalias if af action
+#	Configure or remove aliases for network interface $if.
 #	It returns 0 if at least one alias was configured or
-#	1 if there were none.
+#	removed, or 1 if there were none.
 #
-ifalias_up()
+ifalias()
 {
 	local _ret
 	_ret=1

+	afexists $2 || return $_ret
+
 	case "$2" in
-	inet)
-		_ret=`ifalias_ipv4_up "$1"`
+	inet|inet6)
+		ifalias_af_common $1 $2 $3 && _ret=0
 		;;
-	inet6)
-		_ret=`ifalias_ipv6_up "$1"`
-		;;
 	esac

 	return $_ret
 }

-# ifalias_ipv4_up if
-#	Helper function for ifalias_up().  Handles IPv4.
+# ifalias_expand_addr af action addr
+#	Expand address range ("N-M") specification in addr.
+#	"addr" must not include an address-family keyword.
+#	The results will include an address-family keyword.
 #
-ifalias_ipv4_up()
+ifalias_expand_addr()
 {
-	local _ret alias ifconfig_args
-	_ret=1

-	# ifconfig_IF_aliasN which starts with "inet"
-	alias=0
-	while : ; do
-		ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
-		case "${ifconfig_args}" in
-		inet\ *)
-			ifconfig $1 ${ifconfig_args} alias && _ret=0
-			;;
-		inet6\ *)
-			;;
-		"")
-			break
-			;;
-		*)
-			warn "\$ifconfig_$1_alias${alias} needs " \
-			    "\"inet\" keyword for an IPv4 address."
-			ifconfig $1 ${ifconfig_args} alias && _ret=0
-			;;
-		esac
-		alias=$((${alias} + 1))
-	done
-
-	return $_ret
+	afexists $1 || return
+	ifalias_expand_addr_$1 $2 $3
 }

-# ifalias_ipv6_up if
-#	Helper function for ifalias_up().  Handles IPv6.
+# ifalias_expand_addr_inet action addr
+#	Helper function for ifalias_expand_addr().  Handles IPv4.
 #
-ifalias_ipv6_up()
+ifalias_expand_addr_inet()
 {
-	local _ret alias ifconfig_args
-	_ret=1
+	local _action _arg _cidr _cidr_addr
+	local _ipaddr _plen _range _iphead _iptail _iplow _iphigh _ipcount
+	local _retstr _c
+	_action=$1
+	_arg=$2
+	_retstr=

-	# ifconfig_IF_aliasN which starts with "inet6"
-	alias=0
-	while : ; do
-		ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
-		case "${ifconfig_args}" in
-		inet6\ *)
-			ifconfig $1 ${ifconfig_args} alias && _ret=0
-			;;
-		"")
-			break
-			;;
+	case $_action:$_arg in
+	*:*--*)		return ;;			# invalid
+	tmp:*)		echo $_arg && return ;;		# already expanded
+	tmp:*-*)	_action="alias"	;;		# to be expanded
+	*:*-*)		;;				# to be expanded
+	*:*)		echo inet $_arg && return ;;	# already expanded
+	esac
+
+	for _cidr in $_arg; do
+		_ipaddr=${_cidr%%/*}
+		_plen=${_cidr##*/}
+		# When subnet prefix length is not specified, use /32.
+		case $_plen in
+		$_ipaddr)	_plen=32 ;;	# "/" character not found
 		esac
-		alias=$((${alias} + 1))
-	done

-	# backward compatibility: ipv6_ifconfig_IF_aliasN.
-	alias=0
-	while : ; do
-		ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF_alias${alias}`
-		case "${ifconfig_args}" in
-		"")
-			break
+		OIFS=$IFS
+		IFS=. set -- $_ipaddr
+		_range=
+		_iphead=
+		_iptail=
+		for _c in $@; do
+			case $_range:$_c in
+			:[0-9]*-[0-9]*)
+				_range=$_c
 			;;
-		*)
-			ifconfig $1 inet6 ${ifconfig_args} alias && _ret=0
-			warn "\$ipv6_ifconfig_$1_alias${alias} is obsolete." \
-			    "  Use ifconfig_$1_aliasN instead."
+			:*)
+				_iphead="${_iphead}${_iphead:+.}${_c}"
 			;;
-		esac
-		alias=$((${alias} + 1))
+			*:*)
+				_iptail="${_iptail}${_iptail:+.}${_c}"
+			;;
+			esac
+		done
+		IFS=$OIFS
+		_iplow=${_range%-*}
+		_iphigh=${_range#*-}
+
+		# clear netmask when removing aliases
+		if [ "$_action" = "-alias" ]; then
+			_plen=""
+		fi
+
+		_ipcount=$_iplow
+		while [ "$_ipcount" -le "$_iphigh" ]; do
+			_retstr="${_retstr} ${_iphead}${_iphead:+.}${_ipcount}${_iptail:+.}${_iptail}${_plen:+/}${_plen}"
+			if [ $_ipcount -gt $(($_iplow + $_IPEXPANDMAX)) ]; then
+				warn "Range specification is too large (${_iphead}${_iphead:+.}${_iplow}${_iptail:+.}${_iptail}-${_iphead}${_iphead:+.}${_iphigh}${_iptail:+.}${_iptail}).  ${_iphead}${_iphead:+.}${_iplow}${_iptail:+.}${_iptail}-${_iphead}${_iphead:+.}${_ipcount}${_iptail:+.}${_iptail} was processed."
+				break
+			else
+				_ipcount=$(($_ipcount + 1))
+			fi
+			# Forcibly set /32 for remaining aliases.
+			_plen=32
+		done
 	done

-	return $_ret
+	for _c in $_retstr; do
+		ifalias_expand_addr_inet $_action $_c
+	done
 }

-# ifalias_down if af
-#	Remove aliases for network interface $if.
-#	It returns 0 if at least one alias was removed or
-#	1 if there were none.
+# ifalias_expand_addr_inet6 action addr
+#	Helper function for ifalias_expand_addr().  Handles IPv6.
 #
-ifalias_down()
+ifalias_expand_addr_inet6()
 {
-	local _ret
-	_ret=1
+	local _action _arg _cidr _cidr_addr
+	local _ipaddr _plen _ipleft _ipright _iplow _iphigh _ipcount
+	local _ipv4part
+	local _retstr _c
+	_action=$1
+	_arg=$2
+	_retstr=

-	case "$2" in
-	inet)
-		_ret=`ifalias_ipv4_down "$1"`
-		;;
-	inet6)
-		_ret=`ifalias_ipv6_down "$1"`
-		;;
+	case $_action:$_arg in
+	*:*--*)		return ;;			# invalid
+	tmp:*)		echo $_arg && return ;;
+	tmp:*-*)	_action="alias"	;;
+	*:*-*)		;;
+	*:*)		echo inet6 $_arg && return ;;
 	esac

-	return $_ret
+	for _cidr in $_arg; do
+		_ipaddr="${_cidr%%/*}"
+		_plen="${_cidr##*/}"
+
+		case $_action:$_ipaddr:$_cidr in
+		-alias:*:*)		unset _plen ;;
+		*:$_cidr:$_ipaddr)	unset _plen ;;
+		esac
+
+		if [ "${_ipaddr%:*.*.*.*}" = "$_ipaddr" ]; then
+			# Handle !v4mapped && !v4compat addresses.
+
+			# The default prefix length is 64.
+			case $_ipaddr:$_cidr in
+			$_cidr:$_ipaddr)	_plen="64" ;;
+			esac
+			_ipleft=${_ipaddr%-*}
+			_ipright=${_ipaddr#*-}
+			_iplow=${_ipleft##*:}
+			_iphigh=${_ipright%%:*}
+			_ipleft=${_ipleft%:*}
+			_ipright=${_ipright#*:}
+
+			if [ "$_iphigh" = "$_ipright" ]; then
+				unset _ipright
+			else
+				_ipright=:$_ipright
+			fi
+
+			if [ -n "$_iplow" -a -n "$_iphigh" ]; then
+				_iplow=$((0x$_iplow))
+				_iphigh=$((0x$_iphigh))
+				_ipcount=$_iplow
+				while [ $_ipcount -le $_iphigh ]; do
+					_r=`printf "%s:%04x%s%s" \
+					    $_ipleft $_ipcount $_ipright \
+					    ${_plen:+/}$_plen`
+					_retstr="$_retstr $_r"
+					if [ $_ipcount -gt $(($_iplow + $_IPEXPANDMAX)) ]
+					then
+						warn "Range specification is too large $(printf '(%s:%04x%s-%s:%04x%s)' $_ipleft $_iplow $_ipright $_ipleft $_iphigh $_ipright). $(printf '%s:%04x%s-%s:%04x%s' $_ipleft $_iplow $_ipright $_ipleft $_ipcount $_ipright) was processed."
+						break
+					else
+						_ipcount=$(($_ipcount + 1))
+					fi
+				done
+			else
+				_retstr="${_ipaddr}${_plen:+/}${_plen}"
+			fi
+
+			for _c in $_retstr; do
+				ifalias_expand_addr_inet6 $_action $_c
+			done
+		else
+			# v4mapped/v4compat should handle as an IPv4 alias
+			_ipv4part=${_ipaddr##*:}
+
+			# Adjust prefix length if any.  If not, set the
+			# default prefix length as 32.
+			case $_ipaddr:$_cidr in
+			$_cidr:$_ipaddr)	_plen=32 ;;
+			*)			_plen=$(($_plen - 96)) ;;
+			esac
+
+			_retstr=`ifalias_expand_addr_inet \
+			    tmp ${_ipv4part}${_plen:+/}${_plen}`
+			for _c in $_retstr; do
+				ifalias_expand_addr_inet $_action $_c
+			done
+		fi
+	done
 }

-# ifalias_ipv4_down if
-#	Helper function for ifalias_down().  Handles IPv4.
+# ifalias_af_common_handler if af action args
+#	Helper function for ifalias_af_common().
 #
-ifalias_ipv4_down()
+ifalias_af_common_handler()
 {
-	local _ret alias ifconfig_args
+	local _ret _if _af _action _args _c _tmpargs
+
 	_ret=1
+	_if=$1
+	_af=$2
+	_action=$3
+	shift 3
+	_args=$*

-	# ifconfig_IF_aliasN which starts with "inet"
-	alias=0
-	while : ; do
-		ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
-		case "${ifconfig_args}" in
-		inet\ *)
-			ifconfig $1 ${ifconfig_args} -alias && _ret=0
+	case $_args in
+	${_af}\ *)	;;
+	*)	return	;;
+	esac
+
+	_tmpargs=
+	for _c in $_args; do
+		case $_c in
+		${_af})
+			case $_tmpargs in
+			${_af}\ *-*)
+				ifalias_af_common_handler $_if $_af $_action \
+				`ifalias_expand_addr $_af $_action ${_tmpargs#${_af}\ }`
 			;;
-		"")
-			break
+			${_af}\ *)
+				${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
 			;;
+			esac
+			_tmpargs=$_af
+		;;
+		*)
+			_tmpargs="$_tmpargs $_c"
+		;;
 		esac
-		alias=$((${alias} + 1))
 	done
+	# Process the last component if any.
+	if [ -n "$_tmpargs}" ]; then
+		case $_tmpargs in
+		${_af}\ *-*)
+			ifalias_af_common_handler $_if $_af $_action \
+			`ifalias_expand_addr $_af $_action ${_tmpargs#${_af}\ }`
+		;;
+		${_af}\ *)
+			${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
+		;;
+		esac
+	fi

 	return $_ret
 }

-# ifalias_ipv6_down if
-#	Helper function for ifalias_down().  Handles IPv6.
+# ifalias_af_common if af action
+#	Helper function for ifalias().
 #
-ifalias_ipv6_down()
+ifalias_af_common()
 {
-	local _ret alias ifconfig_args
+	local _ret _if _af _action alias ifconfig_args _aliasn _c _tmpargs _iaf
+
 	_ret=1
+	_aliasn=
+	_if=$1
+	_af=$2
+	_action=$3

-	# ifconfig_IF_aliasN which starts with "inet6"
+	# ifconfig_IF_aliasN which starts with $_af
 	alias=0
 	while : ; do
-		ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
-		case "${ifconfig_args}" in
-		inet6\ *)
-			ifconfig $1 ${ifconfig_args} -alias && _ret=0
+		ifconfig_args=`get_if_var $_if ifconfig_IF_alias${alias}`
+		_iaf=
+		case $ifconfig_args in
+		inet\ *)	_iaf=inet ;;
+		inet6\ *)	_iaf=inet6 ;;
+		ipx\ *)		_iaf=ipx ;;
+		esac
+
+		case ${_af}:${_action}:${_iaf}:"${ifconfig_args}" in
+		${_af}:*:${_af}:*)
+			_aliasn="$_aliasn $ifconfig_args"
 			;;
-		"")
+		${_af}:*:"":"")
 			break
 			;;
+		inet:alias:"":*)
+			_aliasn="$_aliasn inet $ifconfig_args"
+			warn "\$ifconfig_${_if}_alias${alias} needs " \
+			    "\"inet\" keyword for an IPv4 address."
 		esac
-		alias=$((${alias} + 1))
+		alias=$(($alias + 1))
 	done

 	# backward compatibility: ipv6_ifconfig_IF_aliasN.
-	alias=0
-	while : ; do
-		ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF_alias${alias}`
-		case "${ifconfig_args}" in
-		"")
-			break
+	case $_af in
+	inet6)
+		alias=0
+		while : ; do
+			ifconfig_args=`get_if_var $_if ipv6_ifconfig_IF_alias${alias}`
+			case ${_action}:"${ifconfig_args}" in
+			*:"")
+				break
 			;;
+			alias:*)
+				_aliasn="${_aliasn} inet6 ${ifconfig_args}"
+				warn "\$ipv6_ifconfig_${_if}_alias${alias} " \
+				    "is obsolete.  Use ifconfig_$1_aliasN " \
+				    "instead."
+			;;
+			esac
+			alias=$(($alias + 1))
+		done
+	esac
+
+	# backward compatibility: ipv4_addrs_IF.
+	for _tmpargs in `get_if_var $_if ipv4_addrs_IF`; do
+		_aliasn="$_aliasn inet $_tmpargs"
+	done
+
+	# Handle ifconfig_IF_aliases, ifconfig_IF_aliasN, and the others.
+	_tmpargs=
+	for _c in `get_if_var $_if ifconfig_IF_aliases` $_aliasn; do
+		case $_c in
+		inet|inet6|ipx)
+			case $_tmpargs in
+			${_af}\ *)
+				eval ifalias_af_common_handler $_if $_af $_action $_tmpargs && _ret=0
+			;;
+			esac
+			_tmpargs=$_c
+		;;
 		*)
-			ifconfig $1 inet6 ${ifconfig_args} -alias && _ret=0
-			warn "\$ipv6_ifconfig_$1_alias${alias} is obsolete." \
-			    "  Use ifconfig_$1_aliasN instead."
-			;;
+			_tmpargs="$_tmpargs $_c"
 		esac
-		alias=$((${alias} + 1))
 	done
+	# Process the last component
+	case $_tmpargs in
+	${_af}\ *)
+		ifalias_af_common_handler $_if $_af $_action $_tmpargs && _ret=0
+	;;
+	esac

 	return $_ret
 }
@@ -899,14 +1016,32 @@
 		hostid=${hostid%\%*}

 		for j in ${prefix}; do
-			address=$j\:${hostid}
-			ifconfig ${_if} inet6 ${address} prefixlen 64 ${_action}
+			# The default prefixlen is 64.
+			plen=${j#*/}
+			case $j:$plen in
+			$plen:$j)	plen=64 ;;
+			*)		j=${j%/*} ;;
+			esac

+			# Normalize the last part by removing ":"
+			j=${j%:*}
+			j=${j%:}
+			OIFS=$IFS; IFS=":"; set -- $j; nj=$#; IFS=$OIFS
+			OIFS=$IFS; IFS=":"; set -- $hostid; nh=$#; IFS=$OIFS
+			if [ $(($nj + $nh)) -eq 8 ]; then
+				address=$j\:$hostid
+			else
+				address=$j\::$hostid
+			fi
+
+			${IFCONFIG_CMD} ${_if} inet6 ${address} \
+				prefixlen $plen ${_action}
+
 			# if I am a router, add subnet router
 			# anycast address (RFC 2373).
 			if checkyesno ipv6_gateway_enable; then
-				ifconfig ${_if} inet6 $j:: prefixlen 64 \
-					${_action} anycast
+				${IFCONFIG_CMD} ${_if} inet6 $j:: \
+					prefixlen $plen ${_action} anycast
 			fi
 		done
 	fi
@@ -918,7 +1053,7 @@
 ipv6_accept_rtadv_up()
 {
 	if ipv6_autoconfif $1; then
-		ifconfig $1 inet6 accept_rtadv up
+		${IFCONFIG_CMD} $1 inet6 accept_rtadv up
 		if ! checkyesno rtsold_enable; then
 			rtsol ${rtsol_flags} $1
 		fi
@@ -930,7 +1065,7 @@
 ipv6_accept_rtadv_down()
 {
 	if ipv6_autoconfif $1; then
-		ifconfig $1 inet6 -accept_rtadv
+		${IFCONFIG_CMD} $1 inet6 -accept_rtadv
 	fi
 }

@@ -975,7 +1110,7 @@

 	# create_args_IF
 	for ifn in ${cloned_interfaces}; do
-		ifconfig ${ifn} create `get_if_var ${ifn} create_args_IF`
+		${IFCONFIG_CMD} ${ifn} create `get_if_var ${ifn} create_args_IF`
 		if [ $? -eq 0 ]; then
 			_list="${_list}${_prefix}${ifn}"
 			[ -z "$_prefix" ] && _prefix=' '
@@ -995,7 +1130,7 @@
 	_list=

 	for ifn in ${cloned_interfaces}; do
-		ifconfig -n ${ifn} destroy
+		${IFCONFIG_CMD} -n ${ifn} destroy
 		if [ $? -eq 0 ]; then
 			_list="${_list}${_prefix}${ifn}"
 			[ -z "$_prefix" ] && _prefix=' '
@@ -1022,16 +1157,16 @@
 		debug_flags="`get_if_var $child wlandebug_IF`"

 		if expr $child : 'wlan[0-9][0-9]*$' >/dev/null 2>&1; then
-			ifconfig $child create ${create_args} && cfg=0
+			${IFCONFIG_CMD} $child create ${create_args} && cfg=0
 			if [ -n "${debug_flags}" ]; then
 				wlandebug -i $child ${debug_flags}
 			fi
 		else
-			i=`ifconfig wlan create ${create_args}`
+			i=`${IFCONFIG_CMD} wlan create ${create_args}`
 			if [ -n "${debug_flags}" ]; then
 				wlandebug -i $i ${debug_flags}
 			fi
-			ifconfig $i name $child && cfg=0
+			${IFCONFIG_CMD} $i name $child && cfg=0
 		fi
 		if autoif $child; then
 			ifn_start $child
@@ -1049,14 +1184,14 @@
 		if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
 			child="${ifn}.${child}"
 			create_args=`get_if_var $child create_args_IF`
-			ifconfig $child create ${create_args} && cfg=0
+			${IFCONFIG_CMD} $child create ${create_args} && cfg=0
 		else
 			create_args="vlandev $ifn `get_if_var $child create_args_IF`"
 			if expr $child : 'vlan[0-9][0-9]*$' >/dev/null 2>&1; then
-				ifconfig $child create ${create_args} && cfg=0
+				${IFCONFIG_CMD} $child create ${create_args} && cfg=0
 			else
-				i=`ifconfig vlan create ${create_args}`
-				ifconfig $i name $child && cfg=0
+				i=`${IFCONFIG_CMD} vlan create ${create_args}`
+				${IFCONFIG_CMD} $i name $child && cfg=0
 			fi
 		fi
 		if autoif $child; then
@@ -1080,7 +1215,7 @@
 		if ! ifexists $child; then
 			continue
 		fi
-		ifconfig -n $child destroy && cfg=0
+		${IFCONFIG_CMD} -n $child destroy && cfg=0
 	done

 	child_vlans=`get_if_var $ifn vlans_IF`
@@ -1091,7 +1226,7 @@
 		if ! ifexists $child; then
 			continue
 		fi
-		ifconfig -n $child destroy && cfg=0
+		${IFCONFIG_CMD} -n $child destroy && cfg=0
 	done

 	return ${cfg}
@@ -1138,13 +1273,13 @@
 			;;
 		*)
 			if expr $i : 'gif[0-9][0-9]*$' >/dev/null 2>&1; then
-				ifconfig $i create >/dev/null 2>&1
+				${IFCONFIG_CMD} $i create >/dev/null 2>&1
 			else
-				gif=`ifconfig gif create`
-				ifconfig $gif name $i
+				gif=`${IFCONFIG_CMD} gif create`
+				${IFCONFIG_CMD} $gif name $i
 			fi
-			ifconfig $i tunnel ${peers}
-			ifconfig $i up
+			${IFCONFIG_CMD} $i tunnel ${peers}
+			${IFCONFIG_CMD} $i up
 			;;
 		esac
 	done
@@ -1210,7 +1345,7 @@
 	# ifconfig_IF_ipx
 	ifconfig_args=`_ifconfig_getargs $ifn ipx`
 	if [ -n "${ifconfig_args}" ]; then
-		ifconfig ${ifn} ${ifconfig_args}
+		${IFCONFIG_CMD} ${ifn} ${ifconfig_args}
 		return 0
 	fi

@@ -1227,7 +1362,7 @@
 	_if=$1
 	_ifs="^"
 	_ret=1
-	ipxList="`ifconfig ${_if} | grep 'ipx ' | tr "\n" "$_ifs"`"
+	ipxList="`${IFCONFIG_CMD} ${_if} | grep 'ipx ' | tr "\n" "$_ifs"`"
 	oldifs="$IFS"

 	IFS="$_ifs"
@@ -1238,7 +1373,7 @@
 		_ipx=`expr "$_ipx" : '.*\(ipx [0-9a-h]\{1,8\}H*\.[0-9a-h]\{1,12\}\).*'`

 		IFS="$oldifs"
-		ifconfig ${_if} ${_ipx} delete
+		${IFCONFIG_CMD} ${_if} ${_ipx} delete
 		IFS="$_ifs"
 		_ret=0
 	done
@@ -1255,10 +1390,10 @@
 	local _if _ifname

 	# ifconfig_IF_name
-	for _if in `ifconfig -l`; do
+	for _if in `${IFCONFIG_CMD} -l`; do
 		_ifname=`get_if_var $_if ifconfig_IF_name`
 		if [ ! -z "$_ifname" ]; then
-			ifconfig $_if name $_ifname
+			${IFCONFIG_CMD} $_if name $_ifname
 		fi
 	done

@@ -1290,7 +1425,7 @@
 	_tmplist=
 	case ${network_interfaces} in
 	[Aa][Uu][Tt][Oo])
-		_autolist="`ifconfig -l`"
+		_autolist="`${IFCONFIG_CMD} -l`"
 		_lo=
 		for _if in ${_autolist} ; do
 			if autoif $_if; then
@@ -1398,7 +1533,7 @@
 {
 	local media

-	case `ifconfig $1 2>/dev/null` in
+	case `${IFCONFIG_CMD} $1 2>/dev/null` in
 	*media:?Ethernet*) media=Ethernet ;;
 	esac

@@ -1410,25 +1545,27 @@
 #	If flag is defined, tentative ones will be excluded.
 network6_getladdr()
 {
-	local proto addr rest
-	ifconfig $1 2>/dev/null | while read proto addr rest; do
-		case ${proto} in
-		inet6)
-			case ${addr} in
-			fe80::*)
-				if [ -z "$2" ]; then
-					echo ${addr}
-					return
-				fi
-				case ${rest} in
-				*tentative*)
-					continue
-					;;
-				*)
-					echo ${addr}
-					return
-				esac
-			esac
+	local _if _flag proto addr rest
+	_if=$1
+	_flag=$2
+
+	${IFCONFIG_CMD} $_if 2>/dev/null | while read proto addr rest; do
+		case "${proto}/${addr}/${_flag}/${rest}" in
+		inet6/fe80::*//*)
+			echo ${addr}
+		;;
+		inet6/fe80:://*tentative*)	# w/o flag
+			sleep `${SYSCTL_N} net.inet6.ip6.dad_count`
+			network6_getladdr $_if $_flags
+		;;
+		inet6/fe80::/*/*tentative*)	# w/ flag
+			echo ${addr}
+		;;
+		*)
+			continue
+		;;
 		esac
+
+		return
 	done
 }
Index: share/man/man5/rc.conf.5
===================================================================
--- share/man/man5/rc.conf.5	(revision 251584)
+++ share/man/man5/rc.conf.5	(working copy)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 9, 2013
+.Dd June 15, 2013
 .Dt RC.CONF 5
 .Os
 .Sh NAME
@@ -1124,44 +1124,59 @@
 .Xr ifconfig 8
 while the order of the other arguments is preserved.
 .Pp
-One can configure more than one IPv4 address with the
-.Va ipv4_addrs_ Ns Aq Ar interface
-variable.
-One or more IP addresses must be provided in Classless Inter-Domain
-Routing (CIDR) address notation, whose last byte can be a range like
-192.0.2.5-23/24.
-In this case the address 192.0.2.5 will be configured with the
+It is possible to add IP alias entries using
+.Xr ifconfig 8
+syntax with the address family keyword such as
+.Li inet .
+Assuming that the interface in question was
+.Li ed0 ,
+it might look something like this:
+.Bd -literal
+ifconfig_ed0_alias0="inet 127.0.0.253 netmask 0xffffffff"
+ifconfig_ed0_alias1="inet 127.0.0.254 netmask 0xffffffff"
+.Ed
+.Pp
+It also possible to configure multiple IP addresses in Classless
+Inter-Domain Routing (CIDR) address notation,
+whose each address component can be a range like
+.Li inet 192.0.2.5-23/24
+or
+.Li inet6 2001:db8:1-f::1/64 .
+.Pp
+In the case of
+.Li 192.0.2.5-23/24 ,
+the address 192.0.2.5 will be configured with the
 netmask /24 and the addresses 192.0.2.6 to 192.0.2.23 with
 the non-conflicting netmask /32 as explained in the
 .Xr ifconfig 8
 alias section.
+Note that this special netmask handling is only for
+.Li inet ,
+not for the other address families such as
+.Li inet6 .
+.Pp
 With the interface in question being
 .Li ed0 ,
 an example could look like:
 .Bd -literal
-ipv4_addrs_ed0="192.0.2.129/27 192.0.2.1-5/28"
+ifconfig_ed0_alias2="inet 192.0.2.129/27"
+ifconfig_ed0_alias3="inet 192.0.2.1-5/28"
 .Ed
 .Pp
-It is also possible to add IP alias entries using
-.Xr ifconfig 8
-syntax with the
-.Dq Li inet
-keyword.
-Assuming that the interface in question was
-.Li ed0 ,
-it might look
-something like this:
-.Bd -literal
-ifconfig_ed0_alias0="inet 127.0.0.253 netmask 0xffffffff"
-ifconfig_ed0_alias1="inet 127.0.0.254 netmask 0xffffffff"
-.Ed
+and so on.
 .Pp
-And so on.
+Note that
+.Va ipv4_addrs_ Ns Aq Ar interface
+variable was supported for IPv4 CIDR address notation.
+It is now deprecated because the functionality was integrated into
+.Va ifconfig_ Ns Ao Ar interface Ac Ns Va _alias Ns Aq Ar n
+though
+.Va ipv4_addrs_ Ns Aq Ar interface
+is still supported for backward compatibility.
+.Pp
 For each
 .Va ifconfig_ Ns Ao Ar interface Ac Ns Va _alias Ns Aq Ar n
-entry with the
-.Dq Li inet
-keyword that is found,
+entry with an address family keyword,
 its contents are passed to
 .Xr ifconfig 8 .
 Execution stops at the first unsuccessful access, so if
@@ -1182,6 +1197,18 @@
 Due to this difficult to manage behavior, the
 .Va ifconfig_ Ns Ao Ar interface Ac Ns Va _alias Ns Aq Ar n
 form is deprecated.
+There is
+.Va ifconfig_ Ns Ao Ar interface Ac Ns Va _aliases
+variable, which has the same functionality as
+.Va ifconfig_ Ns Ao Ar interface Ac Ns Va _alias Ns Aq Ar n
+and can have all of entries in a variable like the following:
+.Bd -literal
+ifconfig_ed0_aliases="\\
+	inet 127.0.0.251 netmask 0xffffffff \\
+	inet 127.0.0.252 netmask 0xffffffff \\
+	inet 127.0.0.253 netmask 0xffffffff \\
+	inet 127.0.0.254 netmask 0xffffffff"
+.Ed
 .Pp
 If the
 .Pa /etc/start_if. Ns Aq Ar interface

----Next_Part(Sun_Jun_16_00_59_41_2013_325)----

----Security_Multipart0(Sun_Jun_16_00_59_41_2013_553)--
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.13 (FreeBSD)

iEUEABECAAYFAlG8j20ACgkQTyzT2CeTzy1SbgCYz2DaayPEuTRee288fK0gYLjC
xgCeNCGFQiwFCsS9v3PUbYk+rQBsXd4=
=PYKu
-----END PGP SIGNATURE-----

----Security_Multipart0(Sun_Jun_16_00_59_41_2013_553)----



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130616.005941.1489449431438337467.hrs>