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
RSS 2.0 | leave a response | trackback

One Response

  1. 十二 9th, 2009 / 1:38 下午 天缘 Says:

    过来学习一下,博主文章非常好。我最想系统学一下路由知识了。

    [回复]

发表评论