From 7eb721425e9655a5910f06d54672e2f639414c39 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 19 Jun 2014 16:06:44 +0000 Subject: [PATCH] base-files: depend on jsonfilter and rewrite network.sh to use it Switches /lib/functions/network.sh from jshn based json parsing to jsonfilter expression while keeping the existing api. Expensive methods like "network_find_wan" are up to 20x faster now. Signed-off-by: Jo-Philipp Wich SVN-Revision: 41281 --- package/base-files/Makefile | 6 +- .../base-files/files/lib/functions/network.sh | 441 +++++------------- 2 files changed, 127 insertions(+), 320 deletions(-) diff --git a/package/base-files/Makefile b/package/base-files/Makefile index eea9ecb8e0..a699084808 100644 --- a/package/base-files/Makefile +++ b/package/base-files/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2007-2013 OpenWrt.org +# Copyright (C) 2007-2014 OpenWrt.org # Copyright (C) 2010 Vertical Communications # # This is free software, licensed under the GNU General Public License v2. @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/version.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=base-files -PKG_RELEASE:=153 +PKG_RELEASE:=154 PKG_FILE_DEPENDS:=$(PLATFORM_DIR)/ $(GENERIC_PLATFORM_DIR)/base-files/ PKG_BUILD_DEPENDS:=opkg/host @@ -28,7 +28,7 @@ endif define Package/base-files SECTION:=base CATEGORY:=Base system - DEPENDS:=+netifd +libc +procd + DEPENDS:=+netifd +libc +procd +jsonfilter TITLE:=Base filesystem for OpenWrt URL:=http://openwrt.org/ VERSION:=$(PKG_RELEASE)-$(REVISION) diff --git a/package/base-files/files/lib/functions/network.sh b/package/base-files/files/lib/functions/network.sh index 7d06aa40e9..86ab8905f1 100644 --- a/package/base-files/files/lib/functions/network.sh +++ b/package/base-files/files/lib/functions/network.sh @@ -1,427 +1,234 @@ -. /usr/share/libubox/jshn.sh - -__network_set_cache() -{ - if [ -n "$3" ]; then - eval "export -- __NETWORK_CV_$1='$3'" - __NETWORK_CACHE="${__NETWORK_CACHE:+$__NETWORK_CACHE }__NETWORK_CV_$1" - elif json_get_var "__NETWORK_CV_$1" "$2"; then - __NETWORK_CACHE="${__NETWORK_CACHE:+$__NETWORK_CACHE }__NETWORK_CV_$1" - fi -} - -__network_export() -{ - local __v="__NETWORK_CV_$2" - eval "export -- \"$1=\${$__v:+\${$__v$4}$3}\"; [ -n \"\${$__v+x}\" ]" -} - -__network_parse_ifstatus() -{ - local __iface="$1" - local __key="${__iface}" +# 1: destination variable +# 2: interface +# 3: path +# 4: separator +# 5: limit +__network_ifstatus() { local __tmp - local __idx - local __list - local __old_ns - case "$__iface" in - *[^a-zA-Z0-9_]*) return 1 ;; - esac + [ -z "$__NETWORK_CACHE" ] && \ + export __NETWORK_CACHE="$(ubus call network.interface dump)" - __network_export __tmp "${__key}__parsed" && return 0 - __tmp="$(ubus call network.interface."$__iface" status 2>/dev/null)" - [ -n "$__tmp" ] || return 1 + __tmp="$(jsonfilter ${4:+-F "$4"} ${5:+-l "$5"} -s "$__NETWORK_CACHE" -e "$1=@.interface${2:+[@.interface='$2']}$3")" - json_set_namespace "network" __old_ns - json_load "$__tmp" + [ -z "$__tmp" ] && \ + unset "$1" && \ + return 1 - __network_set_cache "${__key}__parsed" "" "1" - - for __tmp in "" "_inactive"; do - - __key="${__key}${__tmp}" - - # parse addresses - local __family - for __family in 4 6; do - - __list="" - - if json_is_a "ipv${__family}_address" array; then - - json_select "ipv${__family}_address" - - __idx=1 - - while json_is_a "$__idx" object; do - - json_select "$((__idx++))" - json_get_var __tmp "address" && __list="${__list:+$__list }$__tmp" - json_get_var __tmp "mask" && __list="${__list:+$__list/}$__tmp" - json_select ".." - - done - - json_select ".." - - fi - - if json_is_a "ipv${__family}_prefix_assignment" array; then - - json_select "ipv${__family}_prefix_assignment" - - __idx=1 - - while json_is_a "$__idx" object; do - - json_select "$((__idx++))" - json_get_var __tmp "address" && __list="${__list:+$__list }${__tmp}1" - json_get_var __tmp "mask" && __list="${__list:+$__list/}$__tmp" - json_select ".." - - done - - json_select ".." - - fi - - if [ -n "$__list" ]; then - __network_set_cache "${__key}_address${__family}" "" "$__list" - fi - - done - - # parse prefixes - if json_is_a "ipv6_prefix" array; then - json_select "ipv6_prefix" - - __idx=1 - __list="" - - while json_is_a "$__idx" object; do - - json_select "$((__idx++))" - json_get_var __tmp "address" && __list="${__list:+$__list }$__tmp" - json_get_var __tmp "mask" && __list="${__list:+$__list/}$__tmp" - json_select ".." - - done - - json_select ".." - - - if [ -n "$__list" ]; then - __network_set_cache "${__key}_prefix6" "" "$__list" - fi - - fi - - # parse routes - if json_is_a route array; then - - json_select "route" - - local __idx=1 - while json_is_a "$__idx" object; do - - json_select "$((__idx++))" - json_get_var __tmp table - - if [ -z "$__tmp" ]; then - json_get_var __tmp target - - case "${__tmp}" in - 0.0.0.0) - __network_set_cache "${__key}_gateway4" nexthop - ;; - ::) - __network_set_cache "${__key}_gateway6" nexthop - ;; - esac - fi - - json_select ".." - - done - - json_select ".." - - fi - - # parse dns info - local __field - for __field in "dns_server" "dns_search"; do - if json_is_a "$__field" array; then - - json_select "$__field" - - __idx=1 - __list="" - - while json_is_a "$__idx" string; do - - json_get_var __tmp "$((__idx++))" - __list="${__list:+$__list }$__tmp" - - done - - json_select ".." - - if [ -n "$__list" ]; then - __network_set_cache "${__key}_${__field}" "" "$__list" - fi - fi - done - - # parse up state, proto, device and physdev - for __field in "up" "proto" "l3_device" "device"; do - if json_get_type __tmp "$__field"; then - __network_set_cache "${__key}_${__field}" "$__field" - fi - done - - # descend into inactive table - json_is_a "inactive" object && json_select "inactive" - - done - - json_cleanup - json_set_namespace "$__old_ns" - - return 0 -} - - -__network_ipaddr() -{ - local __var="$1" - local __iface="$2" - local __field="$3" - local __subst="$4" - local __list="$5" - local __tmp="" - - __network_parse_ifstatus "$__iface" || return 1 - - if [ $__list = 1 ] && [ -n "$__subst" ]; then - __network_export "__list" "${__iface}_${__field}" - - for __list in $__list; do - eval "__tmp=\"${__tmp:+$__tmp }\${__list$__subst}\"" - done - - export -- "$__var=$__tmp"; [ -n "$__tmp" ] - return $? - fi - - __network_export "$__var" "${__iface}_${__field}" "" "$__subst" - return $? + eval "$__tmp" } # determine first IPv4 address of given logical interface # 1: destination variable # 2: interface -network_get_ipaddr() { __network_ipaddr "$1" "$2" "address4" "%%/*" 0; } +network_get_ipaddr() { + __network_ifstatus "$1" "$2" "['ipv4-address'][0].address"; +} # determine first IPv6 address of given logical interface # 1: destination variable # 2: interface -network_get_ipaddr6() { __network_ipaddr "$1" "$2" "address6" "%%/*" 0; } +network_get_ipaddr6() { + __network_ifstatus "$1" "$2" "['ipv6-address'][0].address"; +} # determine first IPv4 subnet of given logical interface # 1: destination variable # 2: interface -network_get_subnet() { __network_ipaddr "$1" "$2" "address4" "%% *" 0; } +network_get_subnet() { + __network_ifstatus "$1" "$2" "['ipv4-address'][0]['address','mask']" "/" +} # determine first IPv6 subnet of given logical interface # 1: destination variable # 2: interface -network_get_subnet6() { __network_ipaddr "$1" "$2" "address6" "%% *" 0; } +network_get_subnet6() { + __network_ifstatus "$1" "$2" "['ipv6-address'][0]['address','mask']" "/" +} # determine first IPv6 prefix of given logical interface # 1: destination variable # 2: interface -network_get_prefix6() { __network_ipaddr "$1" "$2" "prefix6" "%% *" 0; } +network_get_prefix6() { + __network_ifstatus "$1" "$2" "['ipv6-prefix'][0]['address','mask']" "/" +} # determine all IPv4 addresses of given logical interface # 1: destination variable # 2: interface -network_get_ipaddrs() { __network_ipaddr "$1" "$2" "address4" "%%/*" 1; } +network_get_ipaddrs() { + __network_ifstatus "$1" "$2" "['ipv4-address'][*].address" +} # determine all IPv6 addresses of given logical interface # 1: destination variable # 2: interface -network_get_ipaddrs6() { __network_ipaddr "$1" "$2" "address6" "%%/*" 1; } +network_get_ipaddrs6() { + local __addr + local __list="" + + if __network_ifstatus "__addr" "$2" "['ipv6-address','ipv6-prefix-assignment'][*].address"; then + for __addr in $__addr; do + case "$__addr" in + *:) __list="${__list:+$__list }${__addr}1" ;; + *) __list="${__list:+$__list }${__addr}" ;; + esac + done + + export "$1=$__list" + return 0 + fi + + unset "$1" + return 1 +} # determine all IPv4 subnets of given logical interface # 1: destination variable # 2: interface -network_get_subnets() { __network_ipaddr "$1" "$2" "address4" "" 1; } +network_get_subnets() { + __network_ifstatus "$1" "$2" "['ipv4-address'][*]['address','mask']" "/ " +} # determine all IPv6 subnets of given logical interface # 1: destination variable # 2: interface -network_get_subnets6() { __network_ipaddr "$1" "$2" "address6" "" 1; } +network_get_subnets6() { + local __addr + local __list="" + + if __network_ifstatus "__addr" "$2" "['ipv6-address','ipv6-prefix-assignment'][*]['address','mask']" "/ "; then + for __addr in $__addr; do + case "$__addr" in + *:/*) __list="${__list:+$__list }${__addr%/*}1/${__addr##*/}" ;; + *) __list="${__list:+$__list }${__addr}" ;; + esac + done + + export "$1=$__list" + return 0 + fi + + unset "$1" + return 1 +} # determine all IPv6 prefixes of given logical interface # 1: destination variable # 2: interface -network_get_prefixes6() { __network_ipaddr "$1" "$2" "prefix6" "" 1; } - - -__network_gateway() -{ - local __var="$1" - local __iface="$2" - local __family="$3" - local __inactive="$4" - - __network_parse_ifstatus "$__iface" || return 1 - - if [ "$__inactive" = 1 -o "$__inactive" = "true" ]; then - __network_export "$__var" "${__iface}_inactive_gateway${__family}" && \ - return 0 - fi - - __network_export "$__var" "${__iface}_gateway${__family}" - return $? +network_get_prefixes6() { + __network_ifstatus "$1" "$2" "['ipv6-prefix'][*]['address','mask']" "/ " } # determine IPv4 gateway of given logical interface # 1: destination variable # 2: interface # 3: consider inactive gateway if "true" (optional) -network_get_gateway() { __network_gateway "$1" "$2" 4 "${3:-0}"; } +network_get_gateway() { + __network_ifstatus "$1" "$2" ".route[@.target='0.0.0.0' && !@.table].nexthop" "" 1 && \ + return 0 + + [ "$3" = 1 -o "$3" = "true" ] && \ + __network_ifstatus "$1" "$2" ".inactive.route[@.target='0.0.0.0' && !@.table].nexthop" "" 1 +} # determine IPv6 gateway of given logical interface # 1: destination variable # 2: interface # 3: consider inactive gateway if "true" (optional) -network_get_gateway6() { __network_gateway "$1" "$2" 6 "${3:-0}"; } +network_get_gateway6() { + __network_ifstatus "$1" "$2" ".route[@.target='::' && !@.table].nexthop" "" 1 && \ + return 0 - -__network_dns() { - local __var="$1" - local __iface="$2" - local __field="$3" - local __inactive="$4" - - __network_parse_ifstatus "$__iface" || return 1 - - if [ "$__inactive" = 1 -o "$__inactive" = "true" ]; then - __network_export "$__var" "${__iface}_inactive_${__field}" && \ - return 0 - fi - - __network_export "$__var" "${__iface}_${__field}" - return $? + [ "$3" = 1 -o "$3" = "true" ] && \ + __network_ifstatus "$1" "$2" ".inactive.route[@.target='::' && !@.table].nexthop" "" 1 } # determine the DNS servers of the given logical interface # 1: destination variable # 2: interface # 3: consider inactive servers if "true" (optional) -network_get_dnsserver() { __network_dns "$1" "$2" dns_server "${3:-0}"; } +network_get_dnsserver() { + __network_ifstatus "$1" "$2" "['dns-server'][*]" && return 0 + + [ "$3" = 1 -o "$3" = "true" ] && \ + __network_ifstatus "$1" "$2" ".inactive['dns-server'][*]" +} # determine the domains of the given logical interface # 1: destination variable # 2: interface # 3: consider inactive domains if "true" (optional) -network_get_dnssearch() { __network_dns "$1" "$2" dns_search "${3:-0}"; } +network_get_dnssearch() { + __network_ifstatus "$1" "$2" "['dns-search'][*]" && return 0 + + [ "$3" = 1 -o "$3" = "true" ] && \ + __network_ifstatus "$1" "$2" ".inactive['dns-search'][*]" +} +# 1: destination variable +# 2: addr +# 3: inactive __network_wan() { - local __var="$1" - local __family="$2" - local __inactive="$3" - local __iface + __network_ifstatus "$1" "" \ + "[@.route[@.target='$2' && !@.table]].interface" "" 1 && \ + return 0 - for __iface in $(ubus list | sed -ne 's/^network\.interface\.//p'); do - if [ "$__iface" != loopback ]; then - if __network_gateway "$__var" "$__iface" "$__family" "$__inactive"; then - eval "export -- \"$__var=$__iface\"" - return 0 - fi - fi - done - - eval "export -- \"$__var=\"" - return 1 + [ "$3" = 1 -o "$3" = "true" ] && \ + __network_ifstatus "$1" "" \ + "[@.inactive.route[@.target='$2' && !@.table]].interface" "" 1 } # find the logical interface which holds the current IPv4 default route # 1: destination variable # 2: consider inactive default routes if "true" (optional) -network_find_wan() { __network_wan "$1" 4 "${2:-0}"; } +network_find_wan() { __network_wan "$1" "0.0.0.0" "$2"; } # find the logical interface which holds the current IPv6 default route # 1: destination variable # 2: consider inactive dafault routes if "true" (optional) -network_find_wan6() { __network_wan "$1" 6 "${2:-0}"; } - - -__network_device() -{ - local __var="$1" - local __iface="$2" - local __field="$3" - - __network_parse_ifstatus "$__iface" || return 1 - __network_export "$__var" "${__iface}_${__field}" - return $? -} +network_find_wan6() { __network_wan "$1" "::" "$2"; } # test whether the given logical interface is running # 1: interface network_is_up() { local __up - __network_device __up "$1" up && [ $__up -eq 1 ] + __network_ifstatus "__up" "$1" ".up" && [ "$__up" = 1 ] } # determine the protocol of the given logical interface # 1: destination variable # 2: interface -network_get_protocol() { __network_device "$1" "$2" proto; } +network_get_protocol() { __network_ifstatus "$1" "$2" ".proto"; } # determine the layer 3 linux network device of the given logical interface # 1: destination variable # 2: interface -network_get_device() { __network_device "$1" "$2" l3_device; } +network_get_device() { __network_ifstatus "$1" "$2" ".l3_device"; } # determine the layer 2 linux network device of the given logical interface # 1: destination variable # 2: interface -network_get_physdev() { __network_device "$1" "$2" device; } - - -__network_defer() -{ - local __device="$1" - local __defer="$2" - - json_init - json_add_string name "$__device" - json_add_boolean defer "$__defer" - - ubus call network.device set_state "$(json_dump)" 2>/dev/null -} +network_get_physdev() { __network_ifstatus "$1" "$2" ".device"; } # defer netifd actions on the given linux network device # 1: device name -network_defer_device() { __network_defer "$1" 1; } +network_defer_device() +{ + ubus call network.device set_state \ + "$(printf '{ "name": "%s", "defer": true }' "$1")" 2>/dev/null +} # continue netifd actions on the given linux network device # 1: device name -network_ready_device() { __network_defer "$1" 0; } +network_ready_device() +{ + ubus call network.device set_state \ + "$(printf '{ "name": "%s", "defer": false }' "$1")" 2>/dev/null +} # flush the internal value cache to force re-reading values from ubus -network_flush_cache() -{ - local __tmp - for __tmp in $__NETWORK_CACHE __NETWORK_CACHE; do - unset "$__tmp" - done -} +network_flush_cache() { unset __NETWORK_CACHE; }