mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Merge pull request #455 from DrDoof/feat/storm-control
storm: limit broadcast, multicast and unknown unicast and multicast per port
This commit is contained in:
13 files changed
+324
-3
No files matched your search
@@ -82,7 +82,8 @@ SRCS += \
|
||||
rtl837x_phy.c \
|
||||
rtl837x_pins.c\
|
||||
rtl837x_port.c \
|
||||
rtl837x_stp.c
|
||||
rtl837x_stp.c \
|
||||
rtl837x_storm.c
|
||||
SRCS += \
|
||||
httpd/httpd.c \
|
||||
httpd/page_impl.c
|
||||
|
||||
@@ -360,4 +360,5 @@ The following documents give further documentation on specific features of the R
|
||||
- [SFP+ ports](doc/sfp.md)
|
||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
||||
- [VLAN](doc/vlan.md)
|
||||
- [Storm control](doc/storm_control.md)
|
||||
- [Modifications and Flash replacement](doc/mods.md)
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "rtl837x_stp.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "rtl837x_bandwidth.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "sfp.h"
|
||||
#include "dhcp.h"
|
||||
#include "syslog.h"
|
||||
@@ -1573,6 +1574,57 @@ err:
|
||||
cmd_error("bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
||||
}
|
||||
|
||||
static __code char * __code storm_types[STORM_TYPES] = { "bcast", "mcast", "ucast", "umcast" };
|
||||
|
||||
void parse_storm(void)
|
||||
{
|
||||
uint8_t port, type, d;
|
||||
__xdata uint32_t rate;
|
||||
__xdata uint8_t *p;
|
||||
|
||||
if (cmd_words_len == 1)
|
||||
return storm_show();
|
||||
if (cmd_words_len < 4 || !cmd_parse_port_separator(cmd_words_b[1]))
|
||||
goto err;
|
||||
port = atoi_results_u8;
|
||||
|
||||
type = 0;
|
||||
while (!cmd_compare(2, storm_types[type])) {
|
||||
if (++type == STORM_TYPES)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (cmd_words_len == 4 && cmd_compare(3, "off"))
|
||||
return storm_off(port, type);
|
||||
if (cmd_words_len != 5)
|
||||
goto err;
|
||||
|
||||
rate = 0;
|
||||
p = &cmd_buffer[cmd_words_b[3]];
|
||||
do {
|
||||
d = *p++ - '0';
|
||||
if (d > 9 || rate > 99999999)
|
||||
goto err;
|
||||
rate = (rate << 3) + (rate << 1) + d;
|
||||
} while (*p != ' ' && *p != NUL);
|
||||
|
||||
if (cmd_compare(4, "pps")) {
|
||||
if (!rate || rate > 0xfffff)
|
||||
goto err;
|
||||
storm_set(port, type, rate, 1);
|
||||
} else if (cmd_compare(4, "kbps")) {
|
||||
if (!rate || rate > 10000000)
|
||||
goto err;
|
||||
storm_set(port, type, rate, 0);
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: storm [<port> bcast|mcast|ucast|umcast <rate> pps|kbps|off]\n");
|
||||
}
|
||||
|
||||
void parse_syslog(void)
|
||||
{
|
||||
if (cmd_words_len < 2) // no argument -> print status
|
||||
@@ -1946,6 +1998,8 @@ void cmd_parser(void) __banked
|
||||
parse_bw();
|
||||
} else if (cmd_compare(0, "temp")) {
|
||||
parse_temp();
|
||||
} else if (cmd_compare(0, "storm")) {
|
||||
parse_storm();
|
||||
} else if (cmd_compare(0, "version")) {
|
||||
print_sw_version();
|
||||
} else if (cmd_compare(0, "time")) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Storm Control
|
||||
Storm control limits the rate at which a port admits broadcast, multicast,
|
||||
unknown unicast and unknown multicast frames. Frames of a type above its limit
|
||||
are dropped at ingress, so a loop or a misbehaving host cannot flood the rest
|
||||
of the network through that port. Known unicast traffic is not affected.
|
||||
|
||||
## Commands
|
||||
```
|
||||
storm <port> bcast|mcast|ucast|umcast <rate> pps
|
||||
storm <port> bcast|mcast|ucast|umcast <rate> kbps
|
||||
storm <port> bcast|mcast|ucast|umcast off
|
||||
storm
|
||||
```
|
||||
`ucast` is unicast to a MAC address the switch has not learned yet, and
|
||||
`umcast` is multicast without an entry in the address table. Multicast groups
|
||||
get their entries from IGMP snooping, so without `igmp on` all multicast is
|
||||
unknown and only the `umcast` limit applies to it; `mcast` covers the groups
|
||||
IGMP has learned. A limit in
|
||||
packets per second goes from 1 to 1048575, a limit in kbit/s from 1 to
|
||||
10000000. `storm` without arguments prints the limits of every port. The
|
||||
limits are kept in the configuration like any other setting, and the Bandwidth
|
||||
page of the web interface has a Storm control card to set them.
|
||||
|
||||
## Registers
|
||||
Each port and type has an enable bit and a meter index, and each limit uses
|
||||
one of the 64 shared meters of the switch. RTLPlayground gives every port and
|
||||
type its own meter, index `24 + port * 4 + type`, so one port's storm does not
|
||||
eat into the limit of another. Storm control uses meters 24 to 63 and leaves
|
||||
0 to 23 to the ACL. The limit of a meter is in `RTL837X_METER_RATE + 4 *
|
||||
meter`, and bit `meter % 32` of `RTL837X_METER_MODE + 4 * (meter / 32)`
|
||||
selects pps instead of kbit/s.
|
||||
```
|
||||
#define RTL837X_STORM_CTRL 0x54e4 /* + 4 * type, bit = port */
|
||||
#define RTL837X_STORM_MIDX 0x54f4 /* + 8 * type + 4 * (port / 5), 6 bits per port */
|
||||
#define RTL837X_METER_RATE 0x5cf0 /* + 4 * meter, 24 bits, kbit/s or pps */
|
||||
#define RTL837X_METER_MODE 0x5ef0 /* + 4 * (meter / 32), bit set = pps */
|
||||
```
|
||||
In kbit/s mode one step of the rate is 1 kbit/s. Measured with 100 and 1000 byte
|
||||
frames, the meter counts a frame with its FCS, but without preamble and
|
||||
interframe gap. Every meter has a bit that adds them, in `0x5f08 + 4 * (meter
|
||||
/ 32)`, which storm control leaves cleared. `IGBW_INC_IFG` and `EGBW_INC_IFG`
|
||||
are the matching bits of the bandwidth control.
|
||||
|
||||
An ingress bandwidth limit on the same port works on the same arriving frames
|
||||
as the storm limit rather than after it, and the two together pass far less
|
||||
than either one: a 1 Mbit/s `umcast` limit with a 10 Mbit/s ingress limit let
|
||||
0.12 to 0.16 Mbit/s of a 1.4 Gbit/s stream through, where each alone passed
|
||||
1.17 and 10.2 Mbit/s.
|
||||
|
||||
The type is 0 for broadcast, 1 for multicast, 2 for unknown unicast and 3 for
|
||||
unknown multicast. The burst size of a meter (0x5df0 + 4 * meter) counts packets
|
||||
in pps mode; its default of 0x2000 lets 8192 frames through before a pps limit
|
||||
bites, so a pps limit sets the burst to one second of traffic. A kbit/s limit
|
||||
puts back the default.
|
||||
+60
-2
@@ -70,6 +70,9 @@ e_idle:"idle",e_na:"n/a",
|
||||
bw_title:"Bandwidth limits",bw_h:"Mbit/s, 0.016-10000",bw_in:"Ingress limit",bw_out:"Egress limit",
|
||||
bw_exceed:"When exceeded",bw_fc:"Flow control",bw_drop:"Drop",
|
||||
bw_in_err:"Ingress limit must be 0.016-10000 Mbit/s",bw_out_err:"Egress limit must be 0.016-10000 Mbit/s",
|
||||
sc_title:"Storm control",sc_h:"per port and traffic type, empty = off",sc_bcast:"Broadcast",sc_mcast:"Multicast",
|
||||
sc_ucast:"Unknown unicast",sc_umcast:"Unknown multicast",sc_err:"Storm limit must be 1-1048575 pps or 1-10000000 kbit/s",
|
||||
sc_note:"Frames of a type above its limit are dropped where they enter the switch.",
|
||||
sy_network:"Network",sy_dhcp:"Use DHCP",sy_dhcp_t:"Request address via DHCP",sy_services:"Services",
|
||||
sy_igmp:"IGMP snooping",sy_sysip:"server IP",sy_server:"Server",sy_port:"Port",
|
||||
sy_sesstmo:"Session timeout (s)",sy_sesstmo_err:"Session timeout must be 1-65535 s",
|
||||
@@ -677,6 +680,7 @@ var CONF_CMDS=[
|
||||
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+p2p\s+(auto|on|off)$/,
|
||||
/^igmp\s+(on|off)$/,/^mtu\s+\d{1,2}\s+\d+$/,
|
||||
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
|
||||
/^storm\s+\d{1,2}\s+(bcast|mcast|ucast|umcast)\s+(off|\d{1,8}\s+(pps|kbps))$/,
|
||||
];
|
||||
function isConfCmd(line){
|
||||
for(var i=0;i<CONF_CMDS.length;i++)if(CONF_CMDS[i].test(line))return true;
|
||||
@@ -1725,7 +1729,61 @@ function bwApply(n){
|
||||
}else cmds.push("bw out "+n+" off");
|
||||
postCmds(cmds).then(bwLoad).catch(function(){});
|
||||
}
|
||||
tabHooks.bw={enter:function(){needPorts(function(){bwLoad().catch(function(){})})}};
|
||||
var SC_TYPES=["bcast","mcast","ucast","umcast"],scSig="";
|
||||
function scLoad(){
|
||||
return getJSON("/storm.json").then(function(s){
|
||||
var tb=$("sctable").tBodies[0];
|
||||
byPort(s);
|
||||
var sig=s.map(function(p){return p.portNum}).join();
|
||||
if(sig!==scSig){
|
||||
scSig=sig;tb.innerHTML="";
|
||||
s.forEach(function(p){
|
||||
var n=p.portNum,tr=tb.insertRow();
|
||||
tr.id="scr"+n;
|
||||
tr.addEventListener("input",function(){tr.dataset.dirty="1"});
|
||||
tr.addEventListener("change",function(){tr.dataset.dirty="1"});
|
||||
tr.insertCell().textContent=n;
|
||||
SC_TYPES.forEach(function(ty){
|
||||
tr.insertCell().appendChild(h("span",{style:"display:flex;gap:4px"},[
|
||||
h("input",{class:"in sm",id:"scv"+ty+n,type:"number",min:"1",step:"1"}),
|
||||
h("select",{class:"in",id:"scu"+ty+n},[
|
||||
h("option",{value:"pps",text:"pps"}),
|
||||
h("option",{value:"kbps",text:"kbit/s"}),
|
||||
]),
|
||||
]));
|
||||
});
|
||||
tr.insertCell().appendChild(h("button",{class:"ctl",text:t("c_apply"),onclick:function(){scApply(n)}}));
|
||||
});
|
||||
}
|
||||
s.forEach(function(p){
|
||||
var n=p.portNum;
|
||||
if($("scr"+n).dataset.dirty)return;
|
||||
SC_TYPES.forEach(function(ty,k){
|
||||
var on=p.en.charAt(k)==="1",pps=p.pps.charAt(k)==="1",raw=parseInt(p.rate.substr(k*6,6),16);
|
||||
var inp=$("scv"+ty+n),sel=$("scu"+ty+n);
|
||||
inp.value=on?raw:"";
|
||||
sel.value=on&&!pps?"kbps":"pps";
|
||||
inp.dataset.cur=on?inp.value+" "+sel.value:"off";
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
function scApply(n){
|
||||
var cmds=[];
|
||||
for(var k=0;k<SC_TYPES.length;k++){
|
||||
var ty=SC_TYPES[k],inp=$("scv"+ty+n),u=$("scu"+ty+n).value,v=inp.value.trim(),want="off";
|
||||
if(v!==""&&v!=="0"){
|
||||
var x=Number(v);
|
||||
if(!Number.isInteger(x)||x<1||(u==="pps"&&x>1048575)||(u==="kbps"&&x>10000000)){toast(t("sc_err"),"err");return;}
|
||||
want=x+" "+u;
|
||||
}
|
||||
if(want!==inp.dataset.cur)cmds.push("storm "+n+" "+ty+" "+want);
|
||||
}
|
||||
delete $("scr"+n).dataset.dirty;
|
||||
if(!cmds.length)return;
|
||||
postCmds(cmds).then(scLoad).catch(function(){});
|
||||
}
|
||||
tabHooks.bw={enter:function(){needPorts(function(){bwLoad().then(scLoad).catch(function(){})})}};
|
||||
|
||||
var IPRE=/^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
function okIp(s){
|
||||
@@ -1870,7 +1928,7 @@ var CONF_OVERWRITE=[
|
||||
/^lag\s+\d\b/,/^laghash\s+\d\b/,/^isolate\s+\d{1,2}\b/,
|
||||
/^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/,
|
||||
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+(edge|cost|prio|guard|filter|p2p)\b/,
|
||||
/^igmp\b/,/^mtu\s+\d{1,2}\b/,
|
||||
/^igmp\b/,/^mtu\s+\d{1,2}\b/,/^storm\s+\d{1,2}\s+(bcast|mcast|ucast|umcast)\b/,
|
||||
];
|
||||
var CONF_TOGGLE=[/^(syslog)\s+(on|off)$/,/^(stp)\s+(on|off)$/,/^(stp\s+(port\s+\d{1,2}|lag\s+[1-4]))\s+(on|off)$/];
|
||||
function mergeConf(base,texts){
|
||||
|
||||
@@ -351,6 +351,12 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="bw_in">Ingress limit</th><th>Mbit/s</th><th data-i18n="bw_exceed">When exceeded</th><th data-i18n="bw_out">Egress limit</th><th>Mbit/s</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
<div class="card"><h2><span data-i18n="sc_title">Storm control</span> <span class="hint" data-i18n="sc_h">per port and traffic type, empty = off</span></h2>
|
||||
<div class="scrollx"><table class="t" id="sctable">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="sc_bcast">Broadcast</th><th data-i18n="sc_mcast">Multicast</th><th data-i18n="sc_ucast">Unknown unicast</th><th data-i18n="sc_umcast">Unknown multicast</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:8px" data-i18n="sc_note">Frames of a type above its limit are dropped where they enter the switch.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-system">
|
||||
|
||||
@@ -1016,6 +1016,8 @@ void httpd_appcall(void)
|
||||
send_eee();
|
||||
} else if (is_word(q, "/bandwidth.json")) {
|
||||
send_bandwidth();
|
||||
} else if (is_word(q, "/storm.json")) {
|
||||
send_storm();
|
||||
} else if (is_word(q, "/l2.json")) {
|
||||
parse_short(q + 13); // e.g.: /l2.json?idx=10
|
||||
send_l2(short_parsed);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "rtl837x_pins.h"
|
||||
@@ -828,6 +829,40 @@ void send_bandwidth(void)
|
||||
}
|
||||
|
||||
|
||||
void send_storm(void)
|
||||
{
|
||||
__xdata uint8_t i, t, idx;
|
||||
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
char_to_html('[');
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
slen += strtox(outbuf + slen, ",\"en\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++)
|
||||
char_to_html(reg_bit_test(RTL837X_STORM_CTRL + (t << 2), i) ? '1' : '0');
|
||||
slen += strtox(outbuf + slen, "\",\"pps\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
idx = STORM_METER(i, t);
|
||||
char_to_html(reg_bit_test(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f) ? '1' : '0');
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\",\"rate\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
reg_read_m(RTL837X_METER_RATE + (STORM_METER(i, t) << 2));
|
||||
byte_to_html(sfr_data[1]);
|
||||
byte_to_html(sfr_data[2]);
|
||||
byte_to_html(sfr_data[3]);
|
||||
}
|
||||
char_to_html('"');
|
||||
char_to_html('}');
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_mtu(void)
|
||||
{
|
||||
dbg_string("send_mtu called\n");
|
||||
|
||||
@@ -12,6 +12,7 @@ void send_status(void);
|
||||
void send_vlan(uint16_t vlan);
|
||||
void send_basic_info(void);
|
||||
void send_bandwidth(void);
|
||||
void send_storm(void);
|
||||
void send_eee(void);
|
||||
void send_l2(uint16_t idx);
|
||||
void l2_delete(uint16_t idx);
|
||||
|
||||
@@ -327,6 +327,11 @@
|
||||
#define RTL837X_IGBW_PORT_FC_CTRL 0x4C8C
|
||||
#define RTL837X_EGBW_PORT_CTRL 0x1c34
|
||||
#define RTL837X_EGBW_CTRL 0x447c
|
||||
#define RTL837X_STORM_CTRL 0x54e4
|
||||
#define RTL837X_STORM_MIDX 0x54f4
|
||||
#define RTL837X_METER_RATE 0x5cf0
|
||||
#define RTL837X_METER_BURST 0x5df0
|
||||
#define RTL837X_METER_MODE 0x5ef0
|
||||
#define EGBW_INC_IFG 0x02
|
||||
#define EGBW_CPUMODE 0x01
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
/* RTL837X_STORM_MIDX words, row type * 2 + half: half 0 holds ports 0-4, half 1 ports 5-9,
|
||||
* 6 bits per port, each set to STORM_METER(port, type) */
|
||||
static const __code uint8_t storm_midx[8][4] = {
|
||||
{ 0x28, 0x92, 0x07, 0x18 }, { 0x3c, 0xe3, 0x4c, 0x2c },
|
||||
{ 0x29, 0x96, 0x17, 0x59 }, { 0x3d, 0xe7, 0x5c, 0x6d },
|
||||
{ 0x2a, 0x9a, 0x27, 0x9a }, { 0x3e, 0xeb, 0x6c, 0xae },
|
||||
{ 0x2b, 0x9e, 0x37, 0xdb }, { 0x3f, 0xef, 0x7c, 0xef },
|
||||
};
|
||||
|
||||
static __code char * __code storm_names[STORM_TYPES] = { " bcast ", " mcast ", " ucast ", " umcast " };
|
||||
|
||||
|
||||
void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked
|
||||
{
|
||||
__xdata uint8_t idx = STORM_METER(port, type);
|
||||
__xdata uint8_t row = (type << 1) | (port >= 5 ? 1 : 0);
|
||||
__xdata uint8_t * __xdata r = (uint8_t *)&rate;
|
||||
|
||||
sfr_data[0] = 0;
|
||||
sfr_data[1] = r[2];
|
||||
sfr_data[2] = r[1];
|
||||
sfr_data[3] = r[0];
|
||||
reg_write_m(RTL837X_METER_RATE + (idx << 2));
|
||||
|
||||
if (!pps) {
|
||||
sfr_data[1] = 0;
|
||||
sfr_data[2] = 0x20;
|
||||
sfr_data[3] = 0;
|
||||
}
|
||||
reg_write_m(RTL837X_METER_BURST + (idx << 2));
|
||||
|
||||
if (pps)
|
||||
reg_bit_set(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f);
|
||||
else
|
||||
reg_bit_clear(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f);
|
||||
|
||||
sfr_data[0] = storm_midx[row][0];
|
||||
sfr_data[1] = storm_midx[row][1];
|
||||
sfr_data[2] = storm_midx[row][2];
|
||||
sfr_data[3] = storm_midx[row][3];
|
||||
reg_write_m(RTL837X_STORM_MIDX + (row << 2));
|
||||
|
||||
reg_bit_set(RTL837X_STORM_CTRL + (type << 2), port);
|
||||
}
|
||||
|
||||
|
||||
void storm_off(uint8_t port, __xdata uint8_t type) __banked
|
||||
{
|
||||
reg_bit_clear(RTL837X_STORM_CTRL + (type << 2), port);
|
||||
}
|
||||
|
||||
|
||||
void storm_show(void) __banked
|
||||
{
|
||||
uint8_t i, t, idx;
|
||||
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
print_string("port ");
|
||||
write_char('0' + machine.log_to_phys_port[i]);
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
print_string(storm_names[t]);
|
||||
if (!reg_bit_test(RTL837X_STORM_CTRL + (t << 2), i)) {
|
||||
print_string("off");
|
||||
continue;
|
||||
}
|
||||
idx = STORM_METER(i, t);
|
||||
reg_read_m(RTL837X_METER_RATE + (idx << 2));
|
||||
print_byte(sfr_data[1]); print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
if (reg_bit_test(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f))
|
||||
print_string(" pps");
|
||||
else
|
||||
print_string(" kbps");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _RTL837X_STORM_H_
|
||||
#define _RTL837X_STORM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define STORM_TYPES 4
|
||||
#define STORM_METER_BASE 24
|
||||
#define STORM_METER(port, type) (STORM_METER_BASE + (((port) << 2) | (type)))
|
||||
|
||||
void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked;
|
||||
void storm_off(uint8_t port, __xdata uint8_t type) __banked;
|
||||
void storm_show(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -139,6 +139,7 @@ void send_status(void) { }
|
||||
void send_vlan(uint16_t vlan) { (void)vlan; }
|
||||
void send_basic_info(void) { }
|
||||
void send_bandwidth(void) { }
|
||||
void send_storm(void) { }
|
||||
void send_eee(void) { }
|
||||
void send_l2(uint16_t idx) { (void)idx; }
|
||||
void l2_delete(uint16_t idx) { (void)idx; }
|
||||
|
||||
Reference in new issue
Block a user