diff mbox

[OpenWrt-Devel,3/3] ppp: Unnumbered support

Message ID 1433925543-20217-3-git-send-email-dedeckeh@gmail.com
State Superseded
Headers show

Commit Message

Hans Dedecker June 10, 2015, 8:39 a.m. UTC
Adds PPP unnumbered support via the parameter unnumbered which points to a logical OpenWRT interface.
The PPP proto shell handler will "borrow" an IP address from the unnumbered interface (if multiple
IP addresses are present the longest prefix different from 32 will be "borrowed") for which a host
dependency will be created. Due to the host dependency the PPP unnumbered interface will only "borrow"
an IP address from an interface which is up.
The borrowed IP address will be shared as local IP address by the PPP daemon and no other local IP
will be accepted from the peer in the IPCP negotiation.

A typical use case is the usage of a public IP subnet on the Lan interface which will be shared
by the PPP interface as local IP address.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
---
 package/network/services/ppp/files/ppp.sh | 66 ++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

Comments

Steven Barth June 10, 2015, 12:03 p.m. UTC | #1
Thanks, I already applied the other two.


On 10.06.2015 10:39, Hans Dedecker wrote:
> +ppp_select_ipaddr()
> +{
> +	local interface="$1"
> +	local addrs=$(uci_get "network.${interface}.ipaddr")
> +	local netmask=$(uci_get "network.${interface}.netmask")
Any particular reason you are reading from UCI here and do not use the
interface status parsing via e.g. network_get_subnets from
/lib/functions/network.sh? This would seem more clear to me and would
avoid the awkward parsing of netmasks as well. Additionally this would
make it work with non-static protos as well.


Cheers,

Steven
Hans Dedecker June 10, 2015, 12:44 p.m. UTC | #2
On Wed, Jun 10, 2015 at 2:03 PM, Steven Barth <cyrus@openwrt.org> wrote:
> Thanks, I already applied the other two.
>
>
> On 10.06.2015 10:39, Hans Dedecker wrote:
>> +ppp_select_ipaddr()
>> +{
>> +     local interface="$1"
>> +     local addrs=$(uci_get "network.${interface}.ipaddr")
>> +     local netmask=$(uci_get "network.${interface}.netmask")
> Any particular reason you are reading from UCI here and do not use the
> interface status parsing via e.g. network_get_subnets from
> /lib/functions/network.sh? This would seem more clear to me and would
> avoid the awkward parsing of netmasks as well. Additionally this would
> make it work with non-static protos as well
UCI is read as network_get_subnets only returns info for active
interfaces; e.g. if the referred interface in the unnumbered parameter
is down it's not possible to install the host dependency based on the
IP address for the PPP interface.
Did not (yet) find a way to circumvent this issue.

Hans
>
>
> Cheers,
>
> Steven
Steven Barth June 10, 2015, 12:52 p.m. UTC | #3
> UCI is read as network_get_subnets only returns info for active
> interfaces; e.g. if the referred interface in the unnumbered parameter
> is down it's not possible to install the host dependency based on the
> IP address for the PPP interface.
> Did not (yet) find a way to circumvent this issue.

Understood, I think the sane way around here would be to add a
host_dependency on the interface itself (without a specific IP-address).
Let me see if this can be added to netifd easily.


Cheers,

Steven
Steven Barth June 10, 2015, 6:42 p.m. UTC | #4
I just pushed
http://git.openwrt.org/?p=project/netifd.git;a=commit;h=5cf30b59baa03db2448570c78e7e92873555d2ec
(not yet bumped in trunk) which allows generic dependencies to
interfaces by using an empty address, with that you can add a host
dependency and once fulfilled
use network_* to get the addresses.

Please let me know if that works for you.


Cheers,

Steven

On 10.06.2015 14:52, Steven Barth wrote:
> 
> 
> 
>> UCI is read as network_get_subnets only returns info for active
>> interfaces; e.g. if the referred interface in the unnumbered parameter
>> is down it's not possible to install the host dependency based on the
>> IP address for the PPP interface.
>> Did not (yet) find a way to circumvent this issue.
> 
> Understood, I think the sane way around here would be to add a
> host_dependency on the interface itself (without a specific IP-address).
> Let me see if this can be added to netifd easily.
> 
> 
> Cheers,
> 
> Steven
>
Hans Dedecker June 10, 2015, 8:37 p.m. UTC | #5
On Wed, Jun 10, 2015 at 8:42 PM, Steven Barth <cyrus@openwrt.org> wrote:
> I just pushed
> http://git.openwrt.org/?p=project/netifd.git;a=commit;h=5cf30b59baa03db2448570c78e7e92873555d2ec
> (not yet bumped in trunk) which allows generic dependencies to
> interfaces by using an empty address, with that you can add a host
> dependency and once fulfilled
> use network_* to get the addresses.
Thx I will try to find some time in the coming days to rework the PPP
unnumbered implementation based on this approach.

Hans
>
> Please let me know if that works for you.
>
>
> Cheers,
>
> Steven
>
> On 10.06.2015 14:52, Steven Barth wrote:
>>
>>
>>
>>> UCI is read as network_get_subnets only returns info for active
>>> interfaces; e.g. if the referred interface in the unnumbered parameter
>>> is down it's not possible to install the host dependency based on the
>>> IP address for the PPP interface.
>>> Did not (yet) find a way to circumvent this issue.
>>
>> Understood, I think the sane way around here would be to add a
>> host_dependency on the interface itself (without a specific IP-address).
>> Let me see if this can be added to netifd easily.
>>
>>
>> Cheers,
>>
>> Steven
>>
Hans Dedecker June 11, 2015, 2:42 p.m. UTC | #6
On Wed, Jun 10, 2015 at 8:42 PM, Steven Barth <cyrus@openwrt.org> wrote:
> I just pushed
> http://git.openwrt.org/?p=project/netifd.git;a=commit;h=5cf30b59baa03db2448570c78e7e92873555d2ec
> (not yet bumped in trunk) which allows generic dependencies to
> interfaces by using an empty address, with that you can add a host
> dependency and once fulfilled
> use network_* to get the addresses.
>
> Please let me know if that works for you.
I have been testing the PPP unnumbered scenario in combination with
the netifd patch and the interface dependency  works as expected.
An updated version of the PPP patch will follow soon.

Thx,
Hans
>
>
> Cheers,
>
> Steven
>
> On 10.06.2015 14:52, Steven Barth wrote:
>>
>>
>>
>>> UCI is read as network_get_subnets only returns info for active
>>> interfaces; e.g. if the referred interface in the unnumbered parameter
>>> is down it's not possible to install the host dependency based on the
>>> IP address for the PPP interface.
>>> Did not (yet) find a way to circumvent this issue.
>>
>> Understood, I think the sane way around here would be to add a
>> host_dependency on the interface itself (without a specific IP-address).
>> Let me see if this can be added to netifd easily.
>>
>>
>> Cheers,
>>
>> Steven
>>
diff mbox

Patch

diff --git a/package/network/services/ppp/files/ppp.sh b/package/network/services/ppp/files/ppp.sh
index 1a72a1e..6770db3 100755
--- a/package/network/services/ppp/files/ppp.sh
+++ b/package/network/services/ppp/files/ppp.sh
@@ -4,10 +4,63 @@ 
 
 [ -n "$INCLUDE_ONLY" ] || {
 	. /lib/functions.sh
+	. /lib/functions/network.sh
 	. ../netifd-proto.sh
 	init_proto "$@"
 }
 
+ppp_mask2cidr()
+{
+	local x=${1##*255.}
+	# count the number of leading all ones
+	local allones=$(( (${#1} - ${#x}) * 2 ))
+	# conversion table based on blocks containing
+	# 4 characters to count the number of trailing bits
+	local tbl="0^^^128^192^224^240^248^252^254^"
+
+	# count the number of four character blocks
+	x=${tbl%%${x%%.*}*}
+	echo $(( $allones + (${#x}/4) ))
+}
+
+ppp_select_ipaddr()
+{
+	local interface="$1"
+	local addrs=$(uci_get "network.${interface}.ipaddr")
+	local netmask=$(uci_get "network.${interface}.netmask")
+	local res
+	local res_mask
+
+	if [ -n "$netmask" ]; then
+		[ "$netmask" != "${netmask##*.}" ] && netmask=$(ppp_mask2cidr $netmask)
+	else
+		netmask=32
+	fi
+
+	for entry in $addrs; do
+		local addr="${entry%%/*}"
+		local mask="${entry#*/}"
+
+		if [ "$addr" != "$mask" ]; then
+			[ "$mask" != "${mask##*.}" ] && mask=$(ppp_mask2cidr $mask)
+		else
+			mask="$netmask"
+		fi
+
+		if [ -n "$res_mask" -a "$mask" != 32 ]; then
+			[ "$mask" -gt "$res_mask" ] || [ "$res_mask" = 32 ] && {
+				res="$addr"
+				res_mask="$mask"
+			}
+		elif [ -z "$res_mask" ]; then
+			res="$addr"
+			res_mask="$mask"
+		fi
+	done
+
+	echo "$res"
+}
+
 ppp_exitcode_tostring()
 {
 	local errorcode=$1
@@ -53,12 +106,14 @@  ppp_generic_init_config() {
 	proto_config_add_boolean authfail
 	proto_config_add_int mtu
 	proto_config_add_string pppname
+	proto_config_add_string unnumbered
 }
 
 ppp_generic_setup() {
 	local config="$1"; shift
+	local localip
 
-	json_get_vars ipv6 demand keepalive keepalive_adaptive username password pppd_options pppname
+	json_get_vars ipv6 demand keepalive keepalive_adaptive username password pppd_options pppname unnumbered
 	if [ "$ipv6" = 0 ]; then
 		ipv6=""
 	elif [ -z "$ipv6" -o "$ipv6" = auto ]; then
@@ -73,6 +128,14 @@  ppp_generic_setup() {
 	fi
 	[ -n "$mtu" ] || json_get_var mtu mtu
 	[ -n "$pppname" ] || pppname="${proto:-ppp}-$config"
+	[ -n "$unnumbered" ] && {
+		localip=$(ppp_select_ipaddr $unnumbered)
+		[ -n "$localip" ] || {
+			proto_block_restart "$config"
+			return
+		}
+		( proto_add_host_dependency "$config" "$localip" "$unnumbered" )
+	}
 
 	local lcp_failure="${keepalive%%[, ]*}"
 	local lcp_interval="${keepalive##*[, ]}"
@@ -86,6 +149,7 @@  ppp_generic_setup() {
 	proto_run_command "$config" /usr/sbin/pppd \
 		nodetach ipparam "$config" \
 		ifname "$pppname" \
+		${localip:+$localip:} \
 		${lcp_failure:+lcp-echo-interval $lcp_interval lcp-echo-failure $lcp_failure $lcp_adaptive} \
 		${ipv6:++ipv6} \
 		nodefaultroute \