From 26547f3e0190129a5b6977197e48cb074d59fe50 Mon Sep 17 00:00:00 2001 From: DrDoof <8052722+DrDoof@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:46:56 +0200 Subject: [PATCH 1/2] storm: limit broadcast, multicast and unknown unicast and multicast per port --- Makefile | 3 +- README.md | 1 + cmd_parser.c | 59 +++++++++++++++++++++++++++++ doc/storm_control.md | 40 ++++++++++++++++++++ html/app.js | 62 ++++++++++++++++++++++++++++++- html/index.html | 6 +++ httpd/httpd.c | 2 + httpd/page_impl.c | 35 ++++++++++++++++++ httpd/page_impl.h | 1 + rtl837x_regs.h | 5 +++ rtl837x_storm.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ rtl837x_storm.h | 12 ++++++ test/test_httpd_tx.c | 1 + 13 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 doc/storm_control.md create mode 100644 rtl837x_storm.c create mode 100644 rtl837x_storm.h diff --git a/Makefile b/Makefile index aa1839c4..bb914904 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index 81fd8dda..6eaf74e8 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/cmd_parser.c b/cmd_parser.c index cb6b6c00..44f84e86 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -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,62 @@ err: cmd_error("bw [in|out|status] [|off|drop|fc]\n"); } +static __code char * __code storm_types[STORM_TYPES] = { "bcast", "mcast", "ucast", "umcast" }; + +void parse_storm(void) __reentrant +{ + static __xdata uint8_t port, type, d; + static __xdata uint32_t rate; + static __xdata uint8_t * __xdata p; + + if (cmd_words_len == 1) { + storm_show(); + return; + } + if (cmd_words_len < 4 || cmd_parse_port_separator(cmd_words_b[1]) == 0) + goto err; + port = atoi_results_u8; + + for (type = 0; type < STORM_TYPES; type++) { + if (cmd_compare(2, storm_types[type])) + break; + } + if (type == STORM_TYPES) + goto err; + + if (cmd_words_len == 4 && cmd_compare(3, "off")) { + storm_off(port, type); + return; + } + 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 [ bcast|mcast|ucast|umcast pps|kbps|off]\n"); +} + void parse_syslog(void) { if (cmd_words_len < 2) // no argument -> print status @@ -1946,6 +2003,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")) { diff --git a/doc/storm_control.md b/doc/storm_control.md new file mode 100644 index 00000000..64299771 --- /dev/null +++ b/doc/storm_control.md @@ -0,0 +1,40 @@ +# 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 bcast|mcast|ucast|umcast pps +storm bcast|mcast|ucast|umcast kbps +storm 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. 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 `port * 4 + type`, so one port's storm does not eat +into the limit of another. +``` +#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. + +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. diff --git a/html/app.js b/html/app.js index 021ebb22..a6e726dd 100644 --- a/html/app.js +++ b/html/app.js @@ -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;i1048575)||(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){ diff --git a/html/index.html b/html/index.html index 36f3650d..f848a811 100644 --- a/html/index.html +++ b/html/index.html @@ -351,6 +351,12 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent} PortIngress limitMbit/sWhen exceededEgress limitMbit/s +

Storm control per port and traffic type, empty = off

+
+ +
PortBroadcastMulticastUnknown unicastUnknown multicast
+

Frames of a type above its limit are dropped where they enter the switch.

+
diff --git a/httpd/httpd.c b/httpd/httpd.c index c4ac485a..b31ec320 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -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); diff --git a/httpd/page_impl.c b/httpd/page_impl.c index a669eb83..952a37f9 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -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 = (i << 2) | 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 + ((((i << 2) | 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"); diff --git a/httpd/page_impl.h b/httpd/page_impl.h index b3bcdfd9..b8df7af9 100644 --- a/httpd/page_impl.h +++ b/httpd/page_impl.h @@ -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); diff --git a/rtl837x_regs.h b/rtl837x_regs.h index 744ab1a5..49520a9f 100644 --- a/rtl837x_regs.h +++ b/rtl837x_regs.h @@ -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 diff --git a/rtl837x_storm.c b/rtl837x_storm.c new file mode 100644 index 00000000..8e5066d3 --- /dev/null +++ b/rtl837x_storm.c @@ -0,0 +1,88 @@ +#include +#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]; + +/* Meter index fields of RTL837X_STORM_MIDX, [type << 1 | ports 5-9] */ +static const __code uint8_t storm_midx[8][4] = { + { 0x10, 0x30, 0x81, 0x00 }, { 0x24, 0x81, 0xc6, 0x14 }, + { 0x11, 0x34, 0x91, 0x41 }, { 0x25, 0x85, 0xd6, 0x55 }, + { 0x12, 0x38, 0xa1, 0x82 }, { 0x26, 0x89, 0xe6, 0x96 }, + { 0x13, 0x3c, 0xb1, 0xc3 }, { 0x27, 0x8d, 0xf6, 0xd7 }, +}; + +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 = (port << 2) | 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 +{ + __xdata 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 = (i << 2) | 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'); + } +} diff --git a/rtl837x_storm.h b/rtl837x_storm.h new file mode 100644 index 00000000..47d6227f --- /dev/null +++ b/rtl837x_storm.h @@ -0,0 +1,12 @@ +#ifndef _RTL837X_STORM_H_ +#define _RTL837X_STORM_H_ + +#include + +#define STORM_TYPES 4 + +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 diff --git a/test/test_httpd_tx.c b/test/test_httpd_tx.c index 6f464d2b..f64cf5fc 100644 --- a/test/test_httpd_tx.c +++ b/test/test_httpd_tx.c @@ -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; } From de431c6d84c49434522303ac9f7da78d8bc1ec2c Mon Sep 17 00:00:00 2001 From: DrDoof <8052722+DrDoof@users.noreply.github.com> Date: Wed, 30 Sep 2026 22:48:31 +0200 Subject: [PATCH 2/2] storm: meters from 24 up, plainer parser, documentation from the review Storm control used meters 0 to 39, the same meters the ACL hands out, so a storm limit and an acl meter could overwrite each other. It now uses 24 + port * 4 + type, meters 24 to 63. parse_storm() is no longer reentrant and uses plain locals, looks the type up in a while loop and returns straight from the one-line cases. storm_show() uses plain locals too. The documentation says how IGMP decides between mcast and umcast, how to get from a meter index to its limit, where the IFG bit of a meter is, and what an ingress bandwidth limit on the same port does to the storm limit. --- cmd_parser.c | 31 +++++++++++++------------------ doc/storm_control.md | 22 ++++++++++++++++++---- httpd/page_impl.c | 4 ++-- rtl837x_storm.c | 17 +++++++++-------- rtl837x_storm.h | 2 ++ 5 files changed, 44 insertions(+), 32 deletions(-) diff --git a/cmd_parser.c b/cmd_parser.c index 44f84e86..0a97a288 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -1576,31 +1576,26 @@ err: static __code char * __code storm_types[STORM_TYPES] = { "bcast", "mcast", "ucast", "umcast" }; -void parse_storm(void) __reentrant +void parse_storm(void) { - static __xdata uint8_t port, type, d; - static __xdata uint32_t rate; - static __xdata uint8_t * __xdata p; + uint8_t port, type, d; + __xdata uint32_t rate; + __xdata uint8_t *p; - if (cmd_words_len == 1) { - storm_show(); - return; - } - if (cmd_words_len < 4 || cmd_parse_port_separator(cmd_words_b[1]) == 0) + 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; - for (type = 0; type < STORM_TYPES; type++) { - if (cmd_compare(2, storm_types[type])) - break; + type = 0; + while (!cmd_compare(2, storm_types[type])) { + if (++type == STORM_TYPES) + goto err; } - if (type == STORM_TYPES) - goto err; - if (cmd_words_len == 4 && cmd_compare(3, "off")) { - storm_off(port, type); - return; - } + if (cmd_words_len == 4 && cmd_compare(3, "off")) + return storm_off(port, type); if (cmd_words_len != 5) goto err; diff --git a/doc/storm_control.md b/doc/storm_control.md index 64299771..09346c6e 100644 --- a/doc/storm_control.md +++ b/doc/storm_control.md @@ -12,7 +12,10 @@ storm 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. A limit in +`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 @@ -21,8 +24,11 @@ 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 `port * 4 + type`, so one port's storm does not eat -into the limit of another. +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 */ @@ -31,7 +37,15 @@ into the limit of another. ``` 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. +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 diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 952a37f9..6b108895 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -843,12 +843,12 @@ void send_storm(void) 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 = (i << 2) | 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 + ((((i << 2) | t)) << 2)); + 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]); diff --git a/rtl837x_storm.c b/rtl837x_storm.c index 8e5066d3..c7e06d71 100644 --- a/rtl837x_storm.c +++ b/rtl837x_storm.c @@ -11,12 +11,13 @@ extern __code struct machine machine; extern __xdata uint8_t sfr_data[4]; -/* Meter index fields of RTL837X_STORM_MIDX, [type << 1 | ports 5-9] */ +/* 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] = { - { 0x10, 0x30, 0x81, 0x00 }, { 0x24, 0x81, 0xc6, 0x14 }, - { 0x11, 0x34, 0x91, 0x41 }, { 0x25, 0x85, 0xd6, 0x55 }, - { 0x12, 0x38, 0xa1, 0x82 }, { 0x26, 0x89, 0xe6, 0x96 }, - { 0x13, 0x3c, 0xb1, 0xc3 }, { 0x27, 0x8d, 0xf6, 0xd7 }, + { 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 " }; @@ -24,7 +25,7 @@ static __code char * __code storm_names[STORM_TYPES] = { " bcast ", " mcast ", " void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked { - __xdata uint8_t idx = (port << 2) | type; + __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; @@ -64,7 +65,7 @@ void storm_off(uint8_t port, __xdata uint8_t type) __banked void storm_show(void) __banked { - __xdata uint8_t i, t, idx; + uint8_t i, t, idx; for (i = machine.min_port; i <= machine.max_port; i++) { print_string("port "); @@ -75,7 +76,7 @@ void storm_show(void) __banked print_string("off"); continue; } - idx = (i << 2) | t; + 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)) diff --git a/rtl837x_storm.h b/rtl837x_storm.h index 47d6227f..5d175269 100644 --- a/rtl837x_storm.h +++ b/rtl837x_storm.h @@ -4,6 +4,8 @@ #include #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;