commit:     97da3ab2158db402fd20b440cefe7a7be7501d6d
Author:     Emeric Verschuur <emeric <AT> mbedsys <DOT> org>
AuthorDate: Sun May  1 11:11:16 2016 +0000
Commit:     Robin H. Johnson <robbat2 <AT> gentoo <DOT> org>
CommitDate: Sun May  1 11:11:16 2016 +0000
URL:        https://gitweb.gentoo.org/proj/netifrc.git/commit/?id=97da3ab2

Adding L2TP (v3) module (net/l2tp.sh) to support L2TPv3 link

 doc/net.example.Linux.in |  24 +++++++
 net/l2tp.sh              | 169 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 193 insertions(+)

diff --git a/doc/net.example.Linux.in b/doc/net.example.Linux.in
index f65c03d..72608bb 100644
--- a/doc/net.example.Linux.in
+++ b/doc/net.example.Linux.in
@@ -985,6 +985,30 @@
 #relay_6to4="192.168.3.2"
 #suffix_6to4=":ff"
 
+# For L2TP (v3) link
+# WARNING: sys-apps/iproute2 is required to use this module
+# You may have to add "l2tp" to modules list
+#
+# A L2 link between need a session within a tunnel
+# 1 session <=> 1 interface and 1 tunnel <=> n session(s)
+# a tunnel can host several session (shared by several interfaces)
+# 
+# Example to create 3 L2TPv3 links where (see man ip, iproute2 manual for more 
details):
+# * l2tpeth0 and l2tpeth1 are tho sessions into a same (shared) tunnel (encap 
IP)
+# * l2tpeth2 is a session into an separate tunnel (encap UDP)
+#
+#l2tptunnel_l2tpeth0="remote 1.2.3.4 local 1.2.4.3 encap ip tunnel_id 1 
peer_tunnel_id 1"
+#l2tpsession_l2tpeth0="tunnel_id 1 session_id 1 peer_session_id 1"
+#config_l2tpeth="10.100.0.1/24"
+#
+#l2tptunnel_l2tpeth1="remote 1.2.3.4 local 1.2.4.3 encap ip tunnel_id 1 
peer_tunnel_id 1"
+#l2tpsession_l2tpeth1="tunnel_id 1 session_id 2 peer_session_id 2"
+#config_l2tpeth1="10.100.1.1/24"
+#
+#l2tptunnel_l2tpeth2="remote 1.2.3.4 local 1.2.4.3 encap udp tunnel_id 2 
peer_tunnel_id 2 udp_sport 5000 udp_dport 6000"
+#l2tpsession_l2tpeth2="tunnel_id 2 session_id 1 peer_session_id 1"
+#config_l2tpeth2="10.100.2.1/24"
+
 #-----------------------------------------------------------------------------
 # Advanced Routing
 # WARNING: For advanced routing you MUST be using sys-apps/iproute2

diff --git a/net/l2tp.sh b/net/l2tp.sh
new file mode 100644
index 0000000..24f5f8c
--- /dev/null
+++ b/net/l2tp.sh
@@ -0,0 +1,169 @@
+# Copyright (c) 2016 Emeric Verschuur <eme...@mbedsys.org>
+# All rights reserved. Released under the 2-clause BSD license.
+
+l2tp_depend()
+{
+       program ip
+       before bridge interface macchanger
+}
+
+# Extract parameter list to shell vars
+#   1. variable prefix
+#   2. string to parse
+_l2tp_eval_props() {
+       local prop_pref=$1
+       local prop_list=$2
+       eval set -- "$3"
+       while [ -n "$1" ]; do
+               eval "case $1 in
+                       $prop_list)
+                               $prop_pref$1=\"$2\"
+                               shift
+                               shift
+                               ;;
+                       *)
+                               l2tp_err=\"invalid property $1\"
+                               return 1
+                               ;;
+                       
+               esac" || return 1
+       done
+       return 0
+}
+
+_is_l2tp() {
+       eval "$(ip l2tp show session | \
+               awk "match(\$0, /^Session ([0-9]+) in tunnel ([0-9]+)\$/, ret) 
{sid=ret[1]; tid=ret[2]} 
+               match(\$0, /^[ ]*interface name: ${IFACE}\$/) {print 
\"session_id=\"sid\";tunnel_id=\"tid; exit}")"
+       test -n "$session_id"
+}
+
+# Get tunnel info
+#    1. Output variable prefix
+#    2. Tunnel ID to find
+_l2tp_get_tunnel_info() {
+       local found
+       eval "$(ip l2tp show tunnel | \
+               awk -v id=$2 -v prefix=$1 '
+               match($0, /^Tunnel ([0-9]+), encap (IP|UDP)$/, ret) {
+                       if (found == "1") exit;
+                       if (ret[1] == id) {
+                               print "found=1;"
+                               print prefix "tunnel_id=" ret[1] ";"
+                               print prefix "encap=" ret[2] ";";
+                               found="1"
+                       }
+               } 
+               match($0, /^[ ]*From ([^ ]+) to ([^ ]+)$/, ret) {
+                       if (found == "1") {
+                               print prefix "local=" ret[1] ";"; 
+                               print prefix "remote=" ret[2] ";"; 
+                       }
+               }
+               match($0, /^[ ]*Peer tunnel ([0-9]+)$/, ret) {
+                       if (found == "1") {
+                               print prefix "peer_tunnel_id=" ret[1] ";"; 
+                       }
+               }
+               match($0, /^[ ]*UDP source \/ dest ports: ([0-9]+)\/([0-9]+)$/, 
ret) {
+                       if (found == "1") {
+                               print prefix "udp_sport=" ret[1] ";"; 
+                               print prefix "udp_dport=" ret[2] ";"; 
+                       }
+               }')"
+       test -n "$found"
+}
+
+_ip_l2tp_add() {
+       local e
+       e="$(LC_ALL=C ip l2tp add $@ 2>&1 1>/dev/null)"
+       case $e in
+               "")
+                       return 0
+                       ;;
+               "RTNETLINK answers: No such process")
+                       # seems to not be a fatal error but I don't know why I 
have this error... hmmm
+                       ewarn "ip l2tp add $2 error: $e"
+                       return 0
+                       ;;
+               *)
+                       eend 1 "ip l2tp add $2 error: $e"
+                       return 1
+                       ;;
+       esac
+       
+}
+
+l2tp_pre_start()
+{
+       local l2tpsession=
+       eval l2tpsession=\$l2tpsession_${IFVAR}
+       test -n "${l2tpsession}" || return 0
+       
+       ebegin "Creating L2TP tunnel ${IFVAR}"
+       local l2tp_err s_name s_tunnel_id s_session_id s_peer_session_id 
s_cookie s_peer_cookie s_offset s_peer_offset s_l2spec_type
+       if ! _l2tp_eval_props s_ 
"name|tunnel_id|session_id|peer_session_id|cookie|peer_cookie|offset|peer_offset|l2spec_type"
 "${l2tpsession}"; then
+               eend 1 "l2tpsession_${IFVAR} syntax error: $l2tp_err"
+               return 1
+       fi
+       if [ -n "$s_name" ]; then
+               eend 1 "l2tpsession_${IFVAR} error: please remove the \"name\" 
parameter (this parameter is managed by the system)"
+               return 1
+       fi
+       # Try to load mendatory l2tp_eth kernel module
+       if ! modprobe l2tp_eth; then
+               eend 1 "l2tp_eth module not present in your kernel (please 
enable CONFIG_L2TP_ETH option in your kernel config)"
+               return 1
+       fi
+       local l2tptunnel=
+       eval l2tptunnel=\$l2tptunnel_${IFVAR}
+       if [ -n "${l2tptunnel}" ]; then
+               local t_tunnel_id t_encap t_local t_remote t_peer_tunnel_id 
t_udp_sport t_udp_dport
+               _l2tp_eval_props t_ 
"remote|local|encap|tunnel_id|peer_tunnel_id|encap|udp_sport|udp_dport" 
"${l2tptunnel}"
+               # if encap=ip we need l2tp_ip kernel module
+               if [ "${t_encap^^}" = "IP" ] && ! modprobe l2tp_ip; then
+                       eend 1 "l2tp_ip module not present in your kernel 
(please enable CONFIG_L2TP_IP option in your kernel config)"
+                       return 1
+               fi
+               # Search for an existing tunnel with the same ID
+               local f_tunnel_id f_encap f_local f_remote f_peer_tunnel_id 
f_udp_sport f_udp_dport
+               if _l2tp_get_tunnel_info f_ $t_tunnel_id; then
+                       # check if the existing tunnel has the same property 
than expected
+                       if [ 
"tunnel_id:$f_tunnel_id;encap:$f_encap;local:$f_local;remote:$f_remote;
+                       
peer_tunnel_id:$f_peer_tunnel_id;udp_sport:$f_udp_sport;udp_dport:$f_udp_dport" 
\
+                       != 
"tunnel_id:$t_tunnel_id;encap:${t_encap^^};local:$t_local;remote:$t_remote;
+                       
peer_tunnel_id:$t_peer_tunnel_id;udp_sport:$t_udp_sport;udp_dport:$t_udp_dport" 
]; then
+                               eend 1 "There are an existing tunnel with 
id=$s_tunnel_id, but the properties mismatch with the one you want to create"
+                               return 1
+                       fi
+               else
+                       veinfo ip l2tp add tunnel ${l2tptunnel}
+                       _ip_l2tp_add tunnel ${l2tptunnel} || return 1
+               fi
+       elif ! ip l2tp show tunnel | grep -Eq "^Tunnel $s_tunnel_id,"; then
+               # no l2tptunnel_<INTF> declaration, assume that the tunnel is 
already present
+               # checking if tunnel_id exists otherwise raise an error
+               eend 1 "Tunnel id=$s_tunnel_id no found (you may have to set 
l2tptunnel_${IFVAR})"
+               return 1
+       fi
+       veinfo ip l2tp add session ${l2tpsession} name "${IFACE}"
+       _ip_l2tp_add session ${l2tpsession} name "${IFACE}" || return 1
+       _up
+}
+
+
+l2tp_post_stop()
+{
+       local session_id tunnel_id
+       _is_l2tp || return 0
+       
+       ebegin "Destroying L2TP tunnel ${IFACE}"
+       veinfo ip l2tp del session tunnel_id $tunnel_id session_id $session_id
+       ip l2tp del session tunnel_id $tunnel_id session_id $session_id
+       if ! ip l2tp show session | grep -Eq "^Session [0-9]+ in tunnel 
$tunnel_id\$"; then
+               #tunnel $tunnel_id no longer used, destoying it...
+               veinfo ip l2tp del tunnel tunnel_id $tunnel_id
+               ip l2tp del tunnel tunnel_id $tunnel_id
+       fi
+       eend $?
+}

Reply via email to