| 設定値 |
-- 監視間隔(1 - 864000 秒)
idle_time = 60
-- 受信負荷率を計測する時間(1, 2 .. )
avr_sec = 1
-- 受信負荷率の閾値(1 - 99 %)
rcv_th = 30
-- [[
連続して閾値を超えたら受信帯域を絞る回数(1, 2, ..)
SWX2200-24G のみ有効。down_countよりも少ない回数を指定する必要がある
]]
shaping_cnt = 3
-- 連続して閾値を超えたらポートを閉じる回数(1, 2, ..)
down_cnt = 5
--[[
帯域を絞る場合のスピードレベル(1 - 31)
switch control function set qos-speed-unit コマンドの設定値 (初期値 32M) に
shaping_speed を掛けた値が実際の帯域幅となる
SWX2200-24Gのみ有効
]]
shaping_speed = 10
-- このスクリプトが出力する SYSLOG のレベル (info, debug, notice)
log_level = "info"
--[[
監視対象のスイッチと監視するポートをカンマで区切って列挙する
MACアドレスかルーターからスイッチまでの接続ポートの経路情報で指定
("00:a0:de:xx:xx:xx" または "lan1:2")
監視するポートを列挙する(port = "1, 3-5, 7")
]]
sw_list = {
{ route = "lan1:1", port = "2-8"}
}
-- (送る: true / 送らない: false)
mail = false
-- メールの設定
mail_tbl = {
smtp_address = "(SMTPサーバのアドレス)",
from = "(送信元メールアドレス)",
to = "(宛先メールアドレス)"
}
|
| ポートの通信速度を求める関数 |
function port_speed(num, route)
local rtn, str, val, rt_name
local cmd = "switch control function get status-port-speed " .. num
local ptn = "(%d+)"
rt.command("switch select " .. route)
rtn, str = rt.command(cmd)
val = 0
if (rtn) and (str) then
str = str:match(ptn)
if (str) then
val = unitstr2num(str)
end
end
return val
end
|
| 回線速度を数値に変換する関数 |
function unitstr2num(str)
local val
val = tonumber(str)
if (val > 0) then
val = val * 1024 * 1024
end
return val
end
|
| 受信オクテット数を求める関数 |
function port_rx_octet(num, route)
local rtn, str
local cmd = "switch control function get status-counter-octet-rx " .. num
local ptn = "(%d+)"
rt.command("switch select " .. route)
rtn, str = rt.command(cmd)
if (rtn) and (str) then
str = string.match(str, ptn)
end
return tonumber(str)
end
|
| オクテット数の差分と回線速度から受信負荷率を求める |
function calc_load(port)
local load, diff
if (port.speed == 0) then
return 0
end
if (port["octet1"] > port["octet2"]) then
-- カウンタの上限を超えた場合
diff = port.speed - port.octet1 * 8
load = (diff + port["octet2"] * 8) / avr_sec
else
diff = port["octet2"] - port["octet1"]
load = diff * 8 / avr_sec -- 速度(bps)
end
load = 100 * load / port.speed -- 負荷率
return load
end
|
| 回線使用率が閾値を超えた時、または正常に復帰した時のメッセージを返す関数 |
function make_portmsg(port, route, load, stat)
local rtn
local str = ""
if (stat == "shaping") then
mail_tbl.text = string.format("受信負荷率が閾値を超えたため、"..
"switch(%s)のポート%dの帯域を絞りました。"..
"\r\n\r\n", route, port)
mail_tbl.text = mail_tbl.text .. "\t受信帯域のレベルを" .. shaping_speed ..
"に変更しました。\r\n"
mail_tbl.text = mail_tbl.text .. "\t閾値: " .. rcv_th .. "%"
elseif (stat == "down") then
mail_tbl.text = string.format("受信負荷率が閾値を超えたため、"..
"switch(%s)のポート%dを閉じました。\r\n\r\n",
route, port)
mail_tbl.text = mail_tbl.text .. "\t受信負荷率:" .. load .. "%\r\n"
mail_tbl.text = mail_tbl.text .. "\t閾値:" .. rcv_th .. "%"
end
end
|
| 閾値を超えた連続回数をカウントする関数 |
function count_proc(t, val, port_num)
local rtn = 0
if (val > rcv_th) then
-- 閾値を超えた場合
t.cnt = t.cnt + 1
-- 24G限定
if (port_num == 24) then
if (t.stat == "normal") and (t.cnt == shaping_cnt) then
t.stat = "shaping"
rtn = 1
end
end
if (t.stat ~= "down") and (t.cnt == down_cnt) then
t.stat = "down"
rtn = 1
end
else
-- 受信負荷率が閾値以下の場合、カウンタをリセットする
t.cnt = 0
end
return rtn, t
end
|
| ポートの受信帯域/ポートをダウンさせる関数 |
function exec_sw_cmd(route, stat, port)
rtn, str = rt.command("switch select " .. route)
if (rtn) then
if (stat == "shaping") then
-- ポートを絞る
rt.command("switch control function set qos-policing-use "
.. port .. " on")
rt.command("switch control function set qos-policing-speed "
.. port .. " " .. shaping_speed)
-- syslogを出力
msg = string.format("over the receive threshold. "..
"port%d speed down", port)
rt.syslog(log_level, msg)
elseif (stat == "down") then
rt.command("switch control function set port-use ".. port .. " off")
-- syslogを出力
msg = string.format("over the receive threshold. port%d down",
port)
rt.syslog(log_level, msg)
end
end
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
|
| メールを送信する関数 |
function send_mail(port, route, load, stat)
local rtn
make_portmsg(port, route, load, stat)
mail_tbl.subject = string.format("receive load watch")
rtn = rt.mail(mail_tbl)
if (not rtn) then
rt.syslog(log_level, "failed to send mail. swx2200_lua_traffic_ctl_rtx1200.lua")
end
end
|
| SWの検索および機種、ポート数の設定 |
function set_sw_tbl(tbl)
for i, sw in ipairs(sw_list) do
route = sw.route
rtn, str = rt.command("switch control function get model-name ".. route)
if (rtn) and (str) then
str = string.match(str, "%w+%p(%d+).")
if (str) then
tbl[i] = {
route = route,
port_num = tonumber(str),
port_info = {},
check_port = {}
}
else
stbl[i] = nil
end
else
tbl[i] = nil
end
end
end
|
| SWの各ポート情報を初期化 |
function port_info_init(tbl, sw_num)
local sw
for i=1, sw_num do
sw = tbl[i]
if (sw ~= nil) then
for j=1, sw.port_num do
sw.port_info[j] = {
speed = 0, octet1 = 0, octet2 = 0, result = 0, cnt = 0, stat = "normal"
}
end
end
end
end
|
| SWの監視するポートを設定 |
function set_check_port(tbl, sw_num)
local sw, port
local min, max, port_val
for i=1, sw_num do
sw = tbl[i]
if (sw ~= nil) then
port = sw_list[i].port
j = 1
str = ""
while (true) do
port_val = string.match(port, str.."(.-),")
if (port_val == nil) then
port_val = string.match(port, str .."(.-)$")
if (port_val == nil) then
break
end
end
--要素が見つかった場合
min, max = string.match(port_val,"(%d+)%p(%d+)")
if (min ~= nil) and (max ~= nil) then
--範囲指定
min = tonumber(min)
max = tonumber(max)
for n = min, max do
sw.check_port[j] = n
j = j + 1
n = n + 1
end
else
--単体指定
sw.check_port[j] = tonumber(port_val)
j = j + 1
end
str = str .. ".-,"
end
end
end
end
|
| SWの各ポートのオクテット数の取得 |
function get_port_info(sw, port_num, str)
local port
--監視するポートの場合
port = sw.port_info[port_num]
if (str == "octet1") then
-- 受信オクテット数を求める(1回目)
octet = port_rx_octet(port_num, sw.route)
-- オクテット数を保存
port["octet1"] = octet
elseif (str == "octet2") then
-- 受信オクテット数を求める(2回目)
octet = port_rx_octet(port_num, sw.route)
-- オクテット数を保存
port["octet2"] = octet
end
end
|
| メインルーチン |
local rtn, str, max
local sw, port
local port_info = {}
local sw_tbl = {}
-- 指定されたSWXを検索、8G/24Gを判別する。
set_sw_tbl(sw_tbl)
--SWの各ポート情報用配列の初期化
port_info_init(sw_tbl, #sw_tbl)
--SWの監視するポート番号をセット
set_check_port(sw_tbl, #sw_tbl)
while (true) do
for i = 1, #sw_tbl do
sw = sw_tbl[i]
num = 1
check = sw.check_port[num]
for j = 1, sw.port_num do
if (j == check) then
port = sw.port_info[j]
max = port_speed(port_num, sw.route)
port["speed"] = max
if (max > 0) then
--1回目
get_port_info(sw, j, "octet1")
--計測時間待ち
rt.sleep(avr_sec)
--2回目
get_port_info(sw, j, "octet2")
--受信負荷率を求める
load = calc_load(port)
--閾値を超えた回数のカウント
rtn, port = count_proc(port, load, sw.port_num)
if (rtn > 0) then
--[[
ポートの受信帯域を絞る/ポートのシャットダウン
]]
exec_sw_cmd(sw.route, port.stat, j)
-- メール送信
if (mail) then
send_mail(j, sw.route, load, port.stat)
end
end
end
num = num + 1
check = sw.check_port[num]
if (check == nil) then
break
end
end
end
end
-- 測定間隔待ち
rt.sleep(idle_time)
end
|