#!/bin/ksh93 # # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2020 Joyent, Inc. # # Traditionally, when a Triton compute node boots, the network is not # configured until after the local filesystems are mounted (in fact # network/physical:default depends upon /system/filesystem/smartdc). Most # obviously, in the case of a head node or a standalone SmartOS install, the # network configuration is stored on the local zpool, so the network cannot # be configured until this happens. # # For Triton compute nodes with encrypted zpools, we must enable the admin # network before the local zpool filesytems are online -- we have to be able # to communicate to the head node services to obtain the pin to unlock the # local zpool. For PXE booted Triton compute nodes, we therefore configure # the admin network sooner via the network/early-admin:default service. When # network/physical:default runs, it will skip the configuration of the admin # network and configuring the remaining interfaces. # # If we are not a Triton compute node, we exit successfully almost immediately # without configuring the admin network. When the network/physical:default # service runs, it will configure all the network interfaces as it traditionally # has PATH=/bin:/usr/bin:/sbin:/usr/sbin . /lib/svc/share/smf_include.sh . /lib/sdc/config.sh . /lib/sdc/network.sh PS4='+ [$LINENO] ' set -o xtrace if ! smf_is_globalzone; then echo "Non-global zone; no action required; exiting" exit $SMT_EXIT_OK fi # XXX Until OS-8367 is sorted out, immediately enable the varpd service. # SMF will properly cope with things if it fails (and blocks both # network/physical and zones). svcadm enable varpd if ! boot_file_config_enabled; then echo "Boot-time networking files not present; exiting" exit $SMF_EXIT_OK fi function fatal { # XXX: For SMF methods, does it matter/better to redirect to stderr? echo "Error: $*" >&2 exit $SMF_EXIT_ERR_FATAL } if ! boot_file_config_valid; then echo "ERROR: boot-time network config file incorrect" >&2 exit $SMF_EXIT_ERR_CONFIG fi unset aggrs unset tags typeset -A tagv typeset -A aggr_links aggr_mode typeset -A ip ip6 netmask gateway gateway6 mtu mac /usr/lib/sdc/net-boot-config | while IFS="=" read var value; do if [[ "$var" =~ _nic$ ]]; then name=${var%_nic} tags+=("${name}") tagv[$name]="$value" elif [[ "$var" =~ _aggr$ ]]; then name=${var%_aggr} aggrs+=(${name}) aggr_links[$name]="${value//,/ }" elif [[ "$var" =~ _lacp_mode$ ]]; then name=${var%_lacp_mode} aggr_mode[$name]="$value" elif [[ "$var" =~ _mtu$ ]]; then (( value < 1500 || value > 65535 )) && fatal "ERROR: $var MTU value \'$value\' is not in" \ "range [1500, 65535]" name=${var%_mtu} mtu[$name]="$value" elif [[ "$var" =~ _ip$ ]]; then name=${var%_ip} ip[$name]="$value" elif [[ "$var" =~ _ip6$ ]]; then name=${var%_ip6} ip6[$name]="$value" elif [[ "$var" =~ _netmask$ ]]; then name=${var%_netmask} netmask[$name]="$value" elif [[ "$var" =~ _gateway$ ]]; then name=${var%_gateway} gateway[$name]="$value" elif [[ "$var" =~ _gateway6$ ]]; then name=${var%_gateway6} gateway6[$name]="$value" elif [[ "$var" =~ _mac$ ]]; then name=${var%_mac} mac[$name]="$value" elif [[ "$var" == "dns_resolvers" ]]; then dns_resolvers=(${value//,/ }) fi eval "CONFIG_$var"="$value" done # This must happen befor any other dladm commands (which includes log_if_state) # or else dladm commands can fail dladm init-phys log_if_state before typeset -A mac_to_link out=$(dladm show-phys -mpo link,address) (( $? == 0 )) || fatal "dladm show-phys failed" while IFS=: read link addr; do macaddr=$(normalize_mac $addr) mac_to_link["$macaddr"]="$link" done <<< "$out" ADMIN_NIC_TAG=${CONFIG_admin_tag:-"admin"} [[ -n "${tagv[$ADMIN_NIC_TAG]}" ]] || \ fatal "ERROR: admin nic tag '$ADMIN_NIC_TAG' not present" # Set $nic to the link that has the admin nic tag. For unfortunate # historic reasons, for aggrs, the MAC address and link name of an aggr # are the same value by net-boot-config (and the source of many errors). # If ${aggr_links[$nic]} is non-empty, it means $nic isn't a MAC address # but an aggr name (and we're done). Otherwise we must map the MAC address # from $tagv back to the link. nic="${tagv[$ADMIN_NIC_TAG]}" if [[ -z "${aggr_links[$nic]}" ]]; then if !valid_mac "$nic"; then fatal "ERROR: admin mac address $nic not found on system" fi _nic=${mac_to_link[$nic]} if [[ -z "$_nic" ]]; then fatal "ERROR: Invalid value of ${ADMIN_NIC_TAG}_nic ($nic)" fi nic=$_nic fi # If there are other nic tags configured on the same link as # the admin tag, find the largest MTU to use to set the # datalink MTU dlmtu="${mtu[$ADMIN_NIC_TAG]}" for tag in ${tags[@]}; do tagmac="${tagv[$tag]}" # If the 'mac' for the nic tag is actually an aggr, the # tag will appear in $aggr_links (and we want to use that as # the link name). If it is not an aggr, we need to map the # MAC address to the link name so we can check if $tag # resides on the same link as the admin interface if [[ -n "${aggr_links[$tagmac]}" ]]; then link="$tagmac" else link="${mac_to_link[$tagmac]}" fi if [[ "$link" == "$nic" && $dlmtu -lt ${mtu[$tag]} ]]; then dlmtu=${mtu[$tag]} fi done if [[ -n "${aggr_links[$nic]}" ]]; then mode=${aggr_mode[$nic]:-"off"} for l in ${aggr_links[$nic]}; do [[ -n "${mac_to_link[$l]}" ]] || fatal "MAC '$l' not present" link="${mac_to_link[$l]}" if [[ -n "$dlmtu" ]]; then dladm set-linkprop -p mtu=$dlmtu $link || \ fatal "ERROR: Failed to set mtu on $link to $dlmtu" fi links+="${link} " done links="${links% }" echo "Creating aggr: $nic (mode=$mode, links=${links})" dladm create-aggr -l ${links// / -l } -L $mode $nic fi if [[ -n "$dlmtu" ]]; then dladm set-linkprop -p mtu=$dlmtu $nic || \ fatal "ERROR: Failed to set mtu on aggr $nic to $dlmtu" fi driver=${nic%%+([0-9])} get_link_state $nic if [[ "$link_state" == "down" ]]; then echo "admin nic '${nic}' is down: unplumbing" /sbin/ifconfig $nic down unplumb wait_for_nic_state $nic "unknown" fi # There's some sort of race condition in the bnx driver: if the plumb # command comes too soon after the unplumb, the interface can come up # in a state where it never fires interrupts for link state changes. if [[ "$driver" == "bnx" ]]; then sleep 5 fi /sbin/ifconfig $nic plumb mtu ${mtu[$ADMIN_NIC_TAG]} wait_for_nic_state $nic "up" if [[ -n "${ip[$ADMIN_NIC_TAG]}" ]]; then /sbin/ifconfig $nic inet ${ip[$ADMIN_NIC_TAG]} \ netmask ${netmask[$ADMIN_NIC_TAG]:-"+"} up [[ -n "${gateway[$ADMIN_NIC_TAG]}" ]] && \ /usr/sbin/route add default ${gateway[$ADMIN_NIC_TAG]} fi if [[ -n "${ip6[$ADMIN_NIC_TAG]}" ]]; then /sbin/ifconfig $nic inet6 plumb mtu ${mtu[$ADMIN_NIC_TAG]} [[ "${ip6[$ADMIN_NIC_TAG]}" != "addrconf" ]] && \ /sbin/ifconfig $nic inet6 addif ${ip6[$ADMIN_NIC_TAG]} preferred up [[ -n "${gateway6[$ADMIN_NIC_TAG]}" ]] && \ /usr/sbin/route add -inet6 default ${gateway6[$ADMIN_NIC_TAG]} fi # Add just the routes reachable through the admin network -- usually these are # only present with rack aware networking (RAN) /usr/lib/sdc/net-boot-config --routes | while read dst gw; do if ! ip_in_net $gw ${ip[$ADMIN_NIC_TAG]} ${netmask[$ADMIN_NIC_TAG]}; then continue fi route add "$dst" "$gw" done if [[ -n "${CONFIG_dns_domain}" && -n ${dns_resolvers[0]} ]]; then echo "search ${CONFIG_dns_domain}" > /etc/resolv.conf for serv in ${dns_resolvers[@]}; do echo "nameserver $serv" >> /etc/resolv.conf done fi touch /etc/svc/volatile/.early_admin_setup log_if_state after