Skip to content

Commit

Permalink
fix issue hanwckf#353 and use swconfig to get port flow
Browse files Browse the repository at this point in the history
if switch in GSW, then use swconfig to get the exact flow for each port.
  • Loading branch information
wsk170 authored Dec 14, 2024
1 parent 0dcf3cb commit 59f6303
Showing 1 changed file with 158 additions and 130 deletions.
288 changes: 158 additions & 130 deletions package/emortal/autocore/files/generic/21_ethinfo.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,54 @@
'use strict';
'require baseclass';
'require fs';
'require rpc';
'require network';

var callSwconfigFeatures = rpc.declare({
object: 'luci',
method: 'getSwconfigFeatures',
params: ['switch'],
expect: { '': {} }
});

var callSwconfigPortState = rpc.declare({
let callSwconfigPortState = rpc.declare({
object: 'luci',
method: 'getSwconfigPortState',
params: ['switch'],
expect: { result: [] }
});

var callLuciBoardJSON = rpc.declare({
let callLuciBoardJSON = rpc.declare({
object: 'luci-rpc',
method: 'getBoardJSON',
expect: { '': {} }
});

var callLuciNetworkDevices = rpc.declare({
let callLuciNetworkDevices = rpc.declare({
object: 'luci-rpc',
method: 'getNetworkDevices',
expect: { '': {} }
});

var isDSA = false;

const ethStyle = {
box: 'max-width: 100px;',
head: `
border-radius: 7px 7px 0 0;
text-align: center;
font-weight: bold;`,
body: `
border: 1px solid lightgrey;
border-radius: 0 0 7px 7px;
display: flex; flex-direction: column;
align-items: center; justify-content: center;`,
icon: 'margin: 5px; width: 40px;',
speed: 'font-size: 0.8rem; font-weight: bold;',
traffic: `
border-top: 1px solid lightgrey;
font-size: 0.8rem;`
};
function getSwitchPortFlow() {
const portFlow = [];
fs.exec('/sbin/swconfig', ['dev', 'switch0', 'show']).then((res) => {
const lines = res.stdout.trim().split(/\n/);
let portNum;
for (let line of lines) {
let match = line.match(/^Port\s+(\d+):$/);
if (match != null) {
portNum = Number(match[1]);
portFlow[portNum] = {};
continue;
}
match = line.match(/^TxByte\s*:\s*(\d+)$/);
if (match != null) {
portFlow[portNum].rxflow = Number(match[1]);
continue;
}
match = line.match(/^RxByte\s*:\s*(\d+)$/);
if (match != null) {
portFlow[portNum].txflow = Number(match[1]);
continue;
}
}
});
return portFlow;
}

function formatSpeed(speed) {
if (speed <= 0) return '-';
Expand All @@ -57,123 +58,150 @@ function formatSpeed(speed) {
}

function getPortColor(carrier, duplex) {
if (!carrier) return 'background-color: whitesmoke;';
if (duplex === 'full' || duplex === true)
return 'background-color: greenyellow;';
return 'background-color: darkorange';
if (!carrier) return 'Gainsboro;';
if (duplex === 'full' || duplex === true) return 'greenyellow;';
return 'darkorange';
}

function getPortIcon(carrier) {
return L.resource(`icons/port_${carrier ? 'up' : 'down'}.png`);
}

function portDom(link, duplex, label, speed, tx_bytes, rx_bytes) {
const portIcon = getPortIcon(link);
const portColor = getPortColor(link, duplex);

return E('div', { style: ethStyle.box }, [
E('div', { style: ethStyle.head + portColor }, label),
E('div', { style: ethStyle.body }, [
E('img', { style: ethStyle.icon, src: portIcon }),
E('div', { style: ethStyle.speed }, formatSpeed(speed)),
E('div', { style: ethStyle.traffic }, [
'\u25b2\u202f%1024.1mB'.format(tx_bytes),
E('br'),
'\u25bc\u202f%1024.1mB'.format(rx_bytes)
])
])
]);
}

return baseclass.extend({
title: _('Ethernet Information'),

load: function () {
return network.getSwitchTopologies().then(function (topologies) {
if (Object.keys(topologies).length === 0) {
isDSA = true;
return Promise.all([
L.resolveDefault(callLuciBoardJSON(), {}),
L.resolveDefault(callLuciNetworkDevices(), {})
]);
}

callSwconfigPortState('switch0').then((ports) => {
topologies.switch0.portstate = ports;
function getPorts(board, netdevs, switches, portflow) {
const ports = [];

if (Object.keys(switches).length === 0) {
const network = board.network;
const ifnames = [network?.wan?.device].concat(network?.lan?.ports);
for (const ifname of ifnames) {
if (ifname in netdevs === false) continue;
const dev = netdevs[ifname];
ports.push({
ifname: dev.name,
carrier: dev.link.carrier,
duplex: dev.link.duplex,
speed: dev.link.speed,
txflow: dev.stats.tx_bytes,
rxflow: dev.stats.rx_bytes
});
return Promise.all([
topologies,
L.resolveDefault(callLuciBoardJSON(), {}),
L.resolveDefault(callLuciNetworkDevices(), {})
]);
});
},
}
return ports;
}

render_gsw: function (data) {
const topologies = data[0];
const board = data[1];
const netdevs = data[2];

let stats;
let foundWAN = false;
const ethPorts = [];
const switch0 = topologies.switch0;
for (const port of switch0.ports) {
const label = port.label.toUpperCase();
const { link, duplex, speed } = switch0.portstate[port.num];
const txrx = { tx_bytes: 0, rx_bytes: 0 };

if (label.startsWith('WAN')) {
foundWAN = true;
stats = netdevs[board.network.wan.device].stats;
const { tx_bytes, rx_bytes } = stats;
ethPorts.unshift(
portDom(link, duplex, 'WAN', speed, tx_bytes, rx_bytes)
);
} else if (label.startsWith('LAN')) {
stats = netdevs['br-lan'].stats;
const { tx_bytes, rx_bytes } = link ? stats : txrx;
ethPorts.push(portDom(link, duplex, label, speed, tx_bytes, rx_bytes));
let wanInSwitch;
const switch0 = switches['switch0'];
const lan = netdevs['br-lan'];
const wan = netdevs[board.network.wan.device];
for (const port of switch0.ports) {
const label = port.label.toUpperCase();
const portstate = switch0.portstate[port.num];
portstate.ifname = label;
portstate.carrier = portstate.link;
if (portflow[port.num]) {
portstate.txflow = portflow[port.num].txflow;
portstate.rxflow = portflow[port.num].rxflow;
}
if (label.startsWith('WAN')) {
wanInSwitch = true;
if (!portstate.rxflow && wan) {
portstate.txflow = wan.stats.tx_bytes;
portstate.rxflow = wan.stats.rx_bytes;
}
ports.unshift(portstate);
} else if (label.startsWith('LAN')) {
if (!portstate.rxflow && lan) {
portstate.txflow = lan.stats.tx_bytes;
portstate.rxflow = lan.stats.rx_bytes;
}
ports.push(portstate);
}
}
if (wanInSwitch) return ports;

if (wan) {
ports.unshift({
ifname: 'WAN',
carrier: wan.link.carrier,
duplex: wan.link.duplex,
speed: wan.link.speed,
txflow: wan.stats.tx_bytes,
rxflow: wan.stats.rx_bytes
});
}
return ports;
}

if (foundWAN) return ethPorts;

const wan = netdevs[board.network.wan.device];
const { speed, duplex, carrier } = wan.link;
const { tx_bytes, rx_bytes } = wan.stats;
ethPorts.unshift(
portDom(carrier, duplex, 'WAN', speed, tx_bytes, rx_bytes)
function renderPorts(data) {
const css = {
grids: `
display: grid; grid-gap: 5px 10px;
grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
margin-bottom: 1em;
`,
head: `
color: Black;
text-align: center;
font-weight: bold;
border-radius: 7px 7px 0 0;
`,
body: `
border: 1px solid lightgrey;
border-radius: 0 0 7px 7px;
display: flex; flex-direction: column;
align-items: center; justify-content: center;`,
icon: 'margin: 5px; width: 32px;',
speed: 'font-size: 0.8rem; font-weight: bold;',
flow: `
border-top: 1px solid lightgrey;
font-size: 0.8rem;`
};

const ports = [];
getPorts(...data).forEach((port) => {
const { carrier, duplex } = port;
const ifname = port.ifname.replace(' ', '');
const color = `background-color: ${getPortColor(carrier, duplex)};`;
ports.push(
E('div', {}, [
E('div', { style: css.head + color }, ifname),
E('div', { style: css.body }, [
E('img', { style: css.icon, src: getPortIcon(carrier) }),
E('div', { style: css.speed }, formatSpeed(port.speed)),
E('div', { style: css.flow }, [
'\u25b2\u202f%1024.1mB'.format(carrier ? port.txflow : 0),
E('br'),
'\u25bc\u202f%1024.1mB'.format(carrier ? port.rxflow : 0)
])
])
])
);
return ethPorts;
},
});

render_dsa: function (data) {
const board = data[0];
const netdevs = data[1];

const ethPorts = [];
const wan = board.network.wan.device;
let devices = `${wan},lan0,lan1,lan2,lan3,lan4,lan5,lan6`;
devices = devices.split(',');
for (const device of devices) {
if (device in netdevs === false) continue;
const dev = netdevs[device];
const label = dev.name;
const { speed, duplex, carrier } = dev.link;
const { tx_bytes, rx_bytes } = dev.stats;
ethPorts.push(portDom(carrier, duplex, label, speed, tx_bytes, rx_bytes));
}
return E('div', { style: css.grids }, ports);
}

return ethPorts;
return baseclass.extend({
title: _('Ethernet Information'),

load: function () {
return Promise.all([
L.resolveDefault(callLuciBoardJSON(), {}),
L.resolveDefault(callLuciNetworkDevices(), {}),
network.getSwitchTopologies().then((topologies) => {
if (Object.keys(topologies).length === 0) return {};
callSwconfigPortState('switch0').then((portstate) => {
topologies['switch0'].portstate = portstate;
});
return topologies;
}),
network.getSwitchTopologies().then((topologies) => {
if (Object.keys(topologies).length === 0) return [];
return getSwitchPortFlow();
})
]);
},

render: function (data) {
const ethPorts = isDSA ? this.render_dsa(data) : this.render_gsw(data);
const gridStyle = `
display: grid; grid-gap: 5px 5px;
grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
margin-bottom: 1em`;
return E('div', { style: gridStyle }, ethPorts);
return renderPorts(data);
}
});

0 comments on commit 59f6303

Please sign in to comment.