diff --git a/html/stat.html b/html/stat.html index 5cfaf05..cb5cbfe 100644 --- a/html/stat.html +++ b/html/stat.html @@ -3,14 +3,42 @@ FreeSwitchOS Port Statistics +
+

Port Statistics

- +
Port link TX Good TX Bad RX Good RX Bad
Port link TX Good TX Bad RX Good RX Bad All Counters
diff --git a/html/stat.js b/html/stat.js index 31973fc..6d1618b 100644 --- a/html/stat.js +++ b/html/stat.js @@ -1,3 +1,160 @@ +const mib_counters = [ + "Interface in Octets", 8, + "", 0, + "Interface out Octets", 8, + "", 0, + "Interface in Unicast Pkts", 8, + "", 0, + "Interface in Multicast Pkts", 8, + "", 0, + "Interface in Broadcast Pkts", 8, + "", 0, + "Interface out Unicast Pkts", 8, // 10 + "", 0, + "Interface out Multicast Pkts", 8, + "", 0, + "Interface out Broadcast Pkts", 8, + "", 0, + "Interface out discards", 4, + "802.1d Tp Port in discards", 4, + "802.3 Single collision frames", 4, + "802.3 Multi collision frames", 4, + "802.3 Deferred transmissions", 4, // 20 + "802.3 Late collisions", 4, + "802.3 Excessive collisions", 4, + "802.3 Symbol errors", 4, + "802.3 Control in unknown opcodes", 4, + "802.3 In Pause frames", 4, + "802.3 Out Pause frames", 4, + "Ether drop events", 4, + "TX Ether Broadcast Pkts", 4, + "TX Ether Multicast Pkts", 4, + "TX Ether CRC Align errors", 4, // 30 + "RX Ether CRC Align errors", 4, + "TX Ether Undersized Pkts", 4, + "RX Ether Undersized Pkts", 4, + "TX Ether Oversized Pkts", 4, + "RX Ether Oversized Pkts", 4, + "TX Ether Fragments", 4, + "RX Ether fragments", 4, + "TX Ether Jabbers", 4, + "RX Ether Jabbers", 4, + "TX Ether Collisions", 4, // 40 + "TX Ether Pkts 640 Octets", 4, + "RX Ether Pkts 640 Octets", 4, + "TX Ether 65-127 Octets", 4, + "RX Ether 65-127 Octets", 4, + "TX Ether Pkts 128-255 Octets", 4, + "RX Ether Pkts 128-255 Octets", 4, + "TX Ether Pkts 256-511 Octets", 4, + "RX Ether Pkts 256-511 Octets", 4, + "TX Ether Pkts 512-1023 Octets", 4, + "RX Ether Pkts 512-1023 Octets", 4, // 50 + "TX Ether Pkts 1024-1518 Octets", 4, + "RX Ether Pkts 1024-1518 Octets", 4, + "", 4, + "RX Ether Undersized Drop Pkts", 4, // 54 + "TX Ether Pkts >1518 Octets", 4, + "RX Ether Pkts >1518 Octets", 4, + "TX Ether Pkts too large", 4, + "RX Ether Pkts too large", 4, + "TX Ether Flexible Octets Set 1", 4, + "RX Ether Flexible Octets Set 1", 4,// 60 + "TX Ether Flexible Octets CRC Set 1", 4, + "RX Ether Flexible Octets CRC Set 1", 4, + "TX Ether Flexible Octets Set 0", 4, + "RX Ether Flexible Octets Set 0", 4, + "TX Ether Flexible Octets CRC Set 0", 4, + "RX Ether Flexible Octets CRC Set 0", 4, + "Lenth Field Errors", 4, + "False Carriers", 4, + "Undersized Octets", 4, + "Framing Errors", 4, // 70 + "", 4, + "RX MAC Discards", 4, // 72 + "RX MAC IPG Short Drop", 4, + "", 4, + "802.1d TP Learned Entry Discards", 4, // 75 + "Egress Queue 7 Dropped Pkts", 4, + "Egress Queue 6 Dropped Pkts", 4, + "Egress Queue 5 Dropped Pkts", 4, + "Egress Queue 4 Dropped Pkts", 4, + "Egress Queue 3 Dropped Pkts", 4, // 80 + "Egress Queue 2 Dropped Pkts", 4, + "Egress Queue 1 Dropped Pkts", 4, + "Egress Queue 0 Dropped Pkts", 4, + "Egress Queue 7 Out Pkts", 4, + "Egress Queue 6 Out Pkts", 4, + "Egress Queue 5 Out Pkts", 4, + "Egress Queue 4 Out Pkts", 4, + "Egress Queue 3 Out Pkts", 4, + "Egress Queue 2 Out Pkts", 4, + "Egress Queue 1 Out Pkts", 4, // 90 + "Egress Queue 0 Out Pkts", 4, + "TX Good Counter", 8, + "", 0, + "RX Good Counter", 8, + "", 0, + "RX Error Counter", 4, + "TX Error Counter", 4, + "TX Good Counter PHY", 8, + "", 0, + "RX Good Counter PHY", 8, // 100 + "", 0, + "RX Error Counter PHY", 4, + "TX Error Counter PHY", 4 +]; + + +function getCounters(port) { + var xhttp = new XMLHttpRequest(); + const popup = document.getElementById('popup'); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + const s = JSON.parse(xhttp.responseText); + console.log("Counters: ", JSON.stringify(s)); + const ptext = document.getElementById('popup_text'); + var t = ""; + console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length); + var c = 0; + for (i = 0; i < mib_counters.length; i += 4) { + console.log(i, " ", mib_counters[i], ": ", mib_counters[i+1]); + if (mib_counters[i] == "" && mib_counters[i + 1] == 8) { + console.log("c " + i + ": continue"); + continue; + } + var count = BigInt(s[i/4]); + if (mib_counters[i+1] == 8) { + t += ""; + c += 1; + } else if (mib_counters[i+1] == 4) { + if (mib_counters[i] != "") { + t += ""; + c += 1; + } + if (c == 2) { + t += ""; + c = 0; + } + if (mib_counters[i+2] != "") { + t += ""; + c += 1; + } + } + if (c == 2) { + t += ""; + c = 0; + } + } + ptext.innerHTML = t + "
Counter Value Counter Value
" + mib_counters[i] + "" + count.toString() + "" + mib_counters[i] + "" + (count >> 32n).toString() + "
" + mib_counters[i+2] + "" + (count & 4294967295n).toString() + "
"; + popup.style.display = 'flex'; + } + }; + xhttp.open("GET", "/counters.json?port=" + port, true); + xhttp.timeout = 1500; xhttp.send(); +} + + function fillStats() { var tbl = document.getElementById('statstable'); if (!numPorts) @@ -21,8 +178,21 @@ function fillStats() { td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`)); td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`)); td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`)); + var button = ''; + td = tr.insertCell(); td.innerHTML = button; } } } const stat = setInterval(fillStats, 1000); + +const popup = document.getElementById('popup'); +const closePopup = document.getElementById('closePopup'); +closePopup.addEventListener('click', () => { + popup.style.display = 'none'; +}); +window.addEventListener('click', (event) => { + if (event.target === popup) { + popup.style.display = 'none'; + } +}); diff --git a/httpd/httpd.c b/httpd/httpd.c index 0d2fe5b..b50a3e7 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -570,7 +570,7 @@ void httpd_appcall(void) parse_short(q + 15); send_vlan(short_parsed); } else if (is_word(q, "/counters.json")) { - send_counters(q[19]-'0'); + send_counters(q[20]-'0'); } else if (is_word(q, "/eee.json")) { send_eee(); } else if (is_word(q, "/mirror.json")) { diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 2b5807b..871818d 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -143,6 +143,16 @@ void reg_to_html(register uint16_t reg) } +void reg_to_html_long(register uint16_t reg) +{ + reg_read_m(reg); + byte_to_html(sfr_data[0]); + byte_to_html(sfr_data[1]); + byte_to_html(sfr_data[2]); + byte_to_html(sfr_data[3]); +} + + void send_sfp_info(uint8_t sfp) { // This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields @@ -257,21 +267,19 @@ void send_counters(char port) dbg_string("send_counters called: "); dbg_byte(port); dbg_char('\n'); slen = strtox(outbuf, HTTP_RESPONCE_JSON); dbg_string("sending counters\n"); - - port--; + dbg_byte(port); uint8_t i = machine.phys_to_log_port[port]; - slen += strtox(outbuf + slen, "{\"portNum\":"); - itoa_html(i + 1); - for (uint8_t j = 0; j < 0x3f; j++) { - STAT_GET(j, i); - slen += strtox(outbuf + slen, ",\"cnt_"); - itoa_html(j); - slen += strtox(outbuf + slen, "\":\"0x"); + slen += strtox(outbuf + slen, "["); + for (uint8_t counter = 0; counter < 0x37; counter++) { + STAT_GET(counter, i); + slen += strtox(outbuf + slen, "\"0x"); reg_to_html(RTL837X_STAT_V_HIGH); - reg_to_html(RTL837X_STAT_V_LOW); + reg_to_html_long(RTL837X_STAT_V_LOW); char_to_html('\"'); + if (counter != 0x36) + char_to_html(','); } - char_to_html('}'); + char_to_html(']'); } diff --git a/rtl837x_common.h b/rtl837x_common.h index ef8d4d6..57c0e6a 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -36,8 +36,21 @@ // the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated, // the VLAN tag is inserted after the RTL tag // See here for the RTL tag: https://github.com/torvalds/linux/commit/1521d5adfc2b557e15f97283c8b7ad688c3ebc40 -#define RTL_TAG_SIZE 8 -#define VLAN_TAG_SIZE 4 +struct rtl_tag { + uint16_t tag; // This is 0x8899 for the RTL837X + uint8_t version; // Version is 4 + uint8_t reason; + uint16_t flags; + uint16_t pmask; // A bit mask for a TX pkt, 4-bit port-number for RX +}; + +struct vlan_tag { + uint16_t svlan; // Service VLAN + uint16_t vlan; +}; + +#define RTL_TAG_SIZE (sizeof (struct rtl_tag)) +#define VLAN_TAG_SIZE (sizeof (struct vlan_tag)) #define RTL_FRAME_TAG_ID 0x8899 // For RX and TX, an 8 byte header describing the frame to be moved to the Asic @@ -70,15 +83,6 @@ struct flash_region_t { extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2]; -// 8899 04 0000 20 0004 -struct rtl_tag { - uint16_t tag; - uint8_t version; - uint8_t reason; - uint16_t flags; - uint16_t pmask; // A bit mask for a TX pkt, 4-bit port-number for RX -}; - // Headers for calls in the common code area (HOME/BANK0) void print_string(__code char *p); void print_long(__xdata uint32_t a); diff --git a/rtl837x_port.c b/rtl837x_port.c index bb96983..08f653c 100644 --- a/rtl837x_port.c +++ b/rtl837x_port.c @@ -400,17 +400,17 @@ void port_stats_print(void) __banked print_string("Up\t"); break; } - STAT_GET(0x2f, i); + STAT_GET(STAT_COUNTER_TX_PKTS, i); print_reg(RTL837X_STAT_V_LOW); write_char('\t'); - STAT_GET(0x30, i); + STAT_GET(STAT_COUNTER_ERR_PKTS, i); + print_reg(RTL837X_STAT_V_LOW); write_char('\t'); + + STAT_GET(STAT_COUNTER_RX_PKTS, i); + print_reg(RTL837X_STAT_V_LOW); write_char('\t'); + + STAT_GET(STAT_COUNTER_ERR_PKTS, i); print_reg(RTL837X_STAT_V_HIGH); write_char('\t'); - - STAT_GET(0x2e, i); - print_reg(RTL837X_STAT_V_LOW); write_char('\t'); - - STAT_GET(0x30, i); - print_reg(RTL837X_STAT_V_LOW); write_char('\t'); print_string("\n"); } } diff --git a/rtl837x_port.h b/rtl837x_port.h index e551c11..22ea1dd 100644 --- a/rtl837x_port.h +++ b/rtl837x_port.h @@ -3,9 +3,9 @@ #include -#define STAT_COUNTER_TX_PKTS 0x2e -#define STAT_COUNTER_RX_PKTS 0x2f -#define STAT_COUNTER_ERR_PKTS 0x30 +#define STAT_COUNTER_TX_PKTS 46 +#define STAT_COUNTER_RX_PKTS 47 +#define STAT_COUNTER_ERR_PKTS 48 #define STAT_GET(cnt, port) \ REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, cnt >> 3, (cnt << 5) | (port << 1) | 1); \ diff --git a/rtl837x_regs.h b/rtl837x_regs.h index 07e5e90..6a43f95 100644 --- a/rtl837x_regs.h +++ b/rtl837x_regs.h @@ -93,11 +93,14 @@ */ #define RTL837X_REG_NIC_BUFFSIZE_TX 0x7844 #define RTL837X_REG_NIC_RXBUFF_RX 0x7848 +#define RTL837X_REG_NIC_RXCMD 0x784c +#define RTL837X_REG_NIC_TXCMD 0x7850 #define RTL837X_REG_RX_CTRL 0x785c #define RTL837X_REG_TX_CTRL 0x7860 -#define RTL837X_REG_RX_AVAIL 0x7874 -#define RTL837X_REG_RX_RINGPTR 0x787c -#define RTL837X_REG_RX_DONE 0x784c +#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874 +#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c +#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884 +#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890 #define RTL837X_REG_CPU_TAG 0x6720 #define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C #define RTL837X_REG_MAC_FORCE_MODE 0x6344 diff --git a/rtlplayground.c b/rtlplayground.c index b463648..8bc0730 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -819,7 +819,7 @@ void tcpip_output(void) uip_buf[VLAN_TAG_SIZE + 2] = uip_buf[VLAN_TAG_SIZE + 3] = 0; uip_buf[VLAN_TAG_SIZE + 6] = uip_buf[VLAN_TAG_SIZE + 7] = 0; - reg_read_m(0x7890); + reg_read_m(RTL837X_REG_CPU_TX_CURR_PKT); uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8; ring_ptr |= sfr_data[3]; @@ -835,20 +835,20 @@ void tcpip_output(void) // Move data over from xmem buffer to ASIC side using DMA nic_tx_packet(ring_ptr); - reg_read_m(0x7884); // actual bytes sent, for now we assume everything worked + // New position of the ring-pointer on the NIC-side indicates number of bytes transmitted + reg_read_m(RTL837X_REG_NIC_TX_CURR_PKT); // Do actual TX of data on ASIC side - sfr_data[0] = sfr_data[1] = sfr_data[2] = 0; - sfr_data[3] = 0x1; - reg_write_m(0x7850); + REG_SET(RTL837X_REG_NIC_TXCMD, 1); } void handle_rx(void) { - reg_read_m(RTL837X_REG_RX_AVAIL); + // Check the amount of data available on the NIC/ASIC side + reg_read_m(RTL837X_REG_NIC_RX_BUFF_DATA); if (sfr_data[2] != 0 || sfr_data[3] != 0) { - reg_read_m(RTL837X_REG_RX_RINGPTR); + reg_read_m(RTL837X_REG_CPU_RX_CURR_PKT); uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8; ring_ptr |= sfr_data[3]; ring_ptr <<= 3; @@ -872,16 +872,13 @@ void handle_rx(void) write_char(' '); } #endif - sfr_data[0] = sfr_data[1] = sfr_data[2] = 0; - sfr_data[3] = 0x1; - reg_write_m(RTL837X_REG_RX_DONE); + REG_SET(RTL837X_REG_NIC_RXCMD, 1); uip_len = (((uint16_t)rx_headers[5]) << 8) | rx_headers[4]; -// write_char('>'); print_byte(uip_buf[ETHERTYPE_OFFSET]); write_char('<'); -// write_char('>'); print_byte(uip_buf[ETHERTYPE_OFFSET + 1]); write_char('<'); - // Check for ARP packet - rx_packet_vlan = uip_buf[12 + RTL_TAG_SIZE + 2] & 0xf; + + // Retrieve VLAN from VLAN-tag + rx_packet_vlan = uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 2] & 0xf; rx_packet_vlan <<= 8; - rx_packet_vlan |= uip_buf[12 + RTL_TAG_SIZE + 3]; + rx_packet_vlan |= uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 3]; #ifdef RXTXDBG print_string(" RX-VLAN: "); print_short(rx_packet_vlan); write_char('\n'); print_string(" RX dst: "); print_byte(uip_buf[0]); print_byte(uip_buf[1]); print_byte(uip_buf[2]); diff --git a/tools/httpd_sim.c b/tools/httpd_sim.c index 1b9f5ac..b2924dd 100644 --- a/tools/httpd_sim.c +++ b/tools/httpd_sim.c @@ -18,6 +18,8 @@ #define PORTS 9 #define NSFP 1 +#define N_COUNTERS 52 + #if PORTS == 9 const uint8_t physToLogPort[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8}; #else @@ -28,7 +30,7 @@ time_t last_called; time_t last_session_use; uint64_t txG[PORTS], txB[PORTS], rxG[PORTS], rxB[PORTS]; -char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20]; +char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20], counter_buf[20], counter_name[20]; char sfp_temp[8], sfp_vcc[8], sfp_txbias[8], sfp_txpower[8], sfp_rxpower[8], sfp_laser[8], sfp_options[6]; char num_buff[20]; char upload_buffer[4194304]; // 4MB @@ -199,6 +201,29 @@ void send_status(int s) } +void send_counters(int s, int port) +{ + struct json_object *v, *counters; + const char *jstring; + char *header = "HTTP/1.1 200 OK\r\n" + "Cache-Control: no-cache\r\n" + "Content-Type: application/json; charset=UTF-8\r\n\r\n"; + + printf("Sending counters\n"); + counters = json_object_new_array_ext(N_COUNTERS); + + for (int i = 0; i < N_COUNTERS; i++) { + v = json_object_new_object(); + sprintf(counter_buf, "0x%016lx", 0x1234UL + i); + json_object_array_add(counters, json_object_new_string(counter_buf)); + } + write(s, header, strlen(header)); + jstring = json_object_to_json_string_ext(counters, JSON_C_TO_STRING_PLAIN); + write(s, jstring, strlen(jstring)); + json_object_put(counters); +} + + void send_eee(int s) { struct json_object *ports, *v; @@ -547,6 +572,14 @@ void launch(struct Server *server) else send_config(new_socket); goto done; + } else if (!strncmp(&buffer[4], "/counters.json?port=", 20)) { + int port = atoi(&buffer[24]); + printf("Counters request for %d\n", port); + if (!authenticated) + send_unauthorized(new_socket); + else + send_counters(new_socket, port); + goto done; } if (!authenticated && !(!strncmp(&buffer[4], "/login.html", 11) || !strncmp(&buffer[4], "/style.css", 10))) { send_to_login(new_socket);