mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
dbg vlan config
This commit is contained in:
parent
f480b001c7
commit
f4828d4c1a
21 changed files with 399 additions and 240 deletions
|
|
@ -11,7 +11,7 @@ USE_LOCAL:=0
|
|||
ifneq ($(USE_LOCAL),1)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/bbfdm.git
|
||||
PKG_SOURCE_VERSION:=ba2812ae1f9ac216fc880096b1c65f8b63ba249c
|
||||
PKG_SOURCE_VERSION:=1615b42e405faceceac825f9c0387a58b90785ae
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -63,8 +63,9 @@ endef
|
|||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_DIR) $(1)/etc/bbfdm
|
||||
$(INSTALL_DIR) $(1)/usr/lib/dmf_handlers
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/default.db $(1)/etc/default_dm.db
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/default.db $(1)/etc/bbfdm/default_dm.db
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/libdm.so $(1)/usr/lib/
|
||||
# Copy only .js handler files recursively, preserving folder structure (skip hidden files/folders)
|
||||
( cd $(PKG_BUILD_DIR)/dm-files; \
|
||||
|
|
|
|||
|
|
@ -193,7 +193,8 @@
|
|||
"db": "true",
|
||||
"flags": [
|
||||
"linker"
|
||||
]
|
||||
],
|
||||
"js-value": "ifname"
|
||||
},
|
||||
{
|
||||
"name": "LastChange",
|
||||
|
|
@ -207,7 +208,8 @@
|
|||
"dataType": "pathRef[]",
|
||||
"pathRef": [
|
||||
"Device.Bridging.Bridge.{i}.Port."
|
||||
]
|
||||
],
|
||||
"js-value": "ssidPath"
|
||||
},
|
||||
{
|
||||
"name": "ManagementPort",
|
||||
|
|
@ -235,7 +237,8 @@
|
|||
"CustomerEdgePort",
|
||||
"CustomerVLANPort",
|
||||
"VLANUnawarePort"
|
||||
]
|
||||
],
|
||||
"default": "CustomerVLANPort"
|
||||
},
|
||||
{
|
||||
"name": "PVID",
|
||||
|
|
|
|||
|
|
@ -13,23 +13,23 @@ import {
|
|||
getUciOption, getUciByType, setUci, addUci, delUci
|
||||
} from '../uci.js';
|
||||
import * as dm from '../dm_consts.js';
|
||||
import { getBridgeDeviceType } from './common.js';
|
||||
|
||||
function clearUnusedDevice(oldPorts, newPorts, devices) {
|
||||
oldPorts?.forEach((port) => {
|
||||
oldPorts?.forEach(port => {
|
||||
if (port.includes('.') && !newPorts?.includes(port)) {
|
||||
const dev = devices?.find((x) => x.name === port);
|
||||
dev?.delUci('network', dev['.name']);
|
||||
const dev = devices?.find(x => x.name === port);
|
||||
if (dev?.['.name']) delUci('network', dev['.name']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function applyBridge(bri, ports, VLANs, VLANPorts) {
|
||||
const ifnames = [];
|
||||
const devices = getUciByType('network', 'device');
|
||||
const devices = getUciByType('network', 'device')?.filter(x => x.type !== undefined);
|
||||
|
||||
const portsVal = getUciOption('network', bri._key, 'ports');
|
||||
if (portsVal) {
|
||||
delUci('network', bri._key, null, 'ports');
|
||||
}
|
||||
if (portsVal) delUci('network', bri._key, null, 'ports');
|
||||
|
||||
// get ports ethernet ifnames
|
||||
for (const port of ports || []) {
|
||||
|
|
@ -42,58 +42,75 @@ function applyBridge(bri, ports, VLANs, VLANPorts) {
|
|||
_log_error(`ifname not found for port: ${port.LowerLayers}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check vlan
|
||||
const portPath = `Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}`;
|
||||
const vp = VLANPorts?.find((x) => x.Port === portPath);
|
||||
const vp = VLANPorts?.find(x => x.Port === portPath);
|
||||
if (!vp?.VLAN) {
|
||||
ifnames.push(ifname);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get index of the vlan
|
||||
const [, indices] = _dm_node(vp.VLAN);
|
||||
const vlanIdx = indices[indices.length - 1];
|
||||
const vlan = VLANs?.find((x) => x['.index'] === vlanIdx);
|
||||
const vlan = VLANs?.find(x => x['.index'] === vlanIdx);
|
||||
if (!vlan || vlan.VLANID <= 0) {
|
||||
ifnames.push(ifname);
|
||||
continue;
|
||||
}
|
||||
|
||||
const eth = ifname;
|
||||
ifname = `${ifname}.${vlan.VLANID}`;
|
||||
|
||||
const dev = devices?.find((x) => x.name === ifname);
|
||||
const dev = devices?.find(x => x.name === ifname);
|
||||
let devName;
|
||||
if (dev) {
|
||||
devName = dev['.name'];
|
||||
} else {
|
||||
devName = `br_${bri['.index']}_port_${vp['.index']}`;
|
||||
const options = {
|
||||
addUci('network', 'device', devName, {
|
||||
ifname: eth,
|
||||
name: ifname,
|
||||
vid: vlan.VLANID,
|
||||
};
|
||||
addUci(
|
||||
'network',
|
||||
'device',
|
||||
devName,
|
||||
options,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const uciConfigs = {};
|
||||
if (!vp.Untagged) {
|
||||
|
||||
// Handle Type parameter - determine device type based on port Type or default behavior
|
||||
let deviceType = '';
|
||||
if (port.Type) {
|
||||
deviceType = getBridgeDeviceType(port.Type);
|
||||
if (deviceType) uciConfigs.type = deviceType;
|
||||
} else if (!vp.Untagged) {
|
||||
uciConfigs.type = '8021q';
|
||||
}
|
||||
uciConfigs.disabled = vlan.Enable && vp.Enable ? '0' : '1';
|
||||
if (port.PriorityRegeneration !== '0,1,2,3,4,5,6,7') {
|
||||
uciConfigs.ingress_qos_mapping = port.PriorityRegeneration.split(',').map((p, i) => `${i}:${p}`);
|
||||
} else {
|
||||
uciConfigs.ingress_qos_mapping = '';
|
||||
deviceType = '8021q';
|
||||
}
|
||||
|
||||
if (port.X_IOPSYS_EU_EgressPriorityRegeneration !== '0,1,2,3,4,5,6,7') {
|
||||
uciConfigs.egress_qos_mapping = port.X_IOPSYS_EU_EgressPriorityRegeneration.split(',').map((p, i) => `${i}:${p}`);
|
||||
} else {
|
||||
uciConfigs.egress_qos_mapping = '';
|
||||
// Handle TPID parameter
|
||||
if (port.TPID) {
|
||||
// If TPID is explicitly set, use it and derive device type if needed
|
||||
uciConfigs.tpid = port.TPID;
|
||||
// Set device type based on TPID if not already set
|
||||
if (!deviceType) {
|
||||
if (port.TPID === '33024') {
|
||||
uciConfigs.type = '8021q';
|
||||
} else if (port.TPID === '34984') {
|
||||
uciConfigs.type = '8021ad';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uciConfigs.disabled = vlan.Enable && vp.Enable ? '0' : '1';
|
||||
uciConfigs.ingress_qos_mapping = port.PriorityRegeneration !== '0,1,2,3,4,5,6,7'
|
||||
? port.PriorityRegeneration.split(',').map((p, i) => `${i}:${p}`)
|
||||
: '';
|
||||
|
||||
uciConfigs.egress_qos_mapping = port.X_IOPSYS_EU_EgressPriorityRegeneration !== ''
|
||||
? port.X_IOPSYS_EU_EgressPriorityRegeneration.split(',').map((p, i) => `${i}:${p}`)
|
||||
: '';
|
||||
|
||||
setUci('network', devName, uciConfigs);
|
||||
ifnames.push(ifname);
|
||||
}
|
||||
|
|
@ -132,22 +149,18 @@ export function initDeviceBridgingBridge(bri) {
|
|||
// create empty interface for the bridge
|
||||
addUci('network', 'interface', `itf_${bri._key}`, {
|
||||
device: bri.Name,
|
||||
layer2_bridge: '1',
|
||||
bridge_empty: '1',
|
||||
});
|
||||
}
|
||||
|
||||
export function filterDeviceBridgingBridge(uci) {
|
||||
return (uci.type === 'bridge');
|
||||
}
|
||||
export const filterDeviceBridgingBridge = uci => uci.type === 'bridge';
|
||||
|
||||
export function deinitDeviceBridgingBridge(uci) {
|
||||
const ports = getUciOption('network', uci, 'ports');
|
||||
ports?.forEach((port) => {
|
||||
ports?.forEach(port => {
|
||||
if (port.includes('.')) {
|
||||
const dev = getUciByType('network', 'device', { match: { name: port } });
|
||||
if (dev) {
|
||||
delUci('network', dev[0]['.name']);
|
||||
}
|
||||
if (dev) delUci('network', dev[0]['.name']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@
|
|||
*/
|
||||
|
||||
import { getUciByType } from '../uci.js';
|
||||
import { getBridgePortType, getTPIDFromDeviceType } from './common.js';
|
||||
|
||||
function importBridge(dev, devices, bridges) {
|
||||
const briPorts = [];
|
||||
const briVLAN = [];
|
||||
const briVLANPort = [];
|
||||
|
||||
// create the management port first
|
||||
briPorts.push({
|
||||
Alias: `cpe-${dev.name}`,
|
||||
|
|
@ -36,32 +38,36 @@ function importBridge(dev, devices, bridges) {
|
|||
_key: dev['.name'],
|
||||
});
|
||||
|
||||
const ethPorts = devices.filter((x) => x.ifname?.startsWith('eth'));
|
||||
const ethPorts = devices.filter(x => x.ifname?.startsWith('eth'));
|
||||
|
||||
for (const portName of (dev.ports || [])) {
|
||||
let portIndex = ethPorts.findIndex((x) => x.ifname === portName);
|
||||
let portIndex = ethPorts.findIndex(x => x.ifname === portName);
|
||||
if (portIndex >= 0) {
|
||||
// Regular ethernet port
|
||||
const ethDevice = ethPorts[portIndex];
|
||||
const portType = getBridgePortType(ethDevice.type) || 'CustomerVLANPort';
|
||||
const tpid = getTPIDFromDeviceType(ethDevice.type, ethDevice.tpid);
|
||||
|
||||
briPorts.push({
|
||||
Enable: 1,
|
||||
Name: ethPorts[portIndex]['.name'],
|
||||
Alias: `cpe-${ethPorts[portIndex]['.name']}`,
|
||||
TPID: 37120,
|
||||
Name: ethDevice['.name'],
|
||||
Alias: `cpe-${ethDevice['.name']}`,
|
||||
TPID: tpid,
|
||||
PVID: 1,
|
||||
Type: 'CustomerVLANPort',
|
||||
Type: portType,
|
||||
LowerLayers: `Device.Ethernet.Interface.${portIndex + 1}`,
|
||||
_key: ethPorts[portIndex]['.name'],
|
||||
_key: ethDevice['.name'],
|
||||
});
|
||||
} else {
|
||||
// vlan device
|
||||
const device = devices.find((x) => x.name === portName);
|
||||
const device = devices.find(x => x.name === portName);
|
||||
if (!device) {
|
||||
_log_error('device not found', portName);
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device.type === '8021q' || device.type === 'untagged') {
|
||||
let vlanIndex = briVLAN.findIndex((x) => x.VLANID === device.vid);
|
||||
if (device.type === '8021q' || device.type === 'untagged' || device.type === '8021ad' || device.type === 'transparent') {
|
||||
let vlanIndex = briVLAN.findIndex(x => x.VLANID === device.vid);
|
||||
if (vlanIndex < 0) {
|
||||
briVLAN.push({ Enable: 1, VLANID: device.vid });
|
||||
vlanIndex = briVLAN.length;
|
||||
|
|
@ -69,14 +75,21 @@ function importBridge(dev, devices, bridges) {
|
|||
vlanIndex += 1;
|
||||
}
|
||||
|
||||
// Get the base ethernet device to determine the correct port index
|
||||
const baseEthDevice = ethPorts.find(x => device.ifname === x.ifname);
|
||||
const basePortIndex = baseEthDevice ? ethPorts.indexOf(baseEthDevice) : 0;
|
||||
|
||||
const portType = getBridgePortType(device.type) || 'CustomerVLANPort';
|
||||
const tpid = getTPIDFromDeviceType(device.type, device.tpid);
|
||||
|
||||
briPorts.push({
|
||||
Enable: 1,
|
||||
Name: device['.name'],
|
||||
Alias: `cpe-${port['.name']}`,
|
||||
TPID: 33024,
|
||||
Alias: `cpe-${device['.name']}`,
|
||||
TPID: tpid,
|
||||
PVID: device.vid,
|
||||
Type: 'CustomerVLANPort',
|
||||
LowerLayers: `Device.Ethernet.Interface.${port['.index'] + 1}`,
|
||||
Type: portType,
|
||||
LowerLayers: `Device.Ethernet.Interface.${basePortIndex + 1}`,
|
||||
_key: device['.name'],
|
||||
});
|
||||
|
||||
|
|
@ -95,14 +108,14 @@ function importBridge(dev, devices, bridges) {
|
|||
|
||||
if (briPorts.length > 1) {
|
||||
const indexes = Array.from({ length: briPorts.length - 1 }, (v, i) => i + 2);
|
||||
briPorts[0].LowerLayers = indexes.map((i) => `Device.Bridging.Bridge.${bridges.length}.Port.${i}`).join(',');
|
||||
briPorts[0].LowerLayers = indexes.map(i => `Device.Bridging.Bridge.${bridges.length}.Port.${i}`).join(',');
|
||||
}
|
||||
}
|
||||
|
||||
export function importDeviceBridgingBridge() {
|
||||
const bridges = [];
|
||||
const devices = getUciByType('network', 'device');
|
||||
devices?.forEach((dev) => {
|
||||
devices?.forEach(dev => {
|
||||
if (dev.type === 'bridge') {
|
||||
importBridge(dev, devices, bridges);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,17 +10,16 @@
|
|||
*/
|
||||
|
||||
import * as std from 'std';
|
||||
import { isTrue } from '../utils.js';
|
||||
import { getUciByType } from '../uci.js';
|
||||
|
||||
function setMgmtPortLowerLayers(bri) {
|
||||
if (!bri) {
|
||||
return 0;
|
||||
}
|
||||
if (!bri) return 0;
|
||||
|
||||
const portPath = `Device.Bridging.Bridge.${bri['.index']}.Port.`;
|
||||
const mgmtPort = _dm_instances(portPath, '(ManagementPort="true" OR ManagementPort=1)');
|
||||
if (mgmtPort.length !== 1) {
|
||||
return 0;
|
||||
}
|
||||
if (mgmtPort.length !== 1) return 0;
|
||||
|
||||
const nonMgmtPort = _dm_instances(portPath, '(ManagementPort="false" OR ManagementPort=0)');
|
||||
_dm_update(`${mgmtPort[0]}.LowerLayers`, nonMgmtPort.join(','));
|
||||
return 0;
|
||||
|
|
@ -36,115 +35,86 @@ export function changedDeviceBridgingBridgePortManagementPort(bri) {
|
|||
|
||||
export function getDeviceBridgingBridgeStatus(bri) {
|
||||
const enable = _dm_get(`Device.Bridging.Bridge.${bri['.index']}.Enable`);
|
||||
if (enable) {
|
||||
return 'Enabled';
|
||||
}
|
||||
|
||||
return 'Disabled';
|
||||
return enable ? 'Enabled' : 'Disabled';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgeSTPStatus(bri) {
|
||||
let status = 'Disabled';
|
||||
const stpState = std.loadFile(`/sys/class/net/${bri.Name}/bridge/stp_state`)?.trim();
|
||||
if (stpState === '1') {
|
||||
status = 'Enabled';
|
||||
}
|
||||
return status;
|
||||
return stpState === '1' ? 'Enabled' : 'Disabled';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortStatus(bri, port) {
|
||||
if (!port['.db']) {
|
||||
return 'Up';
|
||||
}
|
||||
if (!port['.db']) return 'Up';
|
||||
|
||||
const enable = _dm_get(`Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}.Enable`);
|
||||
if (enable) {
|
||||
return 'Up';
|
||||
}
|
||||
|
||||
return 'Down';
|
||||
return enable ? 'Up' : 'Down';
|
||||
}
|
||||
|
||||
export function infoDeviceBridgingBridgePort(path, port) {
|
||||
const mgmtPort = _dm_get(`${path}.ManagementPort`);
|
||||
if (typeof mgmtPort === 'undefined' || mgmtPort) {
|
||||
return;
|
||||
}
|
||||
if (typeof mgmtPort === 'undefined' || mgmtPort) return;
|
||||
|
||||
const lower = _dm_get(`${path}.LowerLayers`);
|
||||
if (!lower) {
|
||||
return;
|
||||
if (lower) {
|
||||
port.ifname = _dm_linker_value(lower);
|
||||
}
|
||||
port.ifname = _dm_linker_value(lower);
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsBytesSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_bytes`)?.trim();
|
||||
// Helper function to read network statistics
|
||||
function getNetworkStat(port, statName) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/${statName}`)?.trim();
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsBytesReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_bytes`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsBytesSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_bytes');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsPacketsSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsBytesReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_bytes');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsPacketsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsErrorsSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_errors`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsErrorsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_errors`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsErrorsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_errors');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsDiscardPacketsSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_dropped`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsErrorsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_errors');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsDiscardPacketsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_dropped`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsDiscardPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_dropped');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsMulticastPacketsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/multicast`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsDiscardPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_dropped');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsUnicastPacketsSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_unicast_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsMulticastPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'multicast');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsUnicastPacketsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_unicast_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsUnicastPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_unicast_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsMulticastPacketsSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_multicast_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsUnicastPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_unicast_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsBroadcastPacketsSent(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/tx_broadcast_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsMulticastPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_multicast_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsBroadcastPacketsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_broadcast_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsBroadcastPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_broadcast_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePortStatsUnknownProtoPacketsReceived(bri, port) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/rx_unknown_packets`)?.trim();
|
||||
}
|
||||
export const getDeviceBridgingBridgePortStatsBroadcastPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_broadcast_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsUnknownProtoPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_unknown_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePort(bri) {
|
||||
let networkName = bri.Name;
|
||||
if (bri.Name.startsWith('br-')) {
|
||||
networkName = bri.Name.slice(3);
|
||||
}
|
||||
const networkName = bri.Name.startsWith('br-') ? bri.Name.slice(3) : bri.Name;
|
||||
|
||||
const wifiIfaces = getUciByType('wireless', 'wifi-iface', { match: { multi_ap: '2' } });
|
||||
wifiIfaces?.forEach((x, i) => {
|
||||
wifiIfaces?.forEach(x => {
|
||||
const ssid = getUciByType('dmmap_wireless', 'ssid',
|
||||
{ match: { device: x.device, ssid: x.ssid}, confdir: '/etc/bbfdm/dmmap'});
|
||||
if (Array.isArray(ssid) && ssid.length > 0) {
|
||||
|
|
@ -152,29 +122,12 @@ export function getDeviceBridgingBridgePort(bri) {
|
|||
}
|
||||
});
|
||||
|
||||
return wifiIfaces?.filter((x) => x.network === networkName);
|
||||
return wifiIfaces?.filter(x => x.network === networkName);
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortLowerLayers(bri, port) {
|
||||
return port.ssidPath || '';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortManagementPort() {
|
||||
return '0';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortPVID() {
|
||||
return '1';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortTPID() {
|
||||
return '37120';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortType() {
|
||||
return 'CustomerVLANPort';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortName(bri, port) {
|
||||
return port.ifname;
|
||||
export function setDeviceBridgingBridgePortManagementPort(val, bri, port) {
|
||||
if (isTrue(val)) {
|
||||
_db_set(`Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}.Name`, bri.Name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
61
dm-framework/datamodels/src/dm-files/Bridge/common.js
Executable file
61
dm-framework/datamodels/src/dm-files/Bridge/common.js
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Genexis B.V. All rights reserved.
|
||||
*
|
||||
* This Software and its content are protected by the Dutch Copyright Act
|
||||
* ('Auteurswet'). All and any copying and distribution of the software
|
||||
* and its content without authorization by Genexis B.V. is
|
||||
* prohibited. The prohibition includes every form of reproduction and
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
export const bridgePortTypeMap = [
|
||||
{ portType: 'CustomerNetworkPort', devType: '8021ad' },
|
||||
{ portType: 'CustomerVLANPort', devType: '8021q' },
|
||||
{ portType: 'CustomerVLANPort', devType: 'untagged' },
|
||||
{ portType: 'CustomerVLANPort', devType: '' },
|
||||
{ portType: 'CustomerVLANPort', devType: undefined },
|
||||
{ portType: 'VLANUnawarePort', devType: 'transparent' }
|
||||
];
|
||||
|
||||
export function getBridgePortType(devType) {
|
||||
const mapping = bridgePortTypeMap.find(map => map.devType === devType);
|
||||
return mapping ? mapping.portType : null;
|
||||
}
|
||||
|
||||
export function getBridgeDeviceType(portType) {
|
||||
const mapping = bridgePortTypeMap.find(map => map.portType === portType);
|
||||
return mapping ? mapping.devType : null;
|
||||
}
|
||||
|
||||
export function getDefaultTPID(deviceType) {
|
||||
switch (deviceType) {
|
||||
case '8021q':
|
||||
return '33024';
|
||||
case '8021ad':
|
||||
return '34984';
|
||||
default:
|
||||
return '37120';
|
||||
}
|
||||
}
|
||||
|
||||
export function getTPIDFromDeviceType(deviceType, explicitTPID) {
|
||||
// If explicit TPID is set, use it
|
||||
if (explicitTPID && explicitTPID !== '') {
|
||||
return parseInt(explicitTPID, 10);
|
||||
}
|
||||
|
||||
// Default TPID based on device type
|
||||
switch (deviceType) {
|
||||
case '8021q':
|
||||
return 33024;
|
||||
case '8021ad':
|
||||
return 34984;
|
||||
case 'untagged':
|
||||
case 'transparent':
|
||||
case '':
|
||||
case undefined:
|
||||
default:
|
||||
return 37120;
|
||||
}
|
||||
}
|
||||
|
|
@ -261,4 +261,8 @@ export function transformInputObject(obj) {
|
|||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function isTrue(val) {
|
||||
return val === 'true' || val === '1' || val === true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ define Package/$(PKG_NAME)/install
|
|||
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
|
||||
$(INSTALL_DIR) $(1)/lib/upgrade/keep.d
|
||||
# $(INSTALL_BIN) ./files/etc/init.d/dm-agent $(1)/etc/init.d/dm-agent
|
||||
$(INSTALL_BIN) ./files/lib/upgrade/keep.d/dm-agent $(1)/lib/upgrade/keep.d/dm-agent
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/dm-agent $(1)/usr/sbin
|
||||
endef
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
config dm_agent 'agent'
|
||||
option loglevel '1'
|
||||
|
|
@ -1 +0,0 @@
|
|||
/etc/dm.db
|
||||
|
|
@ -722,21 +722,6 @@ static int start_trans(int proto)
|
|||
return agent_ctx.trans_id;
|
||||
}
|
||||
|
||||
static int commit_trans()
|
||||
{
|
||||
dmlog_debug("commit_trans");
|
||||
int ret = dmapi_session_end(TRANX_COMMIT_AND_APPLY);
|
||||
agent_ctx.trans_id = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int abort_trans()
|
||||
{
|
||||
dmlog_debug("abort_trans");
|
||||
agent_ctx.trans_id = 0;
|
||||
return dmapi_session_end(TRANX_ROLLBACK);
|
||||
}
|
||||
|
||||
enum {
|
||||
TRANS_CMD,
|
||||
TRANS_OPTIONAL,
|
||||
|
|
@ -777,13 +762,10 @@ static int usp_transaction_handler(struct ubus_context *ctx, struct ubus_object
|
|||
|
||||
get_bbf_options(&options, tb[TRANS_OPTIONAL]);
|
||||
|
||||
if (strcmp(trans_cmd, "start") != 0 && strcmp(trans_cmd, "status") != 0 &&
|
||||
(agent_ctx.trans_id == 0 || agent_ctx.trans_id != options.trans_id)) {
|
||||
dmlog_error("invalid transaction id for cmd: %s. tid: %d", trans_cmd, options.trans_id);
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
|
||||
if (strcmp(trans_cmd, "start") == 0) {
|
||||
set_uci_savedir(options.dm_type);
|
||||
ret = start_trans(options.dm_type);
|
||||
if (ret > 0) {
|
||||
blobmsg_add_u8(&bb, "status", true);
|
||||
|
|
@ -792,10 +774,14 @@ static int usp_transaction_handler(struct ubus_context *ctx, struct ubus_object
|
|||
blobmsg_add_u8(&bb, "status", false);
|
||||
}
|
||||
} else if (strcmp(trans_cmd, "commit") == 0) {
|
||||
ret = commit_trans();
|
||||
ret = dmapi_session_end(TRANX_COMMIT);
|
||||
blobmsg_add_u8(&bb, "status", (ret == 0));
|
||||
} else if (strcmp(trans_cmd, "apply") == 0) {
|
||||
set_uci_savedir(options.dm_type);
|
||||
ret = dmapi_session_apply();
|
||||
blobmsg_add_u8(&bb, "status", (ret == 0));
|
||||
} else if (strcmp(trans_cmd, "abort") == 0) {
|
||||
ret = abort_trans();
|
||||
ret = dmapi_session_end(TRANX_ROLLBACK);
|
||||
blobmsg_add_u8(&bb, "status", (ret == 0));
|
||||
} else if (strcmp(trans_cmd, "status") == 0) {
|
||||
int64_t rem = uloop_timeout_remaining64(&agent_ctx.trans_timer);
|
||||
|
|
@ -914,7 +900,7 @@ int usp_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
|
|||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
int res = 0;
|
||||
void *array = blobmsg_open_array(&bb, "results");
|
||||
if (dm_node_is_parameter(node.id)) {
|
||||
if (set_blob_value(&node, tb[DM_SET_VALUE]) != 0) {
|
||||
|
|
@ -994,7 +980,7 @@ int usp_add_handler(struct ubus_context *ctx, struct ubus_object *obj,
|
|||
dm_node_t node;
|
||||
dm_node_t param_node;
|
||||
bool allow_partial = false;
|
||||
int ret = 0;
|
||||
int res = 0;
|
||||
|
||||
memset(&bb, 0, sizeof(struct blob_buf));
|
||||
blob_buf_init(&bb, 0);
|
||||
|
|
@ -1142,7 +1128,6 @@ int usp_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
|
|||
char *path = blobmsg_get_string(tb[DM_DEL_PATH]);
|
||||
if (dm_path2node(path, &node) != 0 || dmapi_object_del(&node) < 0) {
|
||||
set_result(&bb, path, 9005, "Invalid path");
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
set_result(&bb, path, 0, "1");
|
||||
|
|
|
|||
|
|
@ -531,16 +531,19 @@ int dbmgr_finalize(void)
|
|||
|
||||
int dbmgr_tranx_begin(void)
|
||||
{
|
||||
dmlog_debug("dbmgr_tranx_begin");
|
||||
return exec_trans_sql("BEGIN;", NULL, NULL);
|
||||
}
|
||||
|
||||
int dbmgr_tranx_revert(void)
|
||||
{
|
||||
dmlog_debug("dbmgr_tranx_revert");
|
||||
return exec_trans_sql("ROLLBACK;", NULL, NULL);
|
||||
}
|
||||
|
||||
int dbmgr_tranx_commit(void)
|
||||
{
|
||||
dmlog_debug("dbmgr_tranx_commit");
|
||||
int ret = exec_trans_sql("COMMIT;", NULL, NULL);
|
||||
|
||||
if (ret != 0) {
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@
|
|||
|
||||
extern int importDM();
|
||||
|
||||
#define DEFFAULT_DB_PATH "/etc/default_dm.db"
|
||||
#define DB_PATH "/etc/dm.db"
|
||||
#define BACKUP_DB_PATH "/etc/dm-backup.db"
|
||||
#define NEW_DB_PATH "/etc/dm-new.db"
|
||||
#define DEFFAULT_DB_PATH "/etc/bbfdm/default_dm.db"
|
||||
#define DB_PATH "/etc/bbfdm/dm.db"
|
||||
#define BACKUP_DB_PATH "/etc/bbfdm/dm-backup.db"
|
||||
#define NEW_DB_PATH "/etc/bbfdm/dm-new.db"
|
||||
|
||||
#define INODE_BUF_EXPIRE_TIME 2000 // in ms
|
||||
#define NODELIST_DEFAULT_CNT 32
|
||||
|
|
@ -41,7 +41,8 @@ extern int importDM();
|
|||
enum SESSION_STATE {
|
||||
SESSION_STATE_IDLE,
|
||||
SESSION_STATE_STARTED,
|
||||
SESSION_STATE_MODIFYING
|
||||
SESSION_STATE_MODIFYING,
|
||||
SESSION_STATE_APPLYING,
|
||||
};
|
||||
|
||||
struct dmapi_context {
|
||||
|
|
@ -193,6 +194,20 @@ int dmapi_session_start()
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dmapi_session_apply(void)
|
||||
{
|
||||
dmlog_debug("dmapi_session_apply");
|
||||
if (!dmapi_in_session()) {
|
||||
dmlog_error("not in session, skip apply");
|
||||
return 0;
|
||||
}
|
||||
|
||||
global_ctx.session_state = SESSION_STATE_APPLYING;
|
||||
dm_apply_do_apply();
|
||||
dmlog_debug("dmapi_session_apply end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dmapi_session_end(int action)
|
||||
{
|
||||
if (!dmapi_in_session()) {
|
||||
|
|
@ -200,18 +215,27 @@ int dmapi_session_end(int action)
|
|||
return 0;
|
||||
}
|
||||
|
||||
dmlog_debug("dmapi_session_end, action: %d, state: %d", action, global_ctx.session_state);
|
||||
|
||||
switch (action) {
|
||||
case TRANX_ROLLBACK:
|
||||
dmlog_debug("dmapi_session_end, rollback");
|
||||
dmapi_session_revert();
|
||||
break;
|
||||
case TRANX_COMMIT:
|
||||
dmlog_debug("dmapi_session_end, commit");
|
||||
if (global_ctx.session_state != SESSION_STATE_APPLYING) {
|
||||
dmlog_warn("dmapi_session_end, missing apply before commit");
|
||||
}
|
||||
dmapi_session_commit();
|
||||
break;
|
||||
case TRANX_COMMIT_AND_APPLY:
|
||||
dmlog_debug("dmapi_session_end, commit and apply");
|
||||
dmapi_session_commit();
|
||||
dm_apply_do_apply();
|
||||
break;
|
||||
case TRANX_NO_ACTION:
|
||||
dmlog_debug("dmapi_session_end, TRANX_NO_ACTION");
|
||||
break;
|
||||
default:
|
||||
dmlog_error("invalid action %d", action);
|
||||
|
|
@ -220,8 +244,6 @@ int dmapi_session_end(int action)
|
|||
|
||||
global_ctx.session_state = SESSION_STATE_IDLE;
|
||||
qjs_uci_global_cleanup();
|
||||
|
||||
dmlog_info("session ended");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -233,8 +255,7 @@ int dmapi_session_commit(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (global_ctx.session_state == SESSION_STATE_MODIFYING) {
|
||||
global_ctx.session_state = SESSION_STATE_STARTED;
|
||||
if (global_ctx.session_state == SESSION_STATE_MODIFYING || global_ctx.session_state == SESSION_STATE_APPLYING) {
|
||||
if (dbmgr_tranx_commit() == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
@ -255,12 +276,17 @@ int dmapi_session_revert(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (global_ctx.session_state == SESSION_STATE_MODIFYING) {
|
||||
if (global_ctx.session_state == SESSION_STATE_MODIFYING || global_ctx.session_state == SESSION_STATE_APPLYING) {
|
||||
dbmgr_tranx_revert();
|
||||
global_ctx.session_state = SESSION_STATE_STARTED;
|
||||
dm_apply_reset_changes();
|
||||
|
||||
// Clear instance buffers to ensure any instances added during the transaction
|
||||
// are removed from the buffer since they were rolled back from the database
|
||||
inode_buf_free_all();
|
||||
dm_refresh_linker_nodes(global_ctx.service_name);
|
||||
dmlog_info("instance buffers cleared after transaction rollback");
|
||||
}
|
||||
|
||||
dm_apply_reset_changes();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -390,6 +416,18 @@ int dmapi_param_get(const dm_node_t *node, char **value)
|
|||
asprintf(value, "%s", "true");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if there's a default value defined in JSON
|
||||
if (param->default_val) {
|
||||
*value = strdup(param->default_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// For boolean parameters without a default value, return "false"
|
||||
if (param->data_type == DM_DATA_BOOLEAN) {
|
||||
*value = strdup("false");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -589,7 +627,7 @@ int dmapi_param_set(const dm_node_t *node, const char *value)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!global_ctx.import_mode && !dm_node_is_writable(node->id)) {
|
||||
if (!global_ctx.import_mode && !dm_node_is_writable(node->id) && (global_ctx.session_state != SESSION_STATE_APPLYING)) {
|
||||
dmlog_error("Not able to set readonly parameter %s.", dm_node_str(node));
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -640,7 +678,7 @@ int dmapi_param_set(const dm_node_t *node, const char *value)
|
|||
}
|
||||
|
||||
// db
|
||||
if (global_ctx.session_state != SESSION_STATE_MODIFYING) {
|
||||
if (global_ctx.session_state != SESSION_STATE_MODIFYING && global_ctx.session_state != SESSION_STATE_APPLYING) {
|
||||
dbmgr_tranx_begin();
|
||||
global_ctx.session_state = SESSION_STATE_MODIFYING;
|
||||
}
|
||||
|
|
@ -850,12 +888,14 @@ int dmapi_object_add(dm_node_t *node)
|
|||
return -1;
|
||||
}
|
||||
|
||||
start_session_on_fly();
|
||||
|
||||
if (!dmapi_in_session()) {
|
||||
dmlog_error("not in session");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (global_ctx.session_state != SESSION_STATE_MODIFYING) {
|
||||
if (global_ctx.session_state != SESSION_STATE_MODIFYING && global_ctx.session_state != SESSION_STATE_APPLYING) {
|
||||
dbmgr_tranx_begin();
|
||||
global_ctx.session_state = SESSION_STATE_MODIFYING;
|
||||
}
|
||||
|
|
@ -1100,7 +1140,7 @@ int dmapi_object_del(const dm_node_t *node)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (global_ctx.session_state != SESSION_STATE_MODIFYING) {
|
||||
if (global_ctx.session_state != SESSION_STATE_MODIFYING && global_ctx.session_state != SESSION_STATE_APPLYING) {
|
||||
dbmgr_tranx_begin();
|
||||
global_ctx.session_state = SESSION_STATE_MODIFYING;
|
||||
}
|
||||
|
|
@ -1379,7 +1419,12 @@ dm_nodelist_h dm_nodelist_find(const dm_node_t *node, const char *keys, int only
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!keys) {
|
||||
// Check if this is a multi-index node with incomplete indices
|
||||
// If so, bypass inode buffer and go directly to database
|
||||
int expected_cnt = dm_node_index_cnt(node->id);
|
||||
int has_incomplete_indices = (expected_cnt > 1 && node->cnt < expected_cnt);
|
||||
|
||||
if (!keys && !has_incomplete_indices) {
|
||||
// reuse the db instances in buffer.
|
||||
int retry;
|
||||
struct inode_entry *entry = inode_buf_find(node, &retry);
|
||||
|
|
@ -1402,6 +1447,7 @@ dm_nodelist_h dm_nodelist_find(const dm_node_t *node, const char *keys, int only
|
|||
}
|
||||
}
|
||||
|
||||
// Either keys specified, incomplete indices, or inode buffer failed - use database directly
|
||||
get_indexes(node, list, keys, only_db);
|
||||
return (dm_nodelist_h)list;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ int dmapi_session_start();
|
|||
*/
|
||||
int dmapi_session_end(int action);
|
||||
|
||||
/** Apply changes in a session.
|
||||
* @pre dmapi_session_start should be called successfully
|
||||
* @return 0 in case of success, or a nonzero value in case of error
|
||||
*/
|
||||
int dmapi_session_apply(void);
|
||||
|
||||
/** Commits a transaction in a session.
|
||||
* @pre dmapi_session_start should be called successfully
|
||||
* and have modified parameters or objects by calling
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@ static void reset_confidentials()
|
|||
return;
|
||||
|
||||
int i;
|
||||
dbmgr_tranx_begin();
|
||||
// dbmgr_tranx_begin();
|
||||
int cnt = dm_list_cnt(changed_node_list);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct node_change *change = (struct node_change *)dm_list_get(changed_node_list, i);
|
||||
|
|
@ -672,7 +672,7 @@ static void reset_confidentials()
|
|||
}
|
||||
}
|
||||
|
||||
dbmgr_tranx_commit();
|
||||
// dbmgr_tranx_commit();
|
||||
}
|
||||
|
||||
int dm_apply_reset(void)
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ static int process_linker_node(struct uci_context *ctx, struct uci_package *pkg,
|
|||
|
||||
// Check if this parameter is a linker node
|
||||
if (!is_linker_node(node->id)) {
|
||||
dmlog_error("Not a linker parameter %s", dm_node_str(node));
|
||||
return 0; // Not a linker parameter
|
||||
}
|
||||
|
||||
|
|
@ -144,6 +145,7 @@ static int process_linker_node(struct uci_context *ctx, struct uci_package *pkg,
|
|||
size_t len_linker = strlen(parent_path) + strlen(key_name) + strlen(key_value) + 6; // extra for [==].
|
||||
char *linker_string = malloc(len_linker);
|
||||
if (!linker_string) {
|
||||
dmlog_error("Failed to allocate memory for linker string");
|
||||
free(key_value);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -164,6 +166,7 @@ static int process_linker_node(struct uci_context *ctx, struct uci_package *pkg,
|
|||
char *hash_value = calculate_hash(current_path);
|
||||
|
||||
if (!hash_path || !hash_value) {
|
||||
dmlog_error("Failed to calculate hashes for %s", linker_string);
|
||||
free(linker_string);
|
||||
free(key_value);
|
||||
free(hash_path);
|
||||
|
|
@ -257,10 +260,12 @@ static int process_all_linker_nodes(struct uci_context *ctx, struct uci_package
|
|||
dm_node_t parent_node = {0};
|
||||
parent_node.id = parent_id;
|
||||
|
||||
dm_nodelist_h list = dm_nodelist_get_db(&parent_node);
|
||||
// For multi-index nodes, bypass inode buffer and go directly to DB
|
||||
dm_nodelist_h list = dm_nodelist_find(&parent_node, NULL, 1);
|
||||
if (list != DM_INVALID_NODELIST) {
|
||||
const dm_node_t *instance_node;
|
||||
nodelist_for_each_node(instance_node, list) {
|
||||
// dmlog_debug("processing linker node %s", dm_node_str(instance_node));
|
||||
// Create the parameter node for this instance
|
||||
dm_node_t param_node = *instance_node;
|
||||
param_node.id = linker_id;
|
||||
|
|
@ -334,6 +339,7 @@ static int ensure_uci_sections(struct uci_context *ctx, struct uci_package *pkg)
|
|||
* Main API function to refresh linker nodes
|
||||
*/
|
||||
int dm_refresh_linker_nodes(const char *service_name) {
|
||||
dmlog_debug("dm_refresh_linker_nodes start");
|
||||
if (!service_name) {
|
||||
dmlog_error("Service name is required");
|
||||
return -1;
|
||||
|
|
|
|||
50
dm-framework/dm-api/src/include/qjs_uci_api.h
Executable file
50
dm-framework/dm-api/src/include/qjs_uci_api.h
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* QuickJS UCI helper – public API
|
||||
*
|
||||
* Provides initialisation helpers for the shared libuci context used by
|
||||
* qjs_uci_api.c as well as the QuickJS registration entry point.
|
||||
*/
|
||||
|
||||
#ifndef QJS_UCI_API_H
|
||||
#define QJS_UCI_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialise the shared libuci context.
|
||||
* Safe to call multiple times – subsequent calls are no-ops.
|
||||
* Returns 0 on success, -1 on failure.
|
||||
*/
|
||||
int qjs_uci_global_init(void);
|
||||
|
||||
/* Set the directory where libuci stores pending changes (may be NULL). */
|
||||
void qjs_uci_global_set_savedir(const char *save_dir);
|
||||
|
||||
/* Free the shared libuci context at shutdown (optional). */
|
||||
void qjs_uci_global_cleanup(void);
|
||||
|
||||
/* Register the _uci_call() C binding with QuickJS. */
|
||||
int qjs_uci_api_init(void);
|
||||
|
||||
#include <json-c/json.h>
|
||||
|
||||
/* Simple name/value helper used by dm_uci_* helpers */
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *value;
|
||||
} name_val_t;
|
||||
|
||||
int dm_uci_get(const char *uci_path, char **value);
|
||||
int dm_uci_set(const char *uci_path, const char *value);
|
||||
int dm_uci_add(const char *config, const char *type, const char *section_name, name_val_t *opt_values, int value_cnt);
|
||||
int dm_uci_del(const char *config, const char *section);
|
||||
int dm_uci_get_section_list(const char *config, const char *type, name_val_t *match, int match_cnt, struct json_object **res);
|
||||
int dm_uci_commit(const char *config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* QJS_UCI_API_H */
|
||||
|
|
@ -370,6 +370,7 @@ int qjs_call_get_handler(const dm_node_t *node, char **res)
|
|||
{
|
||||
JSValue val;
|
||||
int free_val = 1;
|
||||
|
||||
const struct dm_parameter *param = dm_node_get_parameter(node->id);
|
||||
if (param->js_val == NULL && !qjs_has_get_handler(node->id)) {
|
||||
dmlog_error("missing get handler for %s", dm_node_str(node));
|
||||
|
|
@ -383,7 +384,7 @@ int qjs_call_get_handler(const dm_node_t *node, char **res)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (param->js_val) {
|
||||
if (param->js_val) {;
|
||||
if (param->js_val[0] == '\0') {
|
||||
val = values[cnt - 1];
|
||||
free_val = 0; // no free
|
||||
|
|
|
|||
|
|
@ -237,12 +237,12 @@ static JSValue _set_param_value(JSContext *ctx, JSValueConst this_val,
|
|||
|
||||
if (value != NULL) {
|
||||
if (only_db) {
|
||||
dbmgr_tranx_begin();
|
||||
// dbmgr_tranx_begin();
|
||||
ret = dbmgr_set(&node, value);
|
||||
if (dm_node_index_cnt(node.id) > 0) {
|
||||
ret |= inode_buf_update_param_value(&node, value);
|
||||
}
|
||||
dbmgr_tranx_commit();
|
||||
// dbmgr_tranx_commit();
|
||||
} else {
|
||||
dmapi_param_set(&node, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ static JSValue _uci_call(JSContext *ctx, JSValueConst this_val,
|
|||
|
||||
/* Attempt to extract a few common parameters for logging */
|
||||
const char *log_cfg = NULL, *log_sec = NULL, *log_opt = NULL, *log_type = NULL;
|
||||
if (args_obj != JS_UNDEFINED) {
|
||||
if (!JS_IsUndefined(args_obj)) {
|
||||
log_cfg = js_obj_get_str(ctx, args_obj, "config");
|
||||
log_sec = js_obj_get_str(ctx, args_obj, "section");
|
||||
log_opt = js_obj_get_str(ctx, args_obj, "option");
|
||||
|
|
@ -316,7 +316,7 @@ static JSValue _uci_call(JSContext *ctx, JSValueConst this_val,
|
|||
|
||||
/* Prepare JSON string of the full argument object for detailed debug */
|
||||
char *args_json = NULL;
|
||||
if (args_obj != JS_UNDEFINED) {
|
||||
if (!JS_IsUndefined(args_obj)) {
|
||||
JSValue arg_json_val = JS_JSONStringify(ctx, args_obj, JS_UNDEFINED, JS_UNDEFINED);
|
||||
if (!JS_IsException(arg_json_val)) {
|
||||
args_json = (char *)JS_ToCString(ctx, arg_json_val);
|
||||
|
|
@ -325,9 +325,9 @@ static JSValue _uci_call(JSContext *ctx, JSValueConst this_val,
|
|||
}
|
||||
|
||||
if (lvl && strcmp(lvl, "dbg") == 0) {
|
||||
dmlog_debug("_uci_call %s: cfg=%s sec=%s opt=%s type=%s args=%s", method,
|
||||
log_cfg ? log_cfg : "-", log_sec ? log_sec : "-", log_opt ? log_opt : "-",
|
||||
log_type ? log_type : "-", args_json ? args_json : "-");
|
||||
// dmlog_debug("_uci_call %s: cfg=%s sec=%s opt=%s type=%s args=%s", method,
|
||||
// log_cfg ? log_cfg : "-", log_sec ? log_sec : "-", log_opt ? log_opt : "-",
|
||||
// log_type ? log_type : "-", args_json ? args_json : "-");
|
||||
} else if (lvl) {
|
||||
if (args_json) {
|
||||
dmlog_info("_uci_call %s: cfg=%s sec=%s opt=%s type=%s args=%s", method,
|
||||
|
|
@ -362,7 +362,7 @@ static JSValue _uci_call(JSContext *ctx, JSValueConst this_val,
|
|||
struct uci_context *uci = g_uci_ctx;
|
||||
|
||||
/* Optional custom configuration directory */
|
||||
if (args_obj != JS_UNDEFINED) {
|
||||
if (!JS_IsUndefined(args_obj)) {
|
||||
confdir = js_obj_get_str(ctx, args_obj, "confdir"); /* explicit */
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +382,7 @@ static JSValue _uci_call(JSContext *ctx, JSValueConst this_val,
|
|||
}
|
||||
|
||||
/* Support absolute/relative file path in 'config' by splitting dir/name */
|
||||
config = (args_obj != JS_UNDEFINED) ? js_obj_get_str(ctx, args_obj, "config") : NULL;
|
||||
config = (!JS_IsUndefined(args_obj)) ? js_obj_get_str(ctx, args_obj, "config") : NULL;
|
||||
|
||||
char cfg_name_buf[128];
|
||||
if (config && strchr(config, '/')) {
|
||||
|
|
@ -639,8 +639,8 @@ cleanup:
|
|||
}
|
||||
|
||||
if (strcmp(lvl, "dbg") == 0) {
|
||||
dmlog_debug("_uci_call %s result ret=%d res=%s", method, ret,
|
||||
payload_str ? payload_str : "<none>");
|
||||
// dmlog_debug("_uci_call %s result ret=%d res=%s", method, ret,
|
||||
// payload_str ? payload_str : "<none>");
|
||||
} else {
|
||||
dmlog_info("_uci_call %s result ret=%d", method, ret);
|
||||
}
|
||||
|
|
@ -685,6 +685,7 @@ int qjs_uci_global_init()
|
|||
if (g_uci_savedir && uci_set_savedir(g_uci_ctx, g_uci_savedir) != UCI_OK) {
|
||||
uci_free_context(g_uci_ctx);
|
||||
g_uci_ctx = NULL;
|
||||
dmlog_error("qjs_uci_global_init: uci_set_savedir failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -695,7 +696,7 @@ int qjs_uci_global_init()
|
|||
|
||||
void qjs_uci_global_set_savedir(const char *save_dir)
|
||||
{
|
||||
dmlog_debug("qjs_uci_global_set_savedir: %s", save_dir);
|
||||
// dmlog_debug("qjs_uci_global_set_savedir: %s", save_dir);
|
||||
if (save_dir == g_uci_savedir && g_uci_ctx) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -812,9 +813,11 @@ static int parse_uci_path(const char *uci_path,
|
|||
|
||||
int dm_uci_get(const char *uci_path, char **value)
|
||||
{
|
||||
dmlog_debug("dm_uci_get: path=%s", uci_path ? uci_path : "-");
|
||||
if (!value)
|
||||
// dmlog_debug("dm_uci_get: path=%s", uci_path ? uci_path : "-");
|
||||
if (!value) {
|
||||
dmlog_error("dm_uci_get: value is NULL");
|
||||
return -1;
|
||||
}
|
||||
*value = NULL;
|
||||
|
||||
const char *confdir = NULL;
|
||||
|
|
@ -878,7 +881,7 @@ error_cleanup:
|
|||
free(config);
|
||||
free(section);
|
||||
free(option);
|
||||
dmlog_debug("dm_uci_get result ret=%d val=%s", (*value) ? 0 : -1, (*value) ? *value : "-");
|
||||
// dmlog_debug("dm_uci_get result ret=%d val=%s", (*value) ? 0 : -1, (*value) ? *value : "-");
|
||||
return (*value) ? 0 : -1;
|
||||
|
||||
error_restore:
|
||||
|
|
@ -949,32 +952,41 @@ error_restore:
|
|||
int dm_uci_del(const char *config, const char *section)
|
||||
{
|
||||
dmlog_info("dm_uci_del: cfg=%s sec=%s", config ? config : "-", section ? section : "-");
|
||||
if (!config || !section)
|
||||
if (!config || !section) {
|
||||
dmlog_error("dm_uci_del: config or section is NULL");
|
||||
return -1;
|
||||
if (ensure_global_ctx() != 0)
|
||||
}
|
||||
if (ensure_global_ctx() != 0) {
|
||||
dmlog_error("dm_uci_del: failed to ensure global context");
|
||||
return -1;
|
||||
}
|
||||
struct uci_context *uci = g_uci_ctx;
|
||||
|
||||
bool need_unload = false;
|
||||
struct uci_package *pkg = uci_lookup_package(uci, config);
|
||||
if (!pkg) {
|
||||
if (uci_load(uci, config, &pkg) != UCI_OK)
|
||||
if (uci_load(uci, config, &pkg) != UCI_OK) {
|
||||
dmlog_error("dm_uci_del: failed to load package %s", config);
|
||||
return -1;
|
||||
}
|
||||
need_unload = true;
|
||||
}
|
||||
|
||||
char path[256];
|
||||
snprintf(path, sizeof(path), "%s.%s", config, section);
|
||||
struct uci_ptr ptr = {};
|
||||
if (uci_lookup_ptr(uci, &ptr, path, true) != UCI_OK)
|
||||
if (uci_lookup_ptr(uci, &ptr, path, true) != UCI_OK) {
|
||||
dmlog_error("dm_uci_del: failed to lookup ptr %s", path);
|
||||
goto unload_pkg;
|
||||
}
|
||||
|
||||
if (uci_delete(uci, &ptr) != UCI_OK)
|
||||
if (uci_delete(uci, &ptr) != UCI_OK) {
|
||||
dmlog_error("dm_uci_del: failed to delete %s", path);
|
||||
goto unload_pkg;
|
||||
}
|
||||
|
||||
if (need_unload && pkg)
|
||||
uci_unload(uci, pkg);
|
||||
dmlog_info("dm_uci_del result ret=0");
|
||||
return 0;
|
||||
|
||||
unload_pkg:
|
||||
|
|
@ -987,23 +999,30 @@ unload_pkg:
|
|||
int dm_uci_commit(const char *config)
|
||||
{
|
||||
dmlog_info("dm_uci_commit: cfg=%s", config ? config : "-");
|
||||
if (!config)
|
||||
if (!config) {
|
||||
dmlog_error("dm_uci_commit: config is NULL");
|
||||
return -1;
|
||||
if (ensure_global_ctx() != 0)
|
||||
}
|
||||
|
||||
if (ensure_global_ctx() != 0){
|
||||
dmlog_error("dm_uci_commit: failed to ensure global context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uci_context *uci = g_uci_ctx;
|
||||
bool need_unload = false;
|
||||
struct uci_package *pkg = uci_lookup_package(uci, config);
|
||||
if (!pkg) {
|
||||
if (uci_load(uci, config, &pkg) != UCI_OK)
|
||||
if (uci_load(uci, config, &pkg) != UCI_OK) {
|
||||
dmlog_error("dm_uci_commit: failed to load package %s", config);
|
||||
return -1;
|
||||
}
|
||||
|
||||
need_unload = true;
|
||||
}
|
||||
int ret = (uci_commit(uci, &pkg, false) == UCI_OK) ? 0 : -1;
|
||||
if (need_unload && pkg)
|
||||
uci_unload(uci, pkg);
|
||||
dmlog_info("dm_uci_commit result ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1054,7 +1073,6 @@ int dm_uci_add(const char *config, const char *type, const char *section_name, n
|
|||
uci_save(uci, pkg);
|
||||
if (need_unload && pkg)
|
||||
uci_unload(uci, pkg);
|
||||
dmlog_info("dm_uci_add result ret=0 section=%s", final_name);
|
||||
return 0;
|
||||
|
||||
unload_pkg:
|
||||
|
|
@ -1136,7 +1154,7 @@ static struct json_object *create_json_values_object_c(struct uci_section *s)
|
|||
|
||||
int dm_uci_get_section_list(const char *config, const char *type, name_val_t *match, int match_cnt, struct json_object **res)
|
||||
{
|
||||
dmlog_debug("dm_uci_get_section_list: cfg=%s type=%s", config ? config : "-", type ? type : "-");
|
||||
// dmlog_debug("dm_uci_get_section_list: cfg=%s type=%s", config ? config : "-", type ? type : "-");
|
||||
if (!config || !res)
|
||||
return -1;
|
||||
*res = NULL;
|
||||
|
|
@ -1168,6 +1186,6 @@ int dm_uci_get_section_list(const char *config, const char *type, name_val_t *ma
|
|||
if (need_unload && pkg)
|
||||
uci_unload(uci, pkg);
|
||||
*res = root;
|
||||
dmlog_debug("dm_uci_get_section_list result ret=0");
|
||||
// dmlog_debug("dm_uci_get_section_list result ret=0");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue