blog » Work / 努力工作 » 高级路由应用一列
高级路由应用一列
关于 Linux 环境下的高级路由 第一手资料应该是 http://lartc.org/ 。系统的学习可以从这里开始。
公司有一个应用,需要使用 3g,但目前的 3g 速度依然不满意。所以在应用层上,开发工程师能够绑定多个 ip 地址,同时占用多条线路。而在系统层面,就需要 pppd 来配合了。
操作的环境是 Ubuntu,在 pppd 部分与其他发行版本相同。
ubuntu 带有 nm-tool 命令,我们通过此命令抓取已经被认出的 ttyUSBx 设备,当看到有设备被认出,而无连接的时候,脚本呼叫 createppp.sh 脚本,并传递一些参数:设备名、拨号号码、用户名、密码。 createppp.sh 会创建此 ppp 链接需要的配置文件并拨号。
createppp.sh 中有一个配置 linkname,此参数将在 /var/run 下为每一个链接创建 ppp-$IFNAME.pid 文件,文件中包含了进程的 pid 号,以及逻辑 ppp 编号,即 ppp0、ppp1 。nm_mon.pl 脚本通过此 pid 文件判断设备是否已经连接上。
ppp 在拨号成功后会执行 /etc/ppp/ip-up.d 下的脚本,于是我们在目录下添加脚本 proute_up。proute_up 负责创建合适的路由表,确保每一条 ppp 链接都有单独的路由表。
proute_up 在第一行又跑了一个脚本 createtables.sh 这个脚本是用来创建路由表的 alias 的,由于在 pppd 环境下能拿到的唯一变量有限,所以我选择了以 $IFNAME 作为路由表名。
最后还有一段,是判断系统当前是否存在默认路由表的,如果没有,则将此 ppp 链接设置为默认路由。但在有默认路由的情况下不覆盖。
类似 $IFNAME 的变量,都可以在 pppd 的 man 手册中查询到。够用了。
nm_mon.pl 脚本,负责监视 ttyUSB 设备以及 ppp 链接是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #! /usr/bin/perl use strict; use Data::Dumper; my @last_flags = (); my $now = time(); my %pids; my $nCount = 2; while (1) { $now = time(); @last_flags = (); my @a = qx(nm-tool); my $flag = ""; my $dev =""; foreach (@a) { chop; if (m/^- Device: ([0-9A-Za-z]+) / ) { $dev = $1; } if (m/^ Type: +Mobile/) { &check_dev($dev); undef $dev; } } $nCount++; if ($nCount >= 3) { $nCount=0; &check_pids(); } sleep(2); } |
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | sub check_dev() { my ($dev) = @_; if (!-f "/var/run/ppp-$dev.pid") { &run_createppp($dev); return 0; } my @lines = qx(cat /var/run/ppp-$dev.pid); chomp @lines; if (qx(ps -eo pid | grep @lines[0])) { print "DEV:$dev Link:$lines[1] ppp is found.\n"; if (defined $pids{$dev}) { $pids{$dev}{link} = $lines[1]; } else { $pids{$dev} = {pid =>@lines[0] + 0, time => $now, link => $lines[1]}; } } else { &run_createppp($dev); } } #state for pids # pid --> [last time, state(B,F,C), $dev, $link] sub check_pids() { print "before:<", Dumper(\%pids), ">\n"; foreach my $key(keys %pids) { if ($pids{$key}{time} + 10 < $now) { if (length($pids{$key}{link}) <= 2) { #kill $pids{$key}{pid} print("time out: $key need redial up for no link.\n"); } elsif (qx(ip addr show dev $key)) { #kill $pids{$key}{pid} print("time out: $key need redial up for no ip addr.\n"); } delete $pids{$key}; } } } cat /proc/tty/driver/usbserial sub run_createppp() { my($dev, $name, $pass) = @_; print "call ./createppp $dev $name $pass\n"; qx(sh ./createppp.sh $dev, $name, $pass); return; } |
createppp.sh 脚本,负责创建连接的配置文件并拨号:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #!/bin/bash [ -s $1 ] if [ $? != 1 ] then echo "You Must Give Me A Device Name!" exit 1 fi dev=$1 devpath=`echo /dev/$dev` num=$2 username=$3 passwd=$4 echo "ABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED '' ATZ OK-AT-OK \"ATDT$2\" CONNECT \d\c" > /etc/chatscripts/$dev echo "hide-password noauth connect \"/usr/sbin/chat -v -f /etc/chatscripts/$dev\" debug $devpath 115200 defaultroute noipdefault user "card" remotename $dev ipparam $dev linkname $dev usepeerdns lcp-echo-failure 0 lcp-echo-interval 0 " > /etc/ppp/peers/$dev sed -i /$dev/d /etc/ppp/pap-secrets echo "\"$username\" $dev \"$passwd\"" >> /etc/ppp/pap-secrets pon $dev |
proute_up 脚本,负责创建合适的路由表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/bin/bash /home/xxxx/createtables.sh $IFNAME ip route add default via $IPREMOTE dev $IFNAME src $IPLOCAL table $IFNAME ip rule add from $IPLOCAL table $IFNAME ip route add $DNS1 via $IPLOCAL dev $IFNAME ip route add $DNS2 via $IPLOCAL dev $IFNAME gw=`/sbin/ip route | grep default | wc -l` if [ $gw -eq 0 ] then ip route add default via $IPREMOTE dev $IFNAME fi |
最后是 createtables.sh 脚本,用于创建合适的路由表 alias。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/bin/bash dev=$1 rtfile="/etc/iproute2/rt_tables" tableid=200 devnum=`grep $dev $rtfile | wc -l` if [ $devnum -eq 1 ] then exit 0 elif [ $devnum -eq 0 ] then tablenum=1 while [ $tablenum -eq 1 ] do tableid=`expr $tableid + 1` tablenum=`grep $tableid $rtfile | wc -l` done echo "$tableid $dev" >> $rtfile fi |
过来学习一下,博主文章非常好。我最想系统学一下路由知识了。
[回复]