--[[ ●LAN 側回線使用率監視スクリプト   一定の監視間隔毎に LAN 側回線使用率(送信/受信)を監視し、設定した閾値を超え   たら管理者にメールを送信して知らせるスクリプトです。   送信/受信の負荷が閾値を指定回数だけ連続して超えた場合にメールを送信します。   その後、負荷が閾値を指定回数だけ連続して下回った場合には、正常値に戻ったと   判断します。設定値 down_mail を true に設定している場合には、正常値に戻った   際にもメールを送信します。 <説明> ・このファイルを RTFS か外部メモリに保存してください。 ・本項目の config の設定では schedule at コマンドでルーター起動時に Lua スク  リプトが実行されるように設定しています。 ・スクリプトを停止するときは terminate lua コマンドを実行してください。 ・再度、Lua スクリプトを実行する場合は lua コマンドで実行してください。 ・★マークの付いた設定値は変更が可能です。 <ノート>  ・メールの送信失敗時に出力する SYSLOG レベルを指定可能です。   SYSLOG のレベルを指定するには、log_level を設定してください。   debug レベル、notice レベルの SYSLOG を出力するためには、それぞれ以下の設定   が必要です。    debug レベル ・・・ syslog debug on    notice レベル・・・ syslog notice on  ・本スクリプトファイルを編集する場合、文字コードは必ず Shift-JIS を使用してく   ださい。 ]] --------------------------## 設定値 ##-------------------------------- -- 監視間隔(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 == "RTX5000") or (rt_name == "RTX3510") or (rt_name == "RTX3500") or (rt_name == "RTX1300") or (rt_name == "RTX1220") or (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")) 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. utilization.lua") end end rt.sleep(idle_time) end