#!/bin/sh # exit on error set -eo pipefail export board_conf="${1}" UBIOS_INIT_DIR="/etc/ubnt/ubios-init" . "${UBIOS_INIT_DIR}/ubios-init-common.sh" BOARD_ID="$(get_ubnthal_system "systemid")" if [ ! -f ${board_conf} ]; then log_error "Board configuration ${board_conf} not found.\n" exit 1 fi # JSON board config validation jq_validate_json "${board_conf}" # @brief Init kernel parameters function init_system(){ local jq_query_config='.["sysctl-conf"][]|.["name"]' local jq_query_modules='.["kernel-modules"][]|.["name"]+" "+.["parameters"]' local sysctl_dir="/etc/sysctl.d/" local config_file="" jq_exec "${jq_query_modules}" "${board_conf}" | while read -r module_name module_parameters; do modprobe ${module_name} ${module_parameters} done rm -rf "${SYSCTL_CONF_DEFAULT}" sysctl -ea > "${SYSCTL_CONF_DEFAULT}" 2>/dev/null || true jq_exec "${jq_query_config}" "${board_conf}" | while read -r config_name dummy; do config_file="${sysctl_dir}/${config_name}" [ -f "${config_file}" ] || (log_error "WARN: Unable to find configuration ${config_file}, skipping." && continue) sysctl -ep "${config_file}" || (log_error "WARN: Unable to apply configuration ${config_file}, skipping." && continue) done } # @brief Apply settings for interface @param1 function init_adapter_settings() { local if_id="${1}" local jq_query_if_settings='.["interfaces"][]|select(.["identification"]["id"]==$if_id)|.["identification"]["settings"]|to_entries[]|.["key"]+" "+.["value"]' if [ ! -d "/sys/class/net/${if_id}" ]; then log_error "WARN: Unable to apply settings for interface ${if_id}, skipping." return 1; fi jq_exec "${jq_query_if_settings}" "${board_conf}" "--arg if_id ${if_id}" | while read -r opt_key opt_val; do case ${opt_key} in tx-queue-length) ip link set "${if_id}" qlen "${opt_val}" ;; *) log_error "WARN: Unknown option to apply : ${opt_key} for interface ${if_id}, skipping." continue esac done } # @brief Init network function init_network(){ # select all .identification.id attribute from interfaces array local jq_query_ifs_no_br='.["interfaces"][]|select(.["identification"]["init-type"]!="bridge")|.["identification"]["id"]' local iface_mac='' local jq_query_if_settings='.["interfaces"][]|select(.["identification"]["settings"]!=null)|.["identification"]["id"]' # list all bond slaves of bond $bond_id local jq_query_bond_slaves='.["interfaces"][]|select(.["identification"]["id"]==$bond_id)[]|.["bond-slaves"]["interfaces"][]["id"]' # list all bridge slaves of bridge $br_id local jq_query_br_slaves='.["interfaces"][]|select(.["identification"]["id"]==$br_id)|.["bridge"]["interfaces"][]["id"]' # list the first bridge slave of bridge $br_id local jq_query_br_first_slave='.["interfaces"][]|select(.["identification"]["id"]==$br_id)|.["bridge"]["interfaces"][0]["id"]' # select .cpu-port attributes and check presence of .trunk-ports of switch $sw_id from cpu-ports array local jq_query_sw_cpu='.["switches"][]?|select(.["id"]==$sw_id)["cpu-ports"][]|(.["cpu-port"]|tostring)+" "+(has("trunk-ports")|tostring)' # select .trunk-ports of switch $sw_id and cpu-port $cpu_port from cpu-ports array local jq_query_sw_trunk_ports='.["switches"][]?|select(.["id"]==$sw_id)["cpu-ports"][]|select(.["cpu-port"]==($cpu_port|tonumber))|.["trunk-ports"]|join(" ")' # select .interface.id and edge-port attributes of switch $sw_id and cpu-port==$cpu_port from edge-ports array local jq_query_sw_edge='.["switches"][]?|select(.["id"]==$sw_id)["edge-ports"][]|select(.["cpu-port"]==($cpu_port|tonumber))|.["interface"]["id"]+" "+(.["edge-port"]|tostring)' # select init-type attribute of interface with $if_id from interfaces array local jq_query_if_type='.["interfaces"][]|select(.["identification"]["id"]==$if_id)|.["identification"]["init-type"]' # select svlan attribute of interface with $if_id from interfaces array local jq_query_if_svlan='.["interfaces"][]|select(.["identification"]["id"]==$if_id)|(.["identification"]["svlan"]|tostring)' local jq_query_if_svlan_fid='.["interfaces"][]|select(.["identification"]["id"]==$if_id)|(.["identification"]["svlan-fid"]|tostring)' local jq_query_edge_to_cpu='.["switches"][]|select(.["id"]==$sw_id)["edge-ports"][]|select(.["interface"]!=null)|.["interface"]["id"]+" "+(.["edge-port"]|tostring)+" "+(.["cpu-port"]|tostring)' local jq_query_slave_to_cpu='.["switches"][]|select(.["id"]==$sw_id)["edge-ports"][]|select(.["switch"]!=null)|.["switch"]["id"]+" "+(.["edge-port"]|tostring)+" "+(.["cpu-port"]|tostring)' local jq_query_vid='.["interfaces"][]|select(.["identification"]["id"]==$if_id)|.["identification"]["vlan"]' local iface_type='' local iface_svid='' local iface_sfid='' local switch_port='' local addr_idx=0 rename_interface log_info "Creating bond interfaces ..." jq_exec "${jq_query_bond}" "${board_conf}" | while read -r bond_id bond_mode bond_policy dummy; do # create a bond device ip link add "${bond_id}" type bond mode "${bond_mode}" xmit_hash_policy "${bond_policy}" done log_info "Creating bridge interfaces ..." jq_exec "${jq_query_br}" "${board_conf}" | while read -r br_id dummy; do # create bridge brctl addbr "${br_id}" # add ifaces to bridge jq_exec "${jq_query_br_slaves}" "${board_conf}" "--arg br_id ${br_id}" | while read -r if_id dummy; do if [ ! -d "/sys/class/net/${if_id}" ]; then log_error "WARN: Unable to add ${if_id} interface to the bridge, skipping." continue; fi brctl addif "${br_id}" "${if_id}" ip link set ${if_id} up done ip link set "${br_id}" up done log_info "Creating macvlan interfaces ..." jq_exec "${jq_query_macvlan}" "${board_conf}" | while read -r if_id parent_id dummy; do ip link add link "${parent_id}" "${if_id}" type macvlan # set parent to promiscuous mode, which allows acceptance of frames for the MAC VLAN sub-interfaces ip link set "${parent_id}" promisc on done log_info "Creating svlan interfaces ..." jq_exec "${jq_query_svlan}" "${board_conf}" | while read -r if_id parent_id svlan_id dummy; do ip link add link "${parent_id}" "${if_id}" type vlan id ${svlan_id} protocol 802.1ad ip link set "${parent_id}" promisc on done log_info "Creating vlan interfaces ..." jq_exec "${jq_query_vlan}" "${board_conf}" | while read -r if_id parent_id vid dummy; do ip link add link "${parent_id}" name "${if_id}" type vlan id ${vid} if [ ! -d "/sys/class/net/${if_id}" ]; then log_error "WARN: Unable to file ${if_id} interface, skipping." continue; fi echo e > "/sys/class/net/${if_id}/queues/rx-0/rps_cpus" echo e > "/sys/class/net/${parent_id}/queues/rx-0/rps_cpus" done log_info "Setting MAC addresses for interfaces (excluding bridges) .." for if_id in $(jq_exec "${jq_query_ifs_no_br}" "${board_conf}"); do if [ ! -d "/sys/class/net/${if_id}" ]; then log_error "WARN: Unable to set the MAC address for ${if_id} interface, skipping." continue; fi iface_mac=$(get_ubnthal_mac ${if_id}) # Use locally administered address if ubnthal doesn't include the interface if [ -z "${iface_mac}" ]; then iface_mac=$(generate_mac ${addr_idx}) addr_idx=$((addr_idx+1)) fi ip link set dev "${if_id}" address "${iface_mac}" done log_info "Setting vlan parent interface up ..." jq_exec "${jq_query_vlan}" "${board_conf}" | while read -r if_id parent_id vid dummy; do ip link set dev "${parent_id}" up done log_info "Setting mac for bridges ..." jq_exec "${jq_query_br}" "${board_conf}" | while read -r br_id dummy; do iface=$(jq_exec "${jq_query_br_first_slave}" "${board_conf}" "--arg br_id ${br_id}") if [ ! -d "/sys/class/net/${iface}" ]; then log_error "WARN: Unable to inherit the MAC address of ${iface} interface, skipping." continue; fi iface_mac=$(get_sys_mac ${iface}) ip link set "${br_id}" address "${iface_mac}" done log_info "Enslave bond interfaces ..." jq_exec "${jq_query_bond}" "${board_conf}" | while read -r bond_id bond_mode bond_policy dummy; do # add ifaces to bridge jq_exec "${jq_query_bond_slaves}" "${board_conf}" "--arg bond_id ${bond_id}" | while read -r if_id dummy; do if [ ! -d "/sys/class/net/${if_id}" ]; then log_error "WARN: Unable to add ${if_id} interface to the bond, skipping." continue; fi ip link set "${if_id}" down ip link set "${if_id}" master "${bond_id}" ip link set "${if_id}" up done ip link set "${bond_id}" up done log_info "Passing interfaces to link manager ..." jq_exec "${jq_query_lm_list}" "${board_conf}" | while read -r if_id lm_type dummy; do case ${lm_type} in rtlm) switch_port=$(jq_exec "${jq_query_sw_edge_by_ifname}" "${board_conf}" "--arg if_id ${if_id}") if [ "${switch_port}" = "" -o ! -d "/sys/devices/rtlm/${switch_port}" ]; then log_error "WARN: Unable to find RTLM mapping endpoint for ${iface} interface, skipping." continue fi echo "${if_id}" > /sys/devices/rtlm/${switch_port}/devname ;; *) log_error "WARN: Unknown link manager type ${lm_type}, skipping" continue esac done if udapi_server_not_present; then log_info "Initializing switch chips ..." jq_exec "${jq_query_sw}" "${board_conf}" | while read -r sw_id dummy; do swconfig dev "${sw_id}" set reset 1 jq_exec "${jq_query_sw_cpu}" "${board_conf}" "--arg sw_id ${sw_id}" | while read -r cpu_port is_trunk dummy; do trunk_id="${cpu_port}" if [ "${is_trunk}" = "true" ]; then # expand CPU ports cpu_port=$(jq_exec "${jq_query_sw_trunk_ports}" "${board_conf}" "--arg sw_id ${sw_id} --arg cpu_port ${trunk_id}" ) swconfig dev "${sw_id}" trunk "${trunk_id}" set ports "${cpu_port}" fi jq_exec "${jq_query_sw_edge}" "${board_conf}" "--arg sw_id ${sw_id} --arg cpu_port ${trunk_id}" | while read -r edge_if edge_port dummy; do if [ ! -d "/sys/class/net/${edge_if}" ]; then log_error "WARN: Unable to find interface ${edge_if}, skipping." continue; fi iface_type=$(jq_exec "${jq_query_if_type}" "${board_conf}" "--arg if_id ${edge_if}") case ${iface_type} in mac-vlan) # Create ACL rules for traffic redirection swconfig dev "${sw_id}" set enable_acl 1 swconfig dev "${sw_id}" set acl_redirect "add mac_src '*' mac_dst '*' ports_src '${edge_port}' port_dst '${cpu_port}'" swconfig dev "${sw_id}" set acl_redirect "add mac_src '$(get_sys_mac ${edge_if})' mac_dst '*' ports_src '${cpu_port}' port_dst '${edge_port}'" ;; svlan) # Create SVLAN rule iface_svid=$(jq_exec "${jq_query_if_svlan}" "${board_conf}" "--arg if_id ${edge_if}") iface_sfid=$(jq_exec "${jq_query_if_svlan_fid}" "${board_conf}" "--arg if_id ${edge_if}") swconfig dev "${sw_id}" port "${edge_port}" set enable_vlan 0 eval swconfig dev "${sw_id}" svlan "${iface_svid}" set ports "'${edge_port} $(decorate_string_list "" "${cpu_port}" "t")'" swconfig dev "${sw_id}" svlan "${iface_svid}" set fid "${iface_sfid}" ;; vlan) # Create VLAN rule vid=$(jq_exec "${jq_query_vid}" "${board_conf}" "--arg if_id ${edge_if}") swconfig dev "${sw_id}" vlan ${vid} set ports "${edge_port} $(decorate_string_list "" "${cpu_port}" "t")" # vlan setting for master switch and slave switch jq_exec "${jq_query_slave_to_cpu}" "${board_conf}" "--arg sw_id ${sw_id}" | while read -r slave_id ep_id cp_id dummy; do local master_id="${sw_id}" jq_exec "${jq_query_edge_to_cpu}" "${board_conf}" "--arg sw_id ${slave_id}" | while read -r if_id dummy; do local vid=$(jq_exec "${jq_query_vid}" "${board_conf}" "--arg if_id ${if_id}") swconfig dev "${master_id}" vlan ${vid} set ports "${ep_id}t ${cp_id}t" done done ;; *) log_error "WARN: Unknown iface type ${iface_type}, skipping" continue esac done done # save switch configuration swconfig dev "${sw_id}" set apply 1 done fi log_info "Apply interface's settings .." jq_exec "${jq_query_if_settings}" "${board_conf}" | while read -r if_id dummy; do init_adapter_settings "${if_id}" done } # @brief Init shift LED trigger function init_shift_led_trigger(){ local jq_query_ethx_id='.["interfaces"][]|select(.["identification"]["id"]|startswith("eth"))|.["identification"]["id"]' jq_exec "${jq_query_ethx_id}" "${board_conf}" | while read -r if_name dummy; do if [ ! -d "/sys/class/net/${if_name}" ]; then log_error "WARN: Unable to file ${if_name} interface, skipping." continue; fi # setup sysfs LED subsystem echo netdev > /sys/class/leds/${if_name}/trigger echo ${if_name} > /sys/class/leds/${if_name}/device_name echo "link tx rx" > /sys/class/leds/${if_name}/mode done } # @brief Init power gpio setting function init_power_io(){ local jq_query_pwr_gpio='.["descriptors"]|.["power"][]?|select(has("connected"))|.["connected"]|.["path"]|[.|split("/sys/class/gpio/gpio")[]|split("/value")[]|select(.!="")]|first|tonumber' jq_exec "${jq_query_pwr_gpio}" "${board_conf}" | while read -r pwr_gpio dummy; do gpio_export "${pwr_gpio}" done } function main(){ # get model local model=$(jq_exec "${jq_query_model}" "${board_conf}") init_system init_udapi_config_dir init_dropbear_key_dir init_network # For a complete working title list, please check the description of # identification.id attribute in ubios-init/config-board/uispr/IMPORTANT case ${model} in uispr-cherry|uispr-damson) init_power_io ;; uisp-r-lite|uispr-almond) init_shift_led_trigger ;; esac return 0 } main $@ exit $?