LANインターフェースの回線使用率を監視する

Luaスクリプト機能の対応機種は、RTX5000RTX3500RTX1210RTX1200(Rev.10.01.16以降)、RTX830RTX810NVR700WNVR510NVR500FWX120SRT100(Rev.10.00.52以降)です。

図 LANインターフェースの回線使用率を監視する

定期的にLANインターフェースの回線使用率を監視し、送信負荷率または受信負荷率が閾値を超えた場合にメールで通知するLuaスクリプトです。

光回線に接続するためには、別途ONUが必要です。
NVR700WとNVR510は、本体のONUポートに小型ONUを装着することで、光回線に接続できます。

対応機種のうち、設定例を掲載している機種は、以下のとおりです。

機種 掲載内容 備考
RTX5000 RTX3500 RTX1210 RTX1200 RTX830 RTX810 NVR700W NVR510 NVR500 SRT100 コマンド設定例
Luaスクリプト例
Luaスクリプト機能

ルーターの設定例

LANインターフェースの設定
(LAN1ポートを使用)
ip lan1 address 192.168.0.1/24
WANインターフェースの設定
(LAN2ポートを使用)
ip lan2 address dhcp
ip lan2 secure filter in 1020 1030 2000
ip lan2 secure filter out 1010 1011 1012 1013 1014 1015 3000 dynamic 100 101 102 103 104 105 106 107
ip lan2 nat descriptor 1
ip route default gateway dhcp lan2
NATの設定 nat descriptor type 1 masquerade
nat descriptor address outer 1 primary
DHCPの設定 dhcp service server
dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.0.2-192.168.0.100/24
DNSの設定 dns server (ISPより指定されたDNSサーバーのIPアドレス)
dns private address spoof on
フィルターの設定 ip filter source-route on
ip filter directed-broadcast on
ip filter 1010 reject * * udp,tcp 135 *
ip filter 1011 reject * * udp,tcp * 135
ip filter 1012 reject * * udp,tcp netbios_ns-netbios_ssn *
ip filter 1013 reject * * udp,tcp * netbios_ns-netbios_ssn
ip filter 1014 reject * * udp,tcp 445 *
ip filter 1015 reject * * udp,tcp * 445
ip filter 1020 reject 192.168.0.0/24 *
ip filter 1030 pass * 192.168.0.0/24 icmp
ip filter 2000 reject * *
ip filter 3000 pass * *
ip filter dynamic 100 * * ftp
ip filter dynamic 101 * * www
ip filter dynamic 102 * * domain
ip filter dynamic 103 * * smtp
ip filter dynamic 104 * * pop3
ip filter dynamic 105 * * submission
ip filter dynamic 106 * * tcp
ip filter dynamic 107 * * udp
Luaスクリプトのスケジュール設定 schedule at 1 startup * lua (Luaスクリプトファイル名)

Luaスクリプト例

設定値

-- 監視間隔 (1-864000 秒)
idle_time = (監視間隔)

-- 回線使用率を計測する時間(1, 2 .. 秒)
avr_sec = (計測時間)

-- 監視するLANインターフェースの番号
lan_num = (LANインターフェースの番号)

-- 送信負荷率の閾値(1 - 99 %)
snd_th = (負荷率)

-- 受信負荷率の閾値(1 - 99 %)
rcv_th = (負荷率)

-- 連続で閾値を超えたら異常と判断する回数、または正常な状態に復帰したと判断する回数(1, 2 ..)
count = (回数)

-- 正常な状態に復帰した場合にもメールを送るか否か(送る:true / 送らない:false)
down_mail = (true / false)

-- メールの設定
mail_tbl = {
 smtp_address = "(SMTPサーバーのアドレス)",
 from = "(送信元メールアドレス)",
 to = "(宛先メールアドレス)"
}

-- メールの送信に失敗したときに出力する SYSLOG のレベル(info, debug, notice)
log_level = "(SYSLOGレベル)"

LANインターフェースの速度を求める関数

function interface_speed(num)
 local rtn, str, val, rt_name
 local cmd = "show config"
 local ptn = "speed lan" .. tostring(num) .. " (%d+%a)"

 rtn, str = rt.command(cmd)
 if (rtn) and (str) then
  str = str:match(ptn)
  if (str) then
   val = unitstr2num(str)
  end
 end

 if (not val) or (val == 0) then
  rt_name = string.match(_RT_FIRM_REVISION, "(%w+) ")

  if ((rt_name == "RTX1210") or (rt_name == "RTX1200") or (rt_name == "RTX830") or (rt_name == "RTX810") or (rt_name == "NVR700W") or (rt_name == "NVR510") or (rt_name == "NVR500") or (rt_name == "RTX3500") or (rt_name == "RTX5000")) then
   val = unitstr2num("1000m")
  elseif (rt_name == "SRT100") then
   val = unitstr2num("100m")
  end
 end

 return val
end

回線速度を数値に変換する関数

function unitstr2num(str)
 local val, unit

 val = tonumber(str:match("%d+"))
 unit = str:sub(-1):lower()
 
 if (unit == "k") then
  val = val * 1024
 elseif (unit == "m") then
  val = val * 1024 * 1024
 else
  val = 0
 end

 return val
end

show status lan コマンドの実行結果から回線使用率を求める関数

function lan_load_info(num, sec)
 local rtn, str1, str2, rcv, snd
 local t = {}
 local cmd = "show status lan" .. tostring(num)
 local ptn = "%((%d+)%s+オクテット"

 rtn, str1 = rt.command(cmd)
 if (rtn) and (str1) then
  rt.sleep(sec)

  rtn, str2 = rt.command(cmd)
  if (rtn) and (str2) then
   str1 = str1 .. str2

   n = 1
   for w in string.gmatch(str1, ptn) do
    t[n] = w
    n = n + 1
   end

   if (t[1]) and (t[3]) then
    snd = ((tonumber(t[3]) - tonumber(t[1])) *8) /sec
   else
    rtn = false
    str1 = "使用帯域(送信)の取得失敗\r\n"
   end
   if (t[2]) and (t[4]) then
    rcv = ((tonumber(t[4]) - tonumber(t[2])) *8) /sec
   else
    rtn = false
    str1 = "使用帯域(受信)の取得失敗\r\n"
   end
  else
   str1 = str2
  end
 else
  str1 = cmd .. "コマンドの実行失敗\r\n"
 end

 return rtn, rcv, snd, str1
end

回線使用率が閾値を超えたとき、または正常に復帰したときにメッセージを返す関数

function make_lanmsg(tbl, val, th, down)
 local rtn
 local str = ""

 if (val) then
  rtn = count_proc(tbl, val, th)
  if (rtn < 0) then
   if (down) then
    str = tbl.title .. "負荷率が閾値以下の値に下がりました。\r\n"
   end
  elseif (rtn > 0) then
   str = tbl.title .. "負荷率が閾値を超えました。\r\n"
   str = str .. string.format(" %s負荷率: %d%%\r\n 閾値: %d%%\r\n\r\n",
      tbl.title, val, th)
  end
 end

 return str
end

閾値を超えた、または下がった連続回数をカウントする関数

function count_proc(t, val, th)
 local rtn = 0

 if (val > th) then
  if (not t.flag) then
   t.over = t.over + 1
   if (t.over == count) then
    rtn = 1
    t.flag = true
   end
  else
   if (t.down > 0) then
    t.down = 0
   end
  end
 else
  if (t.flag) then
   t.down = t.down + 1
   if (t.down == count) then
    rtn = -1
    t.flag = false
    t.over = 0
    t.down = 0
   end
  else
   if (t.over > 0) then
    t.over = 0
   end
  end
 end

 return rtn
end

現在の日時を取得する関数

function time_stamp()
 local t

 t = os.date("*t")
 return string.format("%d/%02d/%02d %02d:%02d:%02d",
  t.year, t.month, t.day, t.hour, t.min, t.sec)
end

メインルーチン

local rtn, str, max
local snd, rcv
local cnt_tbl = {
 rcv = {over = 0, down = 0, flag = false, title = "受信"},
 snd = {over = 0, down = 0, flag = false, title = "送信"}
}
max = interface_speed(lan_num)

while (true) do
 mail_tbl.text = ""

 rtn, rcv, snd, str = lan_load_info(lan_num, avr_sec)
 if (rtn) then
  snd = 100*snd/max
  rcv = 100*rcv/max
  mail_tbl.text = mail_tbl.text .. make_lanmsg(cnt_tbl.rcv, rcv, rcv_th, down_mail)
  mail_tbl.text = mail_tbl.text .. make_lanmsg(cnt_tbl.snd, snd, snd_th, down_mail)
 else
  mail_tbl.text = str
 end

 if (mail_tbl.text:len() > 0) then
  mail_tbl.subject = string.format("[LAN %d] transmit/receive load watch (%s)", lan_num, time_stamp())
  rtn = rt.mail(mail_tbl)
  if (not rtn) then
   rt.syslog(log_level, "failed to send mail. (Luaスクリプトファイル名)")
  end
 end

 rt.sleep(idle_time)
end

【ご注意】
本設定例は、設定の参考例を示したもので、動作を保証するものではございません。
ご利用いただく際には、十分に評価・検証を実施してください。