From fd2268e105fc89743f7723ba0ce285551e3ac918 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 30 Jul 2026 13:30:01 +0000 Subject: [PATCH 01/17] Untagged VLAN: unified interface type framework Consolidates vlan-manager PRs #39 and #40 into a single implementation. Changes: - Add untagged_vlan_type_t enum with all kernel macvlan modes (private, vepa, bridge, passthru, source), brctl simple bridge, 802.1Q tag-0, and TAGGED_VLAN marker for conventional tagged VLANs - Add UnTaggedVlanType field to DML_VLAN and DML_ETHERNET structs - PSM key dmsb.vlanmanager.%d.untaggedvlantype for non-HUB4 platforms; HUB4 regional flow always uses UNTAGGED_SIMPLE_BRIDGE (brctl) - Set UnTaggedVlanType = TAGGED_VLAN(7) at init when VLANId > 0, so the enum drives the Enable/Disable if/else instead of VLANId > 0 - EthLink_CreateUnTaggedInterface: switch on type for create/delete, covering bridge (brctl), all five macvlan modes, and vlan tag-0 - EthLink_DeleteUnTaggedInterface: symmetric type-aware teardown - Vlan_SetEthLink: always sync type to EthLink entry before enable - Extract Vlan_WaitForInterfaceUp() common helper shared by both tagged and untagged paths in Vlan_Enable - Add status check loop for untagged path (mirrors tagged path) - UntaggedVlanType DM param: read-only, uint32/mapped string - Add .gitignore to suppress autoconf/libtool generated files Merges: https://github.com/rdkcentral/vlan-manager/pull/39 https://github.com/rdkcentral/vlan-manager/pull/40 --- .gitignore | 28 +++ config/RdkVlanManager.xml | 6 + source/TR-181/include/ethernet_apis.h | 27 +++ source/TR-181/include/vlan_apis.h | 3 + .../TR-181/middle_layer_src/ethernet_apis.c | 161 +++++++++++++----- source/TR-181/middle_layer_src/vlan_apis.c | 73 +++++--- source/TR-181/middle_layer_src/vlan_dml.c | 5 + .../TR-181/middle_layer_src/vlan_internal.c | 22 +++ 8 files changed, 252 insertions(+), 73 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aaadaeb --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# autoconf / automake generated +aclocal.m4 +autom4te.cache/ +configure +Makefile.in +source/Makefile.in +source/RdkVlanManager/Makefile.in +source/TR-181/Makefile.in +source/TR-181/middle_layer_src/Makefile.in +cfg/compile +cfg/config.guess +cfg/config.h.in +cfg/config.sub +cfg/depcomp +cfg/install-sh +cfg/libtool.m4 +cfg/ltmain.sh +cfg/ltoptions.m4 +cfg/ltsugar.m4 +cfg/ltversion.m4 +cfg/lt~obsolete.m4 +cfg/missing + +# dm_pack generated +source/RdkVlanManager/dm_pack_datamodel.c + +# misc +.lastlogin diff --git a/config/RdkVlanManager.xml b/config/RdkVlanManager.xml index 1cfda42..3f47b4d 100644 --- a/config/RdkVlanManager.xml +++ b/config/RdkVlanManager.xml @@ -203,6 +203,12 @@ uint32 true + + UntaggedVlanType + unsignedInt: Bridge(0),MacvlanPrivate(1),MacvlanVepa(2),MacvlanBridge(3),MacvlanPassthru(4),MacvlanSource(5),VlanTag0(6),Tagged(7) + uint32/mapped + false + X_RDK_BaseInterface string(64) diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index cfd56b8..5e3d8fa 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -87,6 +87,32 @@ typedef enum { ETH_IF_ERROR }ethernet_link_status_e; +/* + * Untagged VLAN interface type. + * Selects how VlanManager realises an untagged (VLANID <= 0) virtual + * interface on top of the base interface. + * + * Values map to the DM parameter UntaggedVlanType (uint32, mapped to string): + * 0=Bridge, 1=MacvlanPrivate, 2=MacvlanVepa, 3=MacvlanBridge, + * 4=MacvlanPassthru, 5=MacvlanSource, 6=VlanTag0 + * + * MACVLAN modes correspond exactly to kernel ip-link(8) macvlan modes. + * UNTAGGED_SIMPLE_BRIDGE is the default (used when not otherwise configured). + */ +typedef enum +_UNTAGGED_VLAN_TYPE +{ + UNTAGGED_SIMPLE_BRIDGE = 0, /* Default: Linux bridge via brctl */ + UNTAGGED_MACVLAN_PRIVATE = 1, /* macvlan mode private */ + UNTAGGED_MACVLAN_VEPA = 2, /* macvlan mode vepa */ + UNTAGGED_MACVLAN_BRIDGE = 3, /* macvlan mode bridge */ + UNTAGGED_MACVLAN_PASSTHRU = 4, /* macvlan mode passthru */ + UNTAGGED_MACVLAN_SOURCE = 5, /* macvlan mode source */ + UNTAGGED_VLAN_TAG_0 = 6, /* 802.1Q VLAN tag id 0 */ + TAGGED_VLAN = 7 /* Tagged VLAN (VLANID > 0). DML path only. */ +} +untagged_vlan_type_t; + typedef struct _COSA_DML_MARKING { @@ -113,6 +139,7 @@ _DML_ETHERNET CHAR MACAddress[18]; LONG MACAddrOffSet; // Changed to LONG to support negative offsets BOOLEAN PriorityTagging; + untagged_vlan_type_t UnTaggedVlanType; // Untagged VLAN realisation type (bridge/macvlan/tag0) UINT NumberofMarkingEntries; PCOSA_DML_MARKING pstDataModelMarking; } diff --git a/source/TR-181/include/vlan_apis.h b/source/TR-181/include/vlan_apis.h index 9753c1b..9599b83 100644 --- a/source/TR-181/include/vlan_apis.h +++ b/source/TR-181/include/vlan_apis.h @@ -50,6 +50,7 @@ #define PSM_VLANMANAGER_LOWERLAYERS "dmsb.vlanmanager.%d.lowerlayers" #define PSM_VLANMANAGER_VLANID "dmsb.vlanmanager.%d.vlanid" #define PSM_VLANMANAGER_TPID "dmsb.vlanmanager.%d.tpid" +#define PSM_VLANMANAGER_UNTAGGEDVLANTYPE "dmsb.vlanmanager.%d.untaggedvlantype" #define PSM_VLANMANAGER_BASEINTERFACE "dmsb.vlanmanager.%d.baseinterface" #define PSM_VLANMANAGER_PATH "dmsb.vlanmanager.%d.path" @@ -88,6 +89,7 @@ _DML_VLAN CHAR BaseInterface[64]; INT VLANId; UINT TPId; + INT UnTaggedVlanType; /* untagged_vlan_type_t: how an untagged (VLANID<=0) iface is created */ CHAR Path[1024]; } DML_VLAN, *PDML_VLAN; @@ -96,6 +98,7 @@ static inline void DML_VLAN_INIT(PDML_VLAN pVlan) { pVlan->Enable = FALSE; pVlan->Status = VLAN_IF_DOWN; + pVlan->UnTaggedVlanType = 0; /* UNTAGGED_SIMPLE_BRIDGE – default */ } /************************************* diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index 0ec359c..e67f03f 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -871,48 +871,94 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) */ EthLink_CreateBridgeInterface(TRUE); #else - // Create untagged interface using MACVLAN for truly untagged traffic - CcspTraceInfo(("%s-%d: Creating MACVLAN untagged interface %s on base interface %s with MAC offset %ld\n", - __FUNCTION__, __LINE__, pEntry->Name, pEntry->BaseInterface, pEntry->MACAddrOffSet)); - - // Check if interface already exists (as MACVLAN or bridge) and delete it - CcspTraceInfo(("%s-%d: Checking if interface %s already exists\n", __FUNCTION__, __LINE__, pEntry->Name)); - v_secure_system("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", - pEntry->Name, pEntry->Name, pEntry->Name); - - // Get MAC address with offset applied - if (ANSC_STATUS_SUCCESS != EthLink_GetMacAddr(pEntry)) - { - CcspTraceError(("%s-%d: Failed to get MAC address, creating MACVLAN without custom MAC\n", __FUNCTION__, __LINE__)); - // Create MACVLAN without setting custom MAC - kernel will assign one - v_secure_system("ip link add link %s name %s type macvlan mode private", - pEntry->BaseInterface, pEntry->Name); - } - else + /* + * Consolidated untagged (VLANID <= 0) interface creation. The realisation + * method is selected by pEntry->UnTaggedVlanType, which is handed over from + * the VLAN entry (Vlan_SetEthLink) or loaded from the EthLink defaults. + */ + CcspTraceInfo(("%s-%d: Creating untagged interface %s on base interface %s (type=%d, MAC offset=%ld)\n", + __FUNCTION__, __LINE__, pEntry->Name, pEntry->BaseInterface, + pEntry->UnTaggedVlanType, pEntry->MACAddrOffSet)); + + switch (pEntry->UnTaggedVlanType) { - CcspTraceInfo(("%s-%d: Using MAC address: %s (offset: %ld)\n", - __FUNCTION__, __LINE__, pEntry->MACAddress, pEntry->MACAddrOffSet)); - - // Create MACVLAN interface with custom MAC - v_secure_system("ip link add link %s name %s address %s type macvlan mode private", - pEntry->BaseInterface, pEntry->Name, pEntry->MACAddress); - } - - // Set the allmulticast and multicast on for MACVLAN interface - CcspTraceInfo(("%s-%d: Setting allmulticast amd multicast on for MACVLAN interface %s\n", - __FUNCTION__, __LINE__, pEntry->Name)); - v_secure_system("ip link set %s allmulticast on", pEntry->Name); - v_secure_system("ip link set %s multicast on", pEntry->Name); + case UNTAGGED_VLAN_TAG_0: + { + /* 802.1Q VLAN with tag id 0 (priority/untagged frames). */ + v_secure_system("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", + pEntry->Name, pEntry->Name, pEntry->Name); + v_secure_system("ip link add link %s name %s type vlan id 0", + pEntry->BaseInterface, pEntry->Name); + v_secure_system("ip link set %s up", pEntry->Name); + CcspTraceInfo(("%s-%d: Successfully created VLAN tag-0 untagged interface %s\n", + __FUNCTION__, __LINE__, pEntry->Name)); + break; + } + case UNTAGGED_MACVLAN_PRIVATE: + case UNTAGGED_MACVLAN_VEPA: + case UNTAGGED_MACVLAN_BRIDGE: + case UNTAGGED_MACVLAN_PASSTHRU: + case UNTAGGED_MACVLAN_SOURCE: + { + /* MACVLAN in the requested kernel mode (ip-link(8) macvlan). */ + const char *macvlanMode; + switch (pEntry->UnTaggedVlanType) + { + case UNTAGGED_MACVLAN_VEPA: macvlanMode = "vepa"; break; + case UNTAGGED_MACVLAN_BRIDGE: macvlanMode = "bridge"; break; + case UNTAGGED_MACVLAN_PASSTHRU: macvlanMode = "passthru"; break; + case UNTAGGED_MACVLAN_SOURCE: macvlanMode = "source"; break; + default: macvlanMode = "private"; break; + } - // Set MTU to default 1500 - CcspTraceInfo(("%s-%d: Setting MTU to 1500 for MACVLAN interface %s\n", - __FUNCTION__, __LINE__, pEntry->Name)); - v_secure_system("ip link set %s mtu 1500", pEntry->Name); - - v_secure_system("ip link set %s up", pEntry->Name); - - CcspTraceInfo(("%s-%d: Successfully created MACVLAN untagged interface %s\n", - __FUNCTION__, __LINE__, pEntry->Name)); + /* Delete any pre-existing interface with this name. */ + v_secure_system("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", + pEntry->Name, pEntry->Name, pEntry->Name); + + /* Get MAC address with offset applied. */ + if (ANSC_STATUS_SUCCESS != EthLink_GetMacAddr(pEntry)) + { + CcspTraceError(("%s-%d: Failed to get MAC address, creating MACVLAN(%s) without custom MAC\n", + __FUNCTION__, __LINE__, macvlanMode)); + v_secure_system("ip link add link %s name %s type macvlan mode %s", + pEntry->BaseInterface, pEntry->Name, macvlanMode); + } + else + { + CcspTraceInfo(("%s-%d: Using MAC address: %s (offset: %ld) mode %s\n", + __FUNCTION__, __LINE__, pEntry->MACAddress, pEntry->MACAddrOffSet, macvlanMode)); + v_secure_system("ip link add link %s name %s address %s type macvlan mode %s", + pEntry->BaseInterface, pEntry->Name, pEntry->MACAddress, macvlanMode); + } + + v_secure_system("ip link set %s allmulticast on", pEntry->Name); + v_secure_system("ip link set %s multicast on", pEntry->Name); + v_secure_system("ip link set %s mtu 1500", pEntry->Name); + v_secure_system("ip link set %s up", pEntry->Name); + + CcspTraceInfo(("%s-%d: Successfully created MACVLAN(%s) untagged interface %s\n", + __FUNCTION__, __LINE__, macvlanMode, pEntry->Name)); + break; + } + case UNTAGGED_SIMPLE_BRIDGE: + default: + { + /* Default: Linux bridge via brctl. The base interface is enslaved + * to a bridge that carries untagged traffic. */ + v_secure_system("ip link show %s > /dev/null 2>&1 || brctl addbr %s", + pEntry->Name, pEntry->Name); + if ((strcmp(pEntry->BaseInterface, pEntry->Name) != 0) && + (pEntry->BaseInterface[0] != '\0')) + { + v_secure_system("brctl addif %s %s 2>/dev/null", + pEntry->Name, pEntry->BaseInterface); + } + v_secure_system("ifconfig %s up", pEntry->Name); + CcspTraceInfo(("%s-%d: Successfully created bridge untagged interface %s\n", + __FUNCTION__, __LINE__, pEntry->Name)); + break; + } + } #endif //Free VlanCfg skb_config memory @@ -936,12 +982,35 @@ static ANSC_STATUS EthLink_DeleteUnTaggedInterface(PDML_ETHERNET pEntry) return ANSC_STATUS_FAILURE; } - CcspTraceInfo(("%s-%d: Deleting untagged VLAN interface %s\n", - __FUNCTION__, __LINE__, pEntry->Name)); - - v_secure_system("ip link set %s down", pEntry->Name); - v_secure_system("ip link delete %s", pEntry->Name); - + CcspTraceInfo(("%s-%d: Deleting untagged VLAN interface %s (type=%d)\n", + __FUNCTION__, __LINE__, pEntry->Name, pEntry->UnTaggedVlanType)); + + switch (pEntry->UnTaggedVlanType) + { + case UNTAGGED_SIMPLE_BRIDGE: + default: + /* Simple Linux bridge teardown via brctl. */ + if ((strcmp(pEntry->BaseInterface, pEntry->Name) != 0) && + (pEntry->BaseInterface[0] != '\0')) + { + v_secure_system("brctl delif %s %s", pEntry->Name, pEntry->BaseInterface); + } + v_secure_system("ifconfig %s down", pEntry->Name); + v_secure_system("brctl delbr %s", pEntry->Name); + break; + + case UNTAGGED_VLAN_TAG_0: + case UNTAGGED_MACVLAN_PRIVATE: + case UNTAGGED_MACVLAN_VEPA: + case UNTAGGED_MACVLAN_BRIDGE: + case UNTAGGED_MACVLAN_PASSTHRU: + case UNTAGGED_MACVLAN_SOURCE: + /* macvlan and vlan tag-0 devices are removed with ip link. */ + v_secure_system("ip link set %s down", pEntry->Name); + v_secure_system("ip link delete %s", pEntry->Name); + break; + } + CcspTraceInfo(("%s-%d: Successfully deleted untagged VLAN interface %s\n", __FUNCTION__, __LINE__, pEntry->Name)); diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 54e0c0a..147d78c 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -242,6 +242,13 @@ static ANSC_STATUS Vlan_SetEthLink(PDML_VLAN pEntry, BOOL enable, BOOL PriTag) return ANSC_STATUS_FAILURE; } + /* Sync VLAN type to EthLink. TAGGED_VLAN(7) is harmless — EthLink_Enable + * skips untagged creation when PriorityTagging=TRUE. + * TODO: UNTAGGED_VLAN_TAG_0 may need PriorityTagging=TRUE in future. */ + ((PDML_ETHERNET)pNewEntry)->UnTaggedVlanType = (untagged_vlan_type_t)pEntry->UnTaggedVlanType; + CcspTraceInfo(("%s-%d: VLAN type=%d synced to EthLink for %s\n", + __FUNCTION__, __LINE__, pEntry->UnTaggedVlanType, pEntry->Name)); + //Set PriorityTagging. if (enable == TRUE) { @@ -371,7 +378,7 @@ void * Vlan_Disable(void *Arg) } //Delete Created Tagged Vlan Interface - if (pEntry->VLANId > 0) + if (pEntry->UnTaggedVlanType == TAGGED_VLAN) { #ifdef FEATURE_MAPT char wan_ifname[BUFLEN_64] = {0}; @@ -608,11 +615,43 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) } #endif +/* Poll interface status (up to 10 retries, 2 s apart) and notify WanManager. */ +static void Vlan_WaitForInterfaceUp(PDML_VLAN pEntry, const char *ifType) +{ + vlan_link_status_e status = VLAN_IF_DOWN; + INT iIterator = 0; + long uptime = 0; + + while (iIterator < 10) + { + if (ANSC_STATUS_FAILURE == Vlan_GetTaggedVlanInterfaceStatus(pEntry->Name, &status)) + { + CcspTraceError(("%s-%d: Failed to get %s Vlan Interface=%s Status\n", + __FUNCTION__, __LINE__, ifType, pEntry->Name)); + } + + if (VLAN_IF_UP == status) + { + EthLink_SendVirtualIfaceVlanStatus(pEntry->Path, "Up"); + CcspTraceInfo(("%s-%d: Successfully updated Vlan Status (%s) for Interface(%s)\n", + __FUNCTION__, __LINE__, ifType, pEntry->Name)); + break; + } + + iIterator++; + sleep(2); + CcspTraceInfo(("%s-%d: %s Interface Status(%d), retry-count=%d\n", + __FUNCTION__, __LINE__, ifType, status, iIterator)); + } + + get_uptime(&uptime); + pEntry->LastChange = uptime; +} + void * Vlan_Enable(void *Arg) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; - vlan_link_status_e status; - INT iIterator = 0; + vlan_link_status_e status = VLAN_IF_NOTPRESENT; /* safe default: skips deletion on ioctl failure */ PDML_VLAN pEntry = (PDML_VLAN)Arg; if ( NULL == pEntry ) @@ -624,8 +663,8 @@ void * Vlan_Enable(void *Arg) pthread_detach(pthread_self()); pthread_mutex_lock(&vlan_access_mutex); - //Create Vlan Tagged Interface - if(pEntry->VLANId > 0) { + //Create Vlan Tagged or UnTagged Interface, selected by UnTaggedVlanType + if (pEntry->UnTaggedVlanType == TAGGED_VLAN) { if (Vlan_SetEthLink(pEntry, TRUE, TRUE) == ANSC_STATUS_FAILURE) { CcspTraceError(("%s-%d: Failed to Enable EthLink\n", __FUNCTION__, __LINE__)); @@ -660,28 +699,7 @@ void * Vlan_Enable(void *Arg) CcspTraceError(("[%s][%d]Failed to create VLAN Tagged interface \n", __FUNCTION__, __LINE__)); } - //Get status of VLAN link - while(iIterator < 10) - { - if (ANSC_STATUS_FAILURE == Vlan_GetTaggedVlanInterfaceStatus(pEntry->Name, &status)) - { - CcspTraceError(("%s-%d: Failed to get Tagged Vlan Interface=%s Status \n", __FUNCTION__, __LINE__, pEntry->Name)); - } - - if (VLAN_IF_UP == status) - { - EthLink_SendVirtualIfaceVlanStatus(pEntry->Path, "Up"); - CcspTraceInfo(("%s-%d: Successfully Updated Vlan Status to WanManager for Interface(%s) \n", __FUNCTION__, __LINE__, pEntry->Name)); - break; - } - - iIterator++; - sleep(2); - CcspTraceInfo(("%s-%d: Interface Status(%d), retry-count=%d \n", __FUNCTION__, __LINE__, status, iIterator)); - } - long uptime = 0; - get_uptime(&uptime); - pEntry->LastChange = uptime; + Vlan_WaitForInterfaceUp(pEntry, "Tagged"); } else if (pEntry->VLANId == -1) { @@ -724,6 +742,7 @@ void * Vlan_Enable(void *Arg) { CcspTraceError(("%s-%d: Failed to Enable EthLink\n", __FUNCTION__, __LINE__)); } + Vlan_WaitForInterfaceUp(pEntry, "UnTagged"); } pEntry->Status = VLAN_IF_UP; diff --git a/source/TR-181/middle_layer_src/vlan_dml.c b/source/TR-181/middle_layer_src/vlan_dml.c index 49c422d..db65d64 100644 --- a/source/TR-181/middle_layer_src/vlan_dml.c +++ b/source/TR-181/middle_layer_src/vlan_dml.c @@ -360,6 +360,11 @@ Vlan_GetParamUlongValue *puLong = p_Vlan->TPId; return TRUE; } + if (strcmp(ParamName, "UntaggedVlanType") == 0) + { + *puLong = p_Vlan->UnTaggedVlanType; + return TRUE; + } /* CcspTraceWarning(("Unsupported parameter '%s'\n", ParamName)); */ return FALSE; } diff --git a/source/TR-181/middle_layer_src/vlan_internal.c b/source/TR-181/middle_layer_src/vlan_internal.c index 9d9abb9..716590e 100644 --- a/source/TR-181/middle_layer_src/vlan_internal.c +++ b/source/TR-181/middle_layer_src/vlan_internal.c @@ -43,11 +43,14 @@ /*TODO *Need to be Reviewed after Unification is finalised. + * Update: The unification is finalised, however to remove the below code, the respective platform have to use VLAN dicovery or boottime VLAN configuration based. on the region to replace this dynamic country based VLAN configuration. */ #define PSM_VLANMANAGER_CFG_COUNT "dmsb.vlanmanager.cfg.count" #define PSM_VLANMANAGER_CFG_REGION "dmsb.vlanmanager.cfg.%d.region" #define PSM_VLANMANAGER_CFG_VLANID "dmsb.vlanmanager.cfg.%d.vlanid" #define PSM_VLANMANAGER_CFG_TPID "dmsb.vlanmanager.cfg.%d.tpid" +/* Note: UntaggedVlanType is not loaded per-cfg for the HUB4 regional flow; + * that flow always uses UNTAGGED_SIMPLE_BRIDGE (brctl) for untagged VLANs. */ extern char g_Subsystem[32]; extern ANSC_HANDLE bus_handle; @@ -278,6 +281,10 @@ static ANSC_STATUS VlanTerminationInitialize( ANSC_HANDLE hThisObject) pVlan[nIndex].TPId = atoi(acPSMValue) ; } + /* Set UntaggedVlanType: tagged VLANs use TAGGED_VLAN (7); untagged VLANs + * default to UNTAGGED_SIMPLE_BRIDGE (0) for the HUB4 regional flow. */ + pVlan[nIndex].UnTaggedVlanType = (pVlan[nIndex].VLANId > 0) ? 7 /* TAGGED_VLAN */ : 0 /* UNTAGGED_SIMPLE_BRIDGE */; + /*TODO: *Need to be Removed Path From PSM Once RBUS Support Available in VlanManager and WanManager. */ @@ -377,6 +384,21 @@ static ANSC_STATUS VlanTerminationInitialize( ANSC_HANDLE hThisObject) pVlan[nIndex].TPId = atoi(acPSMValue) ; } + /* Set UntaggedVlanType: tagged VLANs always use TAGGED_VLAN (7). + * For untagged VLANs load the type from PSM; falls back to 0 (UNTAGGED_SIMPLE_BRIDGE). */ + if (pVlan[nIndex].VLANId > 0) + { + pVlan[nIndex].UnTaggedVlanType = 7; /* TAGGED_VLAN */ + } + else + { + snprintf( acPSMQuery, sizeof( acPSMQuery ), PSM_VLANMANAGER_UNTAGGEDVLANTYPE, nIndex + 1 ); + if ( CCSP_SUCCESS == DmlVlanGetPSMRecordValue( acPSMQuery, acPSMValue ) ) + { + pVlan[nIndex].UnTaggedVlanType = atoi(acPSMValue) ; + } + } + /* get base interface from psm */ snprintf( acPSMQuery, sizeof( acPSMQuery ), PSM_VLANMANAGER_BASEINTERFACE, nIndex + 1 ); if ( CCSP_SUCCESS == DmlVlanGetPSMRecordValue( acPSMQuery, acPSMValue ) ) From 3dc2312fc2eef37b696f854a7ac1a222e0c08ac7 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 30 Jul 2026 13:54:22 +0000 Subject: [PATCH 02/17] Refactor command execution in EthLink_CreateUnTaggedInterface to use EXEC_CMD for improved logging and error handling --- .../TR-181/middle_layer_src/ethernet_apis.c | 125 +++++++++++++----- 1 file changed, 92 insertions(+), 33 deletions(-) diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index e67f03f..0a50b7d 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -96,6 +98,61 @@ extern ANSC_HANDLE g_MessageBusHandle; int sysevent_fd = -1; token_t sysevent_token; +/* + * EthLink_RunCmd - run a shell command, log it and all output (stdout+stderr), + * and return the exit code. Use EXEC_CMD() to auto-inject __FUNCTION__/__LINE__. + */ +static int EthLink_RunCmd(const char *caller, int line, const char *fmt, ...) +{ + char cmd[512] = {0}; + char redir[544] = {0}; + va_list args; + FILE *fp; + char buf[256] = {0}; + int status; + + va_start(args, fmt); + vsnprintf(cmd, sizeof(cmd) - 1, fmt, args); + va_end(args); + + CcspTraceInfo(("%s-%d: exec: %s\n", caller, line, cmd)); + + snprintf(redir, sizeof(redir) - 1, "%s 2>&1", cmd); + fp = popen(redir, "r"); + if (fp == NULL) + { + CcspTraceError(("%s-%d: popen failed for: %s\n", caller, line, cmd)); + return -1; + } + + while (fgets(buf, sizeof(buf), fp) != NULL) + { + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + if (buf[0] != '\0') + CcspTraceInfo(("%s-%d: [output] %s\n", caller, line, buf)); + } + + status = pclose(fp); + if (status == -1) + { + CcspTraceError(("%s-%d: pclose failed: %s\n", caller, line, cmd)); + return -1; + } + if (WIFEXITED(status)) + { + int rc = WEXITSTATUS(status); + if (rc != 0) + CcspTraceError(("%s-%d: failed (rc=%d): %s\n", caller, line, rc, cmd)); + return rc; + } + if (WIFSIGNALED(status)) + CcspTraceError(("%s-%d: killed by signal %d: %s\n", caller, line, WTERMSIG(status), cmd)); + return -1; +} +#define EXEC_CMD(fmt, ...) EthLink_RunCmd(__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + static ANSC_STATUS DmlEthSetParamValues(const char *pComponent, char *pBus, char *pParamName, char *pParamVal, enum dataType_e type, unsigned int bCommitFlag); static ANSC_STATUS DmlEthGetParamNames(char *pComponent, char *pBus, char *pParamName, char a2cReturnVal[][256], int *pReturnSize); static int EthLink_SyseventInit( void ); @@ -885,13 +942,12 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) case UNTAGGED_VLAN_TAG_0: { /* 802.1Q VLAN with tag id 0 (priority/untagged frames). */ - v_secure_system("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", - pEntry->Name, pEntry->Name, pEntry->Name); - v_secure_system("ip link add link %s name %s type vlan id 0", - pEntry->BaseInterface, pEntry->Name); - v_secure_system("ip link set %s up", pEntry->Name); - CcspTraceInfo(("%s-%d: Successfully created VLAN tag-0 untagged interface %s\n", - __FUNCTION__, __LINE__, pEntry->Name)); + EXEC_CMD("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", + pEntry->Name, pEntry->Name, pEntry->Name); + EXEC_CMD("ip link add link %s name %s type vlan id 0", + pEntry->BaseInterface, pEntry->Name); + EXEC_CMD("ip link set %s up", pEntry->Name); + CcspTraceInfo(("%s-%d: Created VLAN tag-0 interface %s\n", __FUNCTION__, __LINE__, pEntry->Name)); break; } case UNTAGGED_MACVLAN_PRIVATE: @@ -912,31 +968,31 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) } /* Delete any pre-existing interface with this name. */ - v_secure_system("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", - pEntry->Name, pEntry->Name, pEntry->Name); + EXEC_CMD("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", + pEntry->Name, pEntry->Name, pEntry->Name); /* Get MAC address with offset applied. */ + int rc; if (ANSC_STATUS_SUCCESS != EthLink_GetMacAddr(pEntry)) { - CcspTraceError(("%s-%d: Failed to get MAC address, creating MACVLAN(%s) without custom MAC\n", + CcspTraceError(("%s-%d: Failed to get MAC, creating MACVLAN(%s) without custom MAC\n", __FUNCTION__, __LINE__, macvlanMode)); - v_secure_system("ip link add link %s name %s type macvlan mode %s", - pEntry->BaseInterface, pEntry->Name, macvlanMode); + rc = EXEC_CMD("ip link add link %s name %s type macvlan mode %s", + pEntry->BaseInterface, pEntry->Name, macvlanMode); } else { - CcspTraceInfo(("%s-%d: Using MAC address: %s (offset: %ld) mode %s\n", + CcspTraceInfo(("%s-%d: MAC %s (offset %ld) mode %s\n", __FUNCTION__, __LINE__, pEntry->MACAddress, pEntry->MACAddrOffSet, macvlanMode)); - v_secure_system("ip link add link %s name %s address %s type macvlan mode %s", - pEntry->BaseInterface, pEntry->Name, pEntry->MACAddress, macvlanMode); + rc = EXEC_CMD("ip link add link %s name %s address %s type macvlan mode %s", + pEntry->BaseInterface, pEntry->Name, pEntry->MACAddress, macvlanMode); } - - v_secure_system("ip link set %s allmulticast on", pEntry->Name); - v_secure_system("ip link set %s multicast on", pEntry->Name); - v_secure_system("ip link set %s mtu 1500", pEntry->Name); - v_secure_system("ip link set %s up", pEntry->Name); - - CcspTraceInfo(("%s-%d: Successfully created MACVLAN(%s) untagged interface %s\n", + (void)rc; + EXEC_CMD("ip link set %s allmulticast on", pEntry->Name); + EXEC_CMD("ip link set %s multicast on", pEntry->Name); + EXEC_CMD("ip link set %s mtu 1500", pEntry->Name); + EXEC_CMD("ip link set %s up", pEntry->Name); + CcspTraceInfo(("%s-%d: Created MACVLAN(%s) interface %s\n", __FUNCTION__, __LINE__, macvlanMode, pEntry->Name)); break; } @@ -945,16 +1001,15 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) { /* Default: Linux bridge via brctl. The base interface is enslaved * to a bridge that carries untagged traffic. */ - v_secure_system("ip link show %s > /dev/null 2>&1 || brctl addbr %s", - pEntry->Name, pEntry->Name); + EXEC_CMD("ip link show %s > /dev/null 2>&1 || brctl addbr %s", + pEntry->Name, pEntry->Name); if ((strcmp(pEntry->BaseInterface, pEntry->Name) != 0) && (pEntry->BaseInterface[0] != '\0')) { - v_secure_system("brctl addif %s %s 2>/dev/null", - pEntry->Name, pEntry->BaseInterface); + EXEC_CMD("brctl addif %s %s", pEntry->Name, pEntry->BaseInterface); } - v_secure_system("ifconfig %s up", pEntry->Name); - CcspTraceInfo(("%s-%d: Successfully created bridge untagged interface %s\n", + EXEC_CMD("ifconfig %s up", pEntry->Name); + CcspTraceInfo(("%s-%d: Created bridge interface %s\n", __FUNCTION__, __LINE__, pEntry->Name)); break; } @@ -989,15 +1044,17 @@ static ANSC_STATUS EthLink_DeleteUnTaggedInterface(PDML_ETHERNET pEntry) { case UNTAGGED_SIMPLE_BRIDGE: default: + { /* Simple Linux bridge teardown via brctl. */ if ((strcmp(pEntry->BaseInterface, pEntry->Name) != 0) && (pEntry->BaseInterface[0] != '\0')) { - v_secure_system("brctl delif %s %s", pEntry->Name, pEntry->BaseInterface); + EXEC_CMD("brctl delif %s %s", pEntry->Name, pEntry->BaseInterface); } - v_secure_system("ifconfig %s down", pEntry->Name); - v_secure_system("brctl delbr %s", pEntry->Name); + EXEC_CMD("ifconfig %s down", pEntry->Name); + EXEC_CMD("brctl delbr %s", pEntry->Name); break; + } case UNTAGGED_VLAN_TAG_0: case UNTAGGED_MACVLAN_PRIVATE: @@ -1005,10 +1062,12 @@ static ANSC_STATUS EthLink_DeleteUnTaggedInterface(PDML_ETHERNET pEntry) case UNTAGGED_MACVLAN_BRIDGE: case UNTAGGED_MACVLAN_PASSTHRU: case UNTAGGED_MACVLAN_SOURCE: + { /* macvlan and vlan tag-0 devices are removed with ip link. */ - v_secure_system("ip link set %s down", pEntry->Name); - v_secure_system("ip link delete %s", pEntry->Name); + EXEC_CMD("ip link set %s down", pEntry->Name); + EXEC_CMD("ip link delete %s", pEntry->Name); break; + } } CcspTraceInfo(("%s-%d: Successfully deleted untagged VLAN interface %s\n", From 6c67f479a80b84a6b25383ae76a71c699d209892 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 30 Jul 2026 14:49:46 +0000 Subject: [PATCH 03/17] Enhance VLAN handling: add TaggedVlan type and streamline interface creation logic --- source/TR-181/include/ethernet_apis.h | 2 +- .../TR-181/middle_layer_src/ethernet_apis.c | 12 ------ source/TR-181/middle_layer_src/vlan_apis.c | 40 +++++++++++++++---- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index 5e3d8fa..1d1370e 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -94,7 +94,7 @@ typedef enum { * * Values map to the DM parameter UntaggedVlanType (uint32, mapped to string): * 0=Bridge, 1=MacvlanPrivate, 2=MacvlanVepa, 3=MacvlanBridge, - * 4=MacvlanPassthru, 5=MacvlanSource, 6=VlanTag0 + * 4=MacvlanPassthru, 5=MacvlanSource, 6=VlanTag0, 7=TaggedVlan * * MACVLAN modes correspond exactly to kernel ip-link(8) macvlan modes. * UNTAGGED_SIMPLE_BRIDGE is the default (used when not otherwise configured). diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index 0a50b7d..52a0552 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -939,17 +939,6 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) switch (pEntry->UnTaggedVlanType) { - case UNTAGGED_VLAN_TAG_0: - { - /* 802.1Q VLAN with tag id 0 (priority/untagged frames). */ - EXEC_CMD("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", - pEntry->Name, pEntry->Name, pEntry->Name); - EXEC_CMD("ip link add link %s name %s type vlan id 0", - pEntry->BaseInterface, pEntry->Name); - EXEC_CMD("ip link set %s up", pEntry->Name); - CcspTraceInfo(("%s-%d: Created VLAN tag-0 interface %s\n", __FUNCTION__, __LINE__, pEntry->Name)); - break; - } case UNTAGGED_MACVLAN_PRIVATE: case UNTAGGED_MACVLAN_VEPA: case UNTAGGED_MACVLAN_BRIDGE: @@ -1056,7 +1045,6 @@ static ANSC_STATUS EthLink_DeleteUnTaggedInterface(PDML_ETHERNET pEntry) break; } - case UNTAGGED_VLAN_TAG_0: case UNTAGGED_MACVLAN_PRIVATE: case UNTAGGED_MACVLAN_VEPA: case UNTAGGED_MACVLAN_BRIDGE: diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 147d78c..e7f459f 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -128,6 +128,7 @@ static ANSC_STATUS Vlan_DeleteInterface(PDML_VLAN p_Vlan) return ANSC_STATUS_FAILURE; } + v_secure_system("ip link set %s down", p_Vlan->Name); v_secure_system("ip link delete %s", p_Vlan->Name); return ANSC_STATUS_SUCCESS; @@ -243,8 +244,7 @@ static ANSC_STATUS Vlan_SetEthLink(PDML_VLAN pEntry, BOOL enable, BOOL PriTag) } /* Sync VLAN type to EthLink. TAGGED_VLAN(7) is harmless — EthLink_Enable - * skips untagged creation when PriorityTagging=TRUE. - * TODO: UNTAGGED_VLAN_TAG_0 may need PriorityTagging=TRUE in future. */ + * skips untagged creation when PriorityTagging=TRUE. */ ((PDML_ETHERNET)pNewEntry)->UnTaggedVlanType = (untagged_vlan_type_t)pEntry->UnTaggedVlanType; CcspTraceInfo(("%s-%d: VLAN type=%d synced to EthLink for %s\n", __FUNCTION__, __LINE__, pEntry->UnTaggedVlanType, pEntry->Name)); @@ -378,7 +378,7 @@ void * Vlan_Disable(void *Arg) } //Delete Created Tagged Vlan Interface - if (pEntry->UnTaggedVlanType == TAGGED_VLAN) + if (pEntry->VLANId > 0 || pEntry->UnTaggedVlanType == UNTAGGED_VLAN_TAG_0) { #ifdef FEATURE_MAPT char wan_ifname[BUFLEN_64] = {0}; @@ -594,6 +594,8 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; + vlan_configuration_t VlanCfg = {0}; + INT i; if (pEntry == NULL) { @@ -601,8 +603,7 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) return ANSC_STATUS_FAILURE; } - v_secure_system("ip link add link %s name %s type vlan id %u", pEntry->Alias , pEntry->Name, pEntry->VLANId); - + v_secure_system("ip link add link %s name %s type vlan id %u", pEntry->Alias, pEntry->Name, pEntry->VLANId); v_secure_system("ip link set %s up", pEntry->Name); if (Vlan_SetMacAddr(pEntry) == ANSC_STATUS_FAILURE) @@ -611,6 +612,27 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) return ANSC_STATUS_FAILURE; } + /* Apply 802.1p egress QoS map: maps kernel skb priority (SKBMark) to the + * outgoing VLAN PCP (EthernetPriorityMark) on egress. + * Note: alias is a label only (no kernel equivalent). + * skbPort would need tc-filter rules and is not set here. */ + strncpy(VlanCfg.L3Interface, pEntry->Name, sizeof(VlanCfg.L3Interface) - 1); + VlanCfg.VLANId = pEntry->VLANId; + if (EthLink_GetMarking(pEntry->Alias, &VlanCfg) == ANSC_STATUS_SUCCESS) + { + for (i = 0; i < (INT)VlanCfg.skbMarkingNumOfEntries; i++) + { + v_secure_system("ip link set %s type vlan egress-qos-map %u:%d", + pEntry->Name, + VlanCfg.skb_config[i].skbMark, + VlanCfg.skb_config[i].skbEthPriorityMark); + } + if (VlanCfg.skb_config != NULL) + { + free(VlanCfg.skb_config); + } + } + return returnStatus; } #endif @@ -663,8 +685,12 @@ void * Vlan_Enable(void *Arg) pthread_detach(pthread_self()); pthread_mutex_lock(&vlan_access_mutex); - //Create Vlan Tagged or UnTagged Interface, selected by UnTaggedVlanType - if (pEntry->UnTaggedVlanType == TAGGED_VLAN) { + //Create Vlan Tagged or UnTagged Interface + /* UNTAGGED_VLAN_TAG_0 uses the tagged path: it is a 802.1Q VLAN device + * with id 0, so create/QoS/delete all work identically to tagged VLANs. + * PSM must store VLANId=0 for those entries. */ + if (pEntry->VLANId > 0 || pEntry->UnTaggedVlanType == UNTAGGED_VLAN_TAG_0) + { if (Vlan_SetEthLink(pEntry, TRUE, TRUE) == ANSC_STATUS_FAILURE) { CcspTraceError(("%s-%d: Failed to Enable EthLink\n", __FUNCTION__, __LINE__)); From 18ed27532b25f5d2109ac3c3807dda426392fd13 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 30 Jul 2026 16:01:52 +0000 Subject: [PATCH 04/17] Update UntaggedVlanType type to string in RdkVlanManager.xml and add configuration and sequence diagrams documentation for VlanManager --- config/RdkVlanManager.xml | 2 +- docs/vlan-configuration.md | 168 +++++++++++++++++++++++ docs/vlan-sequence-diagrams.md | 242 +++++++++++++++++++++++++++++++++ 3 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 docs/vlan-configuration.md create mode 100644 docs/vlan-sequence-diagrams.md diff --git a/config/RdkVlanManager.xml b/config/RdkVlanManager.xml index 3f47b4d..33879f5 100644 --- a/config/RdkVlanManager.xml +++ b/config/RdkVlanManager.xml @@ -205,7 +205,7 @@ UntaggedVlanType - unsignedInt: Bridge(0),MacvlanPrivate(1),MacvlanVepa(2),MacvlanBridge(3),MacvlanPassthru(4),MacvlanSource(5),VlanTag0(6),Tagged(7) + string: Bridge(0),MacvlanPrivate(1),MacvlanVepa(2),MacvlanBridge(3),MacvlanPassthru(4),MacvlanSource(5),VlanTag0(6),Tagged(7) uint32/mapped false diff --git a/docs/vlan-configuration.md b/docs/vlan-configuration.md new file mode 100644 index 0000000..2de9ea5 --- /dev/null +++ b/docs/vlan-configuration.md @@ -0,0 +1,168 @@ +# VlanManager Configuration Guide + +This document describes how to configure VlanManager VLAN termination entries +through PSM, when to choose each VLAN / MACVLAN type, and how the +`UntaggedVlanType` data-model parameter maps to the underlying Linux netdev. + +- [1. PSM configuration](#1-psm-configuration) + - [1.1 Per-entry PSM keys](#11-per-entry-psm-keys) + - [1.2 Country / region PSM (HUB4 only)](#12-country--region-psm-hub4-only) + - [1.3 Example](#13-example) +- [2. Interface type selection](#2-interface-type-selection) + - [2.1 The `UntaggedVlanType` parameter](#21-the-untaggedvlantype-parameter) + - [2.2 Decision guide](#22-decision-guide) +- [3. Data model parameters](#3-data-model-parameters) + +--- + +## 1. PSM configuration + +VlanManager loads all VLAN termination entries from PSM at start-up +(`VlanTerminationInitialize()` in `vlan_internal.c`). Each entry describes one +virtual interface layered on top of an Ethernet base interface. + +### 1.1 Per-entry PSM keys + +All keys are indexed by the 1-based instance number `%d`. + +| PSM key | Type | Description | +|---------|------|-------------| +| `dmsb.vlanmanager.ifcount` | int | Total number of VLAN termination entries | +| `dmsb.vlanmanager.%d.VlanEnable` | `TRUE`/`FALSE` | Enable the entry at boot | +| `dmsb.vlanmanager.%d.alias` | string | Alias / label (e.g. `DATA`, `VOICE`); also the parent ethlink name | +| `dmsb.vlanmanager.%d.name` | string | Resulting interface name (e.g. `erouter0`, `nett\|brwan`) | +| `dmsb.vlanmanager.%d.lowerlayers` | string | TR-181 path to the parent EthLink (`Device.X_RDK_Ethernet.Link.%d`) | +| `dmsb.vlanmanager.%d.vlanid` | int | 802.1Q VLAN id. `> 0` = tagged, `0` = tag-0, `< 0` = untagged | +| `dmsb.vlanmanager.%d.tpid` | uint | Tag protocol id (0x8100 / 0x88a8) | +| `dmsb.vlanmanager.%d.untaggedvlantype` | uint | **New.** Selects how an untagged (`vlanid <= 0`) interface is realised. See [§2](#2-interface-type-selection). | +| `dmsb.vlanmanager.%d.baseinterface` | string | Physical base interface (e.g. `eth0`, `dsl0`) | +| `dmsb.vlanmanager.%d.path` | string | TR-181 path used to report VlanStatus back to WanManager | + +> `untaggedvlantype` is only consulted for **untagged** entries. For tagged +> entries (`vlanid > 0`) it is forced to `Tagged(7)` at load time and never +> read at interface-creation time. + +### 1.2 Country / region PSM (HUB4 only) + +On builds compiled with `_HUB4_PRODUCT_REQ_`, a second, region-indexed PSM +table selects the VLAN id / TPID per router region: + +| PSM key | Description | +|---------|-------------| +| `dmsb.vlanmanager.cfg.count` | Number of regional config rows | +| `dmsb.vlanmanager.cfg.%d.region` | Region string matched against `platform_hal_GetRouterRegion()` | +| `dmsb.vlanmanager.cfg.%d.vlanid` | VLAN id for that region | +| `dmsb.vlanmanager.cfg.%d.tpid` | TPID for that region | + +> **Deprecation note.** This country/region `dmsb.vlanmanager.cfg.*` table is a +> stop-gap that hard-codes the VLAN id per country in PSM. It **can and should +> be removed** once the WAN VLAN is determined dynamically — i.e. after moving +> to *VLAN discovery* (auto-detect the operator VLAN on the link) or to a +> *boot-time configuration* source (cloud/ACS/JSON). At that point VlanManager +> should receive the resolved `vlanid`/`tpid` directly on the per-entry keys and +> the regional `cfg` branch in `VlanTerminationInitialize()` can be deleted. +> +> `untaggedvlantype` is intentionally **not** loaded from the `cfg` table: the +> HUB4 regional flow always uses `UNTAGGED_SIMPLE_BRIDGE` (brctl) for untagged +> VLANs. + +### 1.3 Example + +A single tagged DATA VLAN (id 100) on `eth0`: + +``` +psmcli set dmsb.vlanmanager.ifcount 1 +psmcli set dmsb.vlanmanager.1.VlanEnable TRUE +psmcli set dmsb.vlanmanager.1.alias DATA +psmcli set dmsb.vlanmanager.1.name nettXvlan +psmcli set dmsb.vlanmanager.1.lowerlayers Device.X_RDK_Ethernet.Link.1 +psmcli set dmsb.vlanmanager.1.vlanid 100 +psmcli set dmsb.vlanmanager.1.tpid 33024 +psmcli set dmsb.vlanmanager.1.baseinterface eth0 +``` + +An untagged WAN over a Linux bridge (default type): + +``` +psmcli set dmsb.vlanmanager.1.vlanid -1 +psmcli set dmsb.vlanmanager.1.untaggedvlantype 0 # UNTAGGED_SIMPLE_BRIDGE +psmcli set dmsb.vlanmanager.1.baseinterface eth0 +``` + +--- + +## 2. Interface type selection + +The `vlanid` value picks the **class** of interface; `untaggedvlantype` refines +the untagged class: + +```mermaid +flowchart TD + A[VLAN entry enabled] --> B{vlanid} + B -->|"> 0"| T[Tagged 802.1Q VLAN] + B -->|"== 0"| Z{untaggedvlantype} + B -->|"< 0"| U{untaggedvlantype} + Z -->|VlanTag0 6| T0[VLAN device id 0] + U -->|Bridge 0| BR[brctl bridge] + U -->|Macvlan 1-5| MV[macvlan device] + T -.tagged path.-> TP[Vlan_CreateTaggedInterface] + T0 -.tagged path.-> TP + BR -.untagged path.-> EP[EthLink_CreateUnTaggedInterface] + MV -.untagged path.-> EP +``` + +### 2.1 The `UntaggedVlanType` parameter + +| Value | Name | Realisation | Kernel command | +|-------|------|-------------|----------------| +| 0 | `Bridge` (default) | Linux bridge, base iface enslaved | `brctl addbr` / `addif` | +| 1 | `MacvlanPrivate` | macvlan, endpoints isolated | `ip link add … type macvlan mode private` | +| 2 | `MacvlanVepa` | macvlan, hairpin via external switch | `… mode vepa` | +| 3 | `MacvlanBridge` | macvlan, local forwarding between endpoints | `… mode bridge` | +| 4 | `MacvlanPassthru` | macvlan, single endpoint owns the lower dev | `… mode passthru` | +| 5 | `MacvlanSource` | macvlan, source-MAC filtered | `… mode source` | +| 6 | `VlanTag0` | 802.1Q VLAN with tag id 0 (priority-tagged) | `ip link add … type vlan id 0` | +| 7 | `Tagged` | conventional tagged VLAN (display only) | set automatically when `vlanid > 0` | + +The MACVLAN modes map 1:1 to the kernel `ip-link(8)` macvlan modes. + +### 2.2 Decision guide + +| Use case | Recommended type | +|----------|------------------| +| Operator delivers WAN on a **tagged** VLAN | tagged (`vlanid > 0`) | +| Priority-tagged frames (VID 0, PCP set) with QoS | `VlanTag0 (6)` | +| Plain untagged WAN, want a bridge you can add more ports to later | `Bridge (0)` — default | +| Untagged WAN needing its **own MAC** distinct from the base iface, isolated | `MacvlanPrivate (1)` | +| Multiple virtual endpoints that must talk to each other locally | `MacvlanBridge (3)` | +| Deployment behind a VEPA-capable switch (hairpin) | `MacvlanVepa (2)` | +| One endpoint that must fully own the base iface (e.g. move its MAC) | `MacvlanPassthru (4)` | +| Restrict to a fixed allow-list of source MACs | `MacvlanSource (5)` | + +Notes: +- Only **tagged** and **VlanTag0** interfaces support 802.1p `egress-qos-map`; + bridge and macvlan types cannot carry per-priority PCP marking (see the + sequence-diagram doc, *Markings*). +- `Bridge (0)` inherits the base interface MAC automatically (kernel sets the + bridge MAC to the lowest enslaved MAC). The macvlan types honour the EthLink + `MACAddrOffSet` to derive a distinct MAC. + +--- + +## 3. Data model parameters + +`Device.Ethernet.VLANTermination.{i}.` exposes, among others: + +| Parameter | Type | Access | Backed by | +|-----------|------|--------|-----------| +| `VLANID` | int | RW | `dmsb.vlanmanager.%d.vlanid` | +| `TPID` | uint | RW | `dmsb.vlanmanager.%d.tpid` | +| `UntaggedVlanType` | uint (mapped) | **RO** | `dmsb.vlanmanager.%d.untaggedvlantype` | +| `X_RDK_BaseInterface` | string | RW | `dmsb.vlanmanager.%d.baseinterface` | + +`UntaggedVlanType` is a **read-only, mapped** enum. It is populated from PSM at +init and is not writable from the data model — change it via PSM and restart, or +via boot-time config once available. + +Mapped string values: +`Bridge(0),MacvlanPrivate(1),MacvlanVepa(2),MacvlanBridge(3),MacvlanPassthru(4),MacvlanSource(5),VlanTag0(6),Tagged(7)` diff --git a/docs/vlan-sequence-diagrams.md b/docs/vlan-sequence-diagrams.md new file mode 100644 index 0000000..60234cf --- /dev/null +++ b/docs/vlan-sequence-diagrams.md @@ -0,0 +1,242 @@ +# VlanManager Components & Sequence Diagrams + +This document describes the runtime components of VlanManager and the +create / delete / marking sequences for tagged and untagged VLAN interfaces. + +- [1. Components](#1-components) +- [2. Trigger & threading model](#2-trigger--threading-model) +- [3. Tagged VLAN create (incl. VLAN tag-0)](#3-tagged-vlan-create-incl-vlan-tag-0) +- [4. Untagged VLAN create (bridge / macvlan)](#4-untagged-vlan-create-bridge--macvlan) +- [5. Delete sequences](#5-delete-sequences) +- [6. Markings (QoS)](#6-markings-qos) + +--- + +## 1. Components + +```mermaid +flowchart LR + subgraph WM[WanManager] + WMK[Marking table
SKBMark / EthPriority / DSCP] + end + subgraph VM[VlanManager] + VDML[VLANTermination DML
vlan_dml.c] + VAPI[VLAN entry logic
vlan_apis.c] + EDML[EthLink DML
ethernet_dml.c] + EAPI[EthLink logic
ethernet_apis.c] + end + K[(Linux kernel
ip / brctl / ifconfig)] + PSM[(PSM)] + + PSM --> VAPI + PSM --> EAPI + VDML --> VAPI + VAPI -->|Vlan_SetEthLink| EDML + EDML --> EAPI + WMK -->|EthLink_AddMarking / GetMarking| EAPI + VAPI -->|popen: ip link / QoS| K + EAPI -->|popen: ip link / brctl / ifconfig| K + EAPI -->|VlanStatus Up/Down| WM +``` + +| Component | File | Responsibility | +|-----------|------|----------------| +| VLANTermination DML | `vlan_dml.c` | TR-181 get/set, spawns worker threads on Enable | +| VLAN entry logic | `vlan_apis.c` | Tagged create/delete, QoS apply, status poll | +| EthLink DML | `ethernet_dml.c` | TR-181 get/set for `Device.X_RDK_Ethernet.Link` | +| EthLink logic | `ethernet_apis.c` | Untagged create/delete, marking table, VlanStatus | +| Command runner | `ethernet_apis.c` `EthLink_RunCmd` / `EXEC_CMD` | `popen()` wrapper that logs the command + all stdout/stderr and the exit code | + +**Key architectural point:** the *config* (type, vlanid) lives on the **VLAN +entry**, but untagged interface *creation* happens in the **EthLink** object. +`Vlan_SetEthLink()` bridges the two — `EthLink_GetEntry()` returns the live +`DML_ETHERNET` struct, so the VLAN thread writes `UnTaggedVlanType` directly onto +it before committing. + +--- + +## 2. Trigger & threading model + +Enabling an entry (from PSM at boot, or a DM `Enable=true`) spawns a detached +worker thread. Tagged and untagged both start the same way but diverge on +`vlanid` / `UnTaggedVlanType`. + +```mermaid +flowchart TD + E[Vlan Enable = true] --> C[Vlan_SetParamBoolValue] + C --> P[pthread_create] + P --> EN[Vlan_Enable thread] + EN --> D{vlanid > 0
OR type == VlanTag0?} + D -->|yes| TAG[Tagged path] + D -->|no| UNT[Untagged path] +``` + +--- + +## 3. Tagged VLAN create (incl. VLAN tag-0) + +Both a normal tagged VLAN (`vlanid > 0`) and VLAN tag-0 (`UntaggedVlanType = +VlanTag0`) take this path — a tag-0 interface is a real 802.1Q device, so +create / QoS / delete are identical. + +```mermaid +sequenceDiagram + participant T as Vlan_Enable (VLAN thread) + participant SE as Vlan_SetEthLink + participant EE as EthLink_Enable + participant CI as Vlan_CreateTaggedInterface + participant QM as Vlan_ApplyQoSMarking + participant K as Kernel + participant WM as WanManager + + T->>SE: enable=TRUE, PriTag=TRUE + SE->>SE: sync UnTaggedVlanType to EthLink struct + SE->>EE: EthLink Enable=TRUE, PriorityTagging=TRUE + EE->>EE: EthLink_AddMarking populate table + Note over EE: PriorityTagging=TRUE so skip untagged create + T->>K: if exists, ip link set down and delete + T->>CI: create + CI->>K: ip link add link base name ifname type vlan id N + CI->>K: ip link set ifname up + CI->>K: ip link set dev ifname address mac + T->>QM: apply QoS + QM->>EE: EthLink_GetMarking alias + QM->>K: ip link set ifname type vlan egress-qos-map SKB colon PCP + T->>K: poll IFF_RUNNING 10x 2s + T->>WM: VlanStatus = Up +``` + +--- + +## 4. Untagged VLAN create (bridge / macvlan) + +For `vlanid < 0` with a bridge or macvlan type, creation is delegated to the +EthLink object. `Vlan_SetEthLink` sets `PriorityTagging=FALSE`, which makes +`EthLink_Enable` run the untagged creation switch. + +```mermaid +sequenceDiagram + participant T as Vlan_Enable (VLAN thread) + participant SE as Vlan_SetEthLink + participant EE as EthLink_Enable + participant CU as EthLink_CreateUnTaggedInterface + participant K as Kernel + participant WM as WanManager + + T->>SE: enable=TRUE, PriTag=FALSE + SE->>SE: sync UnTaggedVlanType to live EthLink struct + SE->>EE: EthLink Enable=TRUE, PriorityTagging=FALSE + EE->>EE: EthLink_AddMarking + EE->>CU: create untagged + alt UNTAGGED_SIMPLE_BRIDGE default + CU->>K: brctl addbr ifname + CU->>K: brctl addif ifname base + CU->>K: ifconfig ifname up + else UNTAGGED_MACVLAN private/vepa/bridge/passthru/source + CU->>K: ip link add link base name ifname address mac type macvlan mode m + CU->>K: ip link set ifname allmulticast multicast on, mtu 1500, up + end + EE->>K: poll IFF_RUNNING 10x 2s + EE->>WM: VlanStatus = Up + T->>WM: VlanStatus = Up untagged status re-check +``` + +--- + +## 5. Delete sequences + +Delete mirrors create. The `vlanid > 0 || type == VlanTag0` test again routes +tagged/tag-0 to the VLAN thread and bridge/macvlan to the EthLink object. + +```mermaid +sequenceDiagram + participant T as Vlan_Disable (VLAN thread) + participant SE as Vlan_SetEthLink + participant ED as EthLink_Disable + participant DU as EthLink_DeleteUnTaggedInterface + participant K as Kernel + participant WM as WanManager + + T->>SE: enable=FALSE + SE->>ED: EthLink Enable=FALSE + alt tagged OR VlanTag0 + Note over T: handled in VLAN thread + T->>K: ip link set ifname down + T->>K: ip link delete ifname + else untagged bridge/macvlan + ED->>DU: delete untagged + alt UNTAGGED_SIMPLE_BRIDGE + DU->>K: brctl delif ifname base + DU->>K: ifconfig ifname down + DU->>K: brctl delbr ifname + else UNTAGGED_MACVLAN modes + DU->>K: ip link set ifname down + DU->>K: ip link delete ifname + end + end + T->>WM: VlanStatus = Down +``` + +> Interfaces are always brought **down before delete** (`ip link set … down` +> then `ip link delete …`, or `ifconfig … down` then `brctl delbr …`) so the +> kernel does not reject removal of a running device. + +--- + +## 6. Markings (QoS) + +WanManager owns the marking table; VlanManager only *reads* it and applies the +result to tagged / tag-0 interfaces via the kernel VLAN `egress-qos-map`. + +### 6.1 Data flow + +```mermaid +flowchart LR + subgraph WanManager + DM["Device.X_RDK_WanManager…Marking.{i}
Alias / SKBPort / SKBMark / EthernetPriorityMark"] + end + AM[EthLink_AddMarking] -->|CCSP get| DM + AM --> TBL[DML_ETHERNET.pstDataModelMarking[]] + GM[EthLink_GetMarking] --> TBL + GM --> CFG["vlan_configuration_t.skb_config[]
(vlan_skb_config_t)"] + CFG --> QOS[egress-qos-map] + QOS --> K["ip link set <if> type vlan
egress-qos-map SKBMark:EthPriority"] +``` + +### 6.2 `vlan_skb_config_t` fields + +| Field | Meaning | Used in egress-qos-map? | +|-------|---------|--------------------------| +| `alias` | Label only (`DATA` / `VOICE`) | No — no kernel equivalent | +| `skbMark` | Kernel skb priority (fwmark class) | **Yes** — left side of the map | +| `skbEthPriorityMark` | Outgoing 802.1p PCP (0–7) | **Yes** — right side of the map | +| `skbPort` | Port-based classification | No — would require `tc filter` rules | + +The applied command is: + +``` +ip link set type vlan egress-qos-map : +``` + +### 6.3 Which types get QoS + +| Interface type | egress-qos-map | Reason | +|----------------|:--------------:|--------| +| Tagged VLAN | ✅ | 802.1Q device carries a PCP field | +| VlanTag0 | ✅ | also a 802.1Q device (priority-tagged) | +| Bridge | ❌ | not a VLAN device | +| Macvlan (all modes) | ❌ | no 802.1Q tag at this layer | + +For bridge / macvlan untagged types there is no L2 PCP to set; QoS for those is +handled elsewhere in the stack (WanManager L2/L3 marking framework). + +### 6.4 When QoS is (re)applied + +```mermaid +flowchart TD + A[Tagged/Tag0 create] --> Q1[Vlan_ApplyQoSMarking] + R[EthLink refresh
X_RDK_Refresh=true] --> Q2[EthLink_TriggerVlanRefresh] + Q2 --> Q3[EthLink_SetEgressQoSMap] + Q1 --> MAP[egress-qos-map applied] + Q3 --> MAP +``` From 127367fd1a49fd4e9d40d046c7d0c7f4f5eac5dc Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 30 Jul 2026 16:38:52 +0000 Subject: [PATCH 05/17] Refactor MAC address handling in EthLink_CreateUnTaggedInterface: change MACAddrOffSet to INT for consistency and streamline interface creation logic. --- source/TR-181/include/ethernet_apis.h | 2 +- .../TR-181/middle_layer_src/ethernet_apis.c | 44 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index 1d1370e..6a74bcc 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -137,7 +137,7 @@ _DML_ETHERNET CHAR LowerLayers[1024]; CHAR Path[1024]; CHAR MACAddress[18]; - LONG MACAddrOffSet; // Changed to LONG to support negative offsets + INT MACAddrOffSet; /* Signed offset added to PAM base MAC. INT matches GetParamIntValue handler. */ BOOLEAN PriorityTagging; untagged_vlan_type_t UnTaggedVlanType; // Untagged VLAN realisation type (bridge/macvlan/tag0) UINT NumberofMarkingEntries; diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index 52a0552..73741e0 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -933,7 +933,7 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) * method is selected by pEntry->UnTaggedVlanType, which is handed over from * the VLAN entry (Vlan_SetEthLink) or loaded from the EthLink defaults. */ - CcspTraceInfo(("%s-%d: Creating untagged interface %s on base interface %s (type=%d, MAC offset=%ld)\n", + CcspTraceInfo(("%s-%d: Creating untagged interface %s on base interface %s (type=%d, MAC offset=%d)\n", __FUNCTION__, __LINE__, pEntry->Name, pEntry->BaseInterface, pEntry->UnTaggedVlanType, pEntry->MACAddrOffSet)); @@ -960,27 +960,12 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) EXEC_CMD("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", pEntry->Name, pEntry->Name, pEntry->Name); - /* Get MAC address with offset applied. */ - int rc; - if (ANSC_STATUS_SUCCESS != EthLink_GetMacAddr(pEntry)) - { - CcspTraceError(("%s-%d: Failed to get MAC, creating MACVLAN(%s) without custom MAC\n", - __FUNCTION__, __LINE__, macvlanMode)); - rc = EXEC_CMD("ip link add link %s name %s type macvlan mode %s", - pEntry->BaseInterface, pEntry->Name, macvlanMode); - } - else - { - CcspTraceInfo(("%s-%d: MAC %s (offset %ld) mode %s\n", - __FUNCTION__, __LINE__, pEntry->MACAddress, pEntry->MACAddrOffSet, macvlanMode)); - rc = EXEC_CMD("ip link add link %s name %s address %s type macvlan mode %s", - pEntry->BaseInterface, pEntry->Name, pEntry->MACAddress, macvlanMode); - } - (void)rc; + /* Create without custom MAC address — MAC is applied uniformly below. */ + EXEC_CMD("ip link add link %s name %s type macvlan mode %s", + pEntry->BaseInterface, pEntry->Name, macvlanMode); EXEC_CMD("ip link set %s allmulticast on", pEntry->Name); EXEC_CMD("ip link set %s multicast on", pEntry->Name); EXEC_CMD("ip link set %s mtu 1500", pEntry->Name); - EXEC_CMD("ip link set %s up", pEntry->Name); CcspTraceInfo(("%s-%d: Created MACVLAN(%s) interface %s\n", __FUNCTION__, __LINE__, macvlanMode, pEntry->Name)); break; @@ -997,13 +982,32 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) { EXEC_CMD("brctl addif %s %s", pEntry->Name, pEntry->BaseInterface); } - EXEC_CMD("ifconfig %s up", pEntry->Name); CcspTraceInfo(("%s-%d: Created bridge interface %s\n", __FUNCTION__, __LINE__, pEntry->Name)); break; } } + /* Apply MAC address for all interface types. + * EthLink_GetMacAddr computes PAM base + MACAddrOffSet and stores the + * result in pEntry->MACAddress. Set it before bringing the interface up + * so there is no window with an incorrect MAC. */ + if (ANSC_STATUS_SUCCESS == EthLink_GetMacAddr(pEntry)) + { + EXEC_CMD("ip link set dev %s address %s", pEntry->Name, pEntry->MACAddress); + CcspTraceInfo(("%s-%d: MAC %s (offset %d) applied to %s\n", + __FUNCTION__, __LINE__, + pEntry->MACAddress, pEntry->MACAddrOffSet, pEntry->Name)); + } + else + { + CcspTraceInfo(("%s-%d: EthLink_GetMacAddr failed, using default MAC for %s\n", + __FUNCTION__, __LINE__, pEntry->Name)); + } + + /* Bring up — common for all interface types. */ + EXEC_CMD("ip link set %s up", pEntry->Name); + #endif //Free VlanCfg skb_config memory if (VlanCfg.skb_config != NULL) From bf136453c3058de9390967df52161938fdea9a03 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Tue, 4 Aug 2026 12:01:17 +0000 Subject: [PATCH 06/17] using SKBPort for skb priority tag --- source/TR-181/middle_layer_src/vlan_apis.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index e7f459f..384e3c3 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -620,11 +620,16 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) VlanCfg.VLANId = pEntry->VLANId; if (EthLink_GetMarking(pEntry->Alias, &VlanCfg) == ANSC_STATUS_SUCCESS) { + /* egress-qos-map reads skb->priority; CLASSIFY --set-class in utopia firewall sets priority=SKBPort */ for (i = 0; i < (INT)VlanCfg.skbMarkingNumOfEntries; i++) { + CcspTraceInfo(("%s-%d: egress-qos-map %s: SKBPort=%u -> pbit=%d\n", + __FUNCTION__, __LINE__, pEntry->Name, + VlanCfg.skb_config[i].skbPort, + VlanCfg.skb_config[i].skbEthPriorityMark)); v_secure_system("ip link set %s type vlan egress-qos-map %u:%d", pEntry->Name, - VlanCfg.skb_config[i].skbMark, + VlanCfg.skb_config[i].skbPort, VlanCfg.skb_config[i].skbEthPriorityMark); } if (VlanCfg.skb_config != NULL) From 3123b231fe0bfb7333d515adbdb673063fc5ea78 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Wed, 5 Aug 2026 17:09:48 +0000 Subject: [PATCH 07/17] Unify VLANId==-1 bridge handling superseded by UnTaggedVlanType --- source/TR-181/middle_layer_src/vlan_apis.c | 57 ++-------------------- 1 file changed, 3 insertions(+), 54 deletions(-) diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 384e3c3..092b48f 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -367,14 +367,10 @@ void * Vlan_Disable(void *Arg) pthread_detach(pthread_self()); pthread_mutex_lock(&vlan_access_mutex); - - if (pEntry->VLANId != -1) + //Set EthLink to False. it will take care UnTagged Created Vlan Interface + if (Vlan_SetEthLink(pEntry, FALSE, FALSE) == ANSC_STATUS_FAILURE) { - //Set EthLink to False. it will take care UnTagged Created Vlan Interface - if (Vlan_SetEthLink(pEntry, FALSE, FALSE) == ANSC_STATUS_FAILURE) - { - CcspTraceError(("%s-%d: Failed to Disable EthLink\n", __FUNCTION__, __LINE__)); - } + CcspTraceError(("%s-%d: Failed to Disable EthLink\n", __FUNCTION__, __LINE__)); } //Delete Created Tagged Vlan Interface @@ -413,19 +409,6 @@ void * Vlan_Disable(void *Arg) Vlan_DeleteInterface(pEntry); #endif } - else if (pEntry->VLANId == -1) - { - /* If the VLANID = -1, the VLAN is a bridge, delete the bridge and delete the interface from the bridge */ - if (strcmp(pEntry->BaseInterface, pEntry->Name) != 0) - { - if (pEntry->BaseInterface[0] != '\0') - { - v_secure_system("brctl delif %s %s", pEntry->Name, pEntry->BaseInterface); - } - v_secure_system("ifconfig %s down", pEntry->Name); - v_secure_system("brctl delbr %s", pEntry->Name); - } - } pEntry->Status = VLAN_IF_DOWN; EthLink_SendVirtualIfaceVlanStatus(pEntry->Path, "Down"); @@ -732,40 +715,6 @@ void * Vlan_Enable(void *Arg) Vlan_WaitForInterfaceUp(pEntry, "Tagged"); } - else if (pEntry->VLANId == -1) - { - /* If the VLANID = -1, the VLAN is a bridge, create the bridge and add the interface to the bridge */ - if (strcmp(pEntry->BaseInterface, pEntry->Name) != 0) - { - v_secure_system("ip link show %s > /dev/null 2>&1 || brctl addbr %s", pEntry->Name, pEntry->Name); - v_secure_system("brctl addif %s %s 2>/dev/null", pEntry->Name, pEntry->BaseInterface); - v_secure_system("ifconfig %s up", pEntry->Name); - } - - //Get status of VLAN link - status = VLAN_IF_DOWN; - while(iIterator < 10) - { - if (ANSC_STATUS_FAILURE == Vlan_GetTaggedVlanInterfaceStatus(pEntry->Name, &status)) - { - CcspTraceError(("%s-%d: Failed to get Tagged Vlan Interface=%s Status \n", __FUNCTION__, __LINE__, pEntry->Name)); - } - - if (VLAN_IF_UP == status) - { - EthLink_SendVirtualIfaceVlanStatus(pEntry->Path, "Up"); - CcspTraceInfo(("%s-%d: Successfully Updated Vlan Status to WanManager for Interface(%s) \n", __FUNCTION__, __LINE__, pEntry->Name)); - break; - } - - iIterator++; - sleep(2); - CcspTraceInfo(("%s-%d: Interface Status(%d), retry-count=%d \n", __FUNCTION__, __LINE__, status, iIterator)); - } - long uptime = 0; - get_uptime(&uptime); - pEntry->LastChange = uptime; - } else { //Enable EthLink and it will take care Creation of UnTagged Vlan Interface. From 4dcadff9e0dbee0068f982e7699543fd96ac673d Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Wed, 5 Aug 2026 17:23:41 +0000 Subject: [PATCH 08/17] Update default untagged VLAN type to UNTAGGED_MACVLAN_PRIVATE and adjust related logic --- source/TR-181/include/ethernet_apis.h | 16 ++++++++-------- source/TR-181/include/vlan_apis.h | 2 +- source/TR-181/middle_layer_src/vlan_internal.c | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index 6a74bcc..4da9571 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -97,18 +97,18 @@ typedef enum { * 4=MacvlanPassthru, 5=MacvlanSource, 6=VlanTag0, 7=TaggedVlan * * MACVLAN modes correspond exactly to kernel ip-link(8) macvlan modes. - * UNTAGGED_SIMPLE_BRIDGE is the default (used when not otherwise configured). + * UNTAGGED_MACVLAN_PRIVATE is the default (used when not otherwise configured). */ typedef enum _UNTAGGED_VLAN_TYPE { - UNTAGGED_SIMPLE_BRIDGE = 0, /* Default: Linux bridge via brctl */ - UNTAGGED_MACVLAN_PRIVATE = 1, /* macvlan mode private */ - UNTAGGED_MACVLAN_VEPA = 2, /* macvlan mode vepa */ - UNTAGGED_MACVLAN_BRIDGE = 3, /* macvlan mode bridge */ - UNTAGGED_MACVLAN_PASSTHRU = 4, /* macvlan mode passthru */ - UNTAGGED_MACVLAN_SOURCE = 5, /* macvlan mode source */ - UNTAGGED_VLAN_TAG_0 = 6, /* 802.1Q VLAN tag id 0 */ + UNTAGGED_MACVLAN_PRIVATE = 0, /* Default: macvlan mode private */ + UNTAGGED_MACVLAN_VEPA = 1, /* macvlan mode vepa */ + UNTAGGED_MACVLAN_BRIDGE = 2, /* macvlan mode bridge */ + UNTAGGED_MACVLAN_PASSTHRU = 3, /* macvlan mode passthru */ + UNTAGGED_MACVLAN_SOURCE = 4, /* macvlan mode source */ + UNTAGGED_VLAN_TAG_0 = 5, /* 802.1Q VLAN tag id 0 */ + UNTAGGED_SIMPLE_BRIDGE = 6, /* Linux bridge via brctl */ TAGGED_VLAN = 7 /* Tagged VLAN (VLANID > 0). DML path only. */ } untagged_vlan_type_t; diff --git a/source/TR-181/include/vlan_apis.h b/source/TR-181/include/vlan_apis.h index 9599b83..dfc6c5c 100644 --- a/source/TR-181/include/vlan_apis.h +++ b/source/TR-181/include/vlan_apis.h @@ -98,7 +98,7 @@ static inline void DML_VLAN_INIT(PDML_VLAN pVlan) { pVlan->Enable = FALSE; pVlan->Status = VLAN_IF_DOWN; - pVlan->UnTaggedVlanType = 0; /* UNTAGGED_SIMPLE_BRIDGE – default */ + pVlan->UnTaggedVlanType = UNTAGGED_MACVLAN_PRIVATE; /* default */ } /************************************* diff --git a/source/TR-181/middle_layer_src/vlan_internal.c b/source/TR-181/middle_layer_src/vlan_internal.c index 716590e..2ebddd0 100644 --- a/source/TR-181/middle_layer_src/vlan_internal.c +++ b/source/TR-181/middle_layer_src/vlan_internal.c @@ -282,8 +282,8 @@ static ANSC_STATUS VlanTerminationInitialize( ANSC_HANDLE hThisObject) } /* Set UntaggedVlanType: tagged VLANs use TAGGED_VLAN (7); untagged VLANs - * default to UNTAGGED_SIMPLE_BRIDGE (0) for the HUB4 regional flow. */ - pVlan[nIndex].UnTaggedVlanType = (pVlan[nIndex].VLANId > 0) ? 7 /* TAGGED_VLAN */ : 0 /* UNTAGGED_SIMPLE_BRIDGE */; + * default to UNTAGGED_MACVLAN_PRIVATE for the HUB4 regional flow. */ + pVlan[nIndex].UnTaggedVlanType = (pVlan[nIndex].VLANId > 0) ? TAGGED_VLAN : UNTAGGED_MACVLAN_PRIVATE; /*TODO: *Need to be Removed Path From PSM Once RBUS Support Available in VlanManager and WanManager. @@ -385,10 +385,10 @@ static ANSC_STATUS VlanTerminationInitialize( ANSC_HANDLE hThisObject) } /* Set UntaggedVlanType: tagged VLANs always use TAGGED_VLAN (7). - * For untagged VLANs load the type from PSM; falls back to 0 (UNTAGGED_SIMPLE_BRIDGE). */ + * For untagged VLANs load the type from PSM; falls back to UNTAGGED_MACVLAN_PRIVATE. */ if (pVlan[nIndex].VLANId > 0) { - pVlan[nIndex].UnTaggedVlanType = 7; /* TAGGED_VLAN */ + pVlan[nIndex].UnTaggedVlanType = TAGGED_VLAN; } else { From cad36e9a067f4a4623cb88b8c59ffca6ee5d80b2 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 6 Aug 2026 09:39:41 +0000 Subject: [PATCH 09/17] Add ethernet_apis.h include to vlan_apis.h and vlan_internal.c for enhanced functionality --- source/TR-181/include/vlan_apis.h | 1 + source/TR-181/middle_layer_src/vlan_internal.c | 1 + 2 files changed, 2 insertions(+) diff --git a/source/TR-181/include/vlan_apis.h b/source/TR-181/include/vlan_apis.h index dfc6c5c..df29ee0 100644 --- a/source/TR-181/include/vlan_apis.h +++ b/source/TR-181/include/vlan_apis.h @@ -38,6 +38,7 @@ #include "vlan_mgr_apis.h" #include "ssp_global.h" #include "secure_wrapper.h" +#include "ethernet_apis.h" /* * Telemetry Markers */ #define VLAN_MARKER_VLAN_IF_CREATE "RDKB_VLAN_CREATE" diff --git a/source/TR-181/middle_layer_src/vlan_internal.c b/source/TR-181/middle_layer_src/vlan_internal.c index 2ebddd0..b851e89 100644 --- a/source/TR-181/middle_layer_src/vlan_internal.c +++ b/source/TR-181/middle_layer_src/vlan_internal.c @@ -35,6 +35,7 @@ #include "vlan_mgr_apis.h" #include "vlan_apis.h" #include "vlan_internal.h" +#include "ethernet_apis.h" #include "plugin_main_apis.h" #include "poam_irepfo_interface.h" #include "sys_definitions.h" From 05ac1e7871f954374d5c472ece7656ee0f4ac410 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 6 Aug 2026 12:35:37 +0000 Subject: [PATCH 10/17] Refactor EthLink_GetMarking to accept PDML_ETHERNET instead of ifname, updating related logic in VLAN interface creation --- source/TR-181/include/ethernet_apis.h | 2 +- .../TR-181/middle_layer_src/ethernet_apis.c | 83 +++++++------------ source/TR-181/middle_layer_src/vlan_apis.c | 24 +++++- 3 files changed, 53 insertions(+), 56 deletions(-) diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index 4da9571..8cfc559 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -259,5 +259,5 @@ void* EthLink_RefreshHandleThread(void *Arg); ANSC_STATUS EthLink_GetMacAddr( PDML_ETHERNET pEntry ); ANSC_STATUS EthLink_SendVirtualIfaceVlanStatus(char *path, char *vlanStatus); ANSC_STATUS DmlEthGetParamValues(char *pComponent, char *pBus, char *pParamName, char *pReturnVal); -ANSC_STATUS EthLink_GetMarking(char *ifname, vlan_configuration_t *pVlanCfg); +ANSC_STATUS EthLink_GetMarking(PDML_ETHERNET pEntry, vlan_configuration_t *pVlanCfg); #endif diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index 73741e0..e726348 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -822,75 +822,56 @@ static ANSC_STATUS EthLink_AddMarking(PDML_ETHERNET pEntry) return ANSC_STATUS_SUCCESS; } -ANSC_STATUS EthLink_GetMarking(char *ifname, vlan_configuration_t *pVlanCfg) +ANSC_STATUS EthLink_GetMarking(PDML_ETHERNET pEntry, vlan_configuration_t *pVlanCfg) { INT iLoopCount = 0; - BOOL Found = FALSE; ANSC_STATUS returnStatus = ANSC_STATUS_FAILURE; - if ((ifname == NULL) || (pVlanCfg == NULL)) + if ((pEntry == NULL) || (pVlanCfg == NULL)) { CcspTraceError(("%s Invalid Memory\n", __FUNCTION__)); return ANSC_STATUS_FAILURE; } - PDATAMODEL_ETHERNET pMyObject = (PDATAMODEL_ETHERNET)g_pBEManager->hEth; - PDML_ETHERNET p_EthLink = NULL; - - if (pMyObject->ulEthlinkInstanceNumber > 0) + if (pEntry != NULL) { - for(iLoopCount = 0; iLoopCount < pMyObject->ulEthlinkInstanceNumber; iLoopCount++) + //Vlan Marking Info + CcspTraceInfo(("%s-%d: NumberofMarkingEntries=%d \n", __FUNCTION__, __LINE__, pEntry->NumberofMarkingEntries)); + if (pEntry->NumberofMarkingEntries > 0) { - p_EthLink = (PDML_ETHERNET)&(pMyObject->EthLink[iLoopCount]); - if (p_EthLink != NULL) + //allocate memory to vlan_skb_config_t, free it once used. + pVlanCfg->skbMarkingNumOfEntries = pEntry->NumberofMarkingEntries; + pVlanCfg->skb_config = (vlan_skb_config_t*)malloc( pEntry->NumberofMarkingEntries * sizeof(vlan_skb_config_t) ); + + if( NULL == pVlanCfg->skb_config ) { - if (strncmp(p_EthLink->Alias, ifname, strlen(ifname)) == 0) - { - Found = TRUE; - break; - } + CcspTraceError(("%s - %d : Invalid SKB priority\n", __FUNCTION__, __LINE__)); + return ANSC_STATUS_FAILURE; } - } - if (Found && (p_EthLink != NULL)) - { - //Vlan Marking Info - CcspTraceInfo(("%s-%d: NumberofMarkingEntries=%d \n", __FUNCTION__, __LINE__, p_EthLink->NumberofMarkingEntries)); - if (p_EthLink->NumberofMarkingEntries > 0) - { - //allocate memory to vlan_skb_config_t, free it once used. - pVlanCfg->skbMarkingNumOfEntries = p_EthLink->NumberofMarkingEntries; - pVlanCfg->skb_config = (vlan_skb_config_t*)malloc( p_EthLink->NumberofMarkingEntries * sizeof(vlan_skb_config_t) ); - if( NULL == pVlanCfg->skb_config ) + for(int i = 0; i < pEntry->NumberofMarkingEntries; i++) + { + PCOSA_DML_MARKING pDataModelMarking = (PCOSA_DML_MARKING)&(pEntry->pstDataModelMarking[i]); + if ((pDataModelMarking != NULL) && (pVlanCfg->skb_config != NULL)) { - CcspTraceError(("%s - %d : Invalid SKB priority\n", __FUNCTION__, __LINE__)); - return ANSC_STATUS_FAILURE; + strncpy(pVlanCfg->skb_config[i].alias, pDataModelMarking->Alias, sizeof(pVlanCfg->skb_config[i].alias) - 1); + pVlanCfg->skb_config[i].skbPort = pDataModelMarking->SKBPort; + pVlanCfg->skb_config[i].skbMark = pDataModelMarking->SKBMark; + pVlanCfg->skb_config[i].skbEthPriorityMark = pDataModelMarking->EthernetPriorityMark; + CcspTraceInfo(("%s-%d: Ins[%d] Alias[%s] SKBPort[%u] SKBMark[%u] EthernetPriorityMark[%d]\n", __FUNCTION__, + __LINE__, (i + 1), pVlanCfg->skb_config[i].alias, pVlanCfg->skb_config[i].skbPort, + pVlanCfg->skb_config[i].skbMark, pVlanCfg->skb_config[i].skbEthPriorityMark )); } - - for(int i = 0; i < p_EthLink->NumberofMarkingEntries; i++) + else { - PCOSA_DML_MARKING pDataModelMarking = (PCOSA_DML_MARKING)&(p_EthLink->pstDataModelMarking[i]); - if ((pDataModelMarking != NULL) && (pVlanCfg->skb_config != NULL)) - { - strncpy(pVlanCfg->skb_config[i].alias, pDataModelMarking->Alias, sizeof(pVlanCfg->skb_config[i].alias) - 1); - pVlanCfg->skb_config[i].skbPort = pDataModelMarking->SKBPort; - pVlanCfg->skb_config[i].skbMark = pDataModelMarking->SKBMark; - pVlanCfg->skb_config[i].skbEthPriorityMark = pDataModelMarking->EthernetPriorityMark; - CcspTraceInfo(("%s-%d: Ins[%d] Alias[%s] SKBPort[%u] SKBMark[%u] EthernetPriorityMark[%d]\n", __FUNCTION__, - __LINE__, (i + 1), pVlanCfg->skb_config[i].alias, pVlanCfg->skb_config[i].skbPort, - pVlanCfg->skb_config[i].skbMark, pVlanCfg->skb_config[i].skbEthPriorityMark )); - } - else - { - CcspTraceError(("%s-%d: pDataModelMarking Or pVlanCfg->skb_config are Null \n", __FUNCTION__, __LINE__)); - free(pVlanCfg->skb_config); - pVlanCfg->skb_config = NULL; - return ANSC_STATUS_FAILURE; - } + CcspTraceError(("%s-%d: pDataModelMarking Or pVlanCfg->skb_config are Null \n", __FUNCTION__, __LINE__)); + free(pVlanCfg->skb_config); + pVlanCfg->skb_config = NULL; + return ANSC_STATUS_FAILURE; } } - returnStatus = ANSC_STATUS_SUCCESS; } + returnStatus = ANSC_STATUS_SUCCESS; } return returnStatus; @@ -915,7 +896,7 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) VlanCfg.VLANId = DEFAULT_VLAN_ID; VlanCfg.TPId = 0; - if (EthLink_GetMarking(pEntry->Alias, &VlanCfg) == ANSC_STATUS_FAILURE) + if (EthLink_GetMarking(pEntry, &VlanCfg) == ANSC_STATUS_FAILURE) { CcspTraceError(("%s Failed to Get Marking, so Can't Create Vlan Interface(%s) \n", __FUNCTION__, pEntry->Alias)); return ANSC_STATUS_FAILURE; @@ -1126,7 +1107,7 @@ static ANSC_STATUS EthLink_TriggerVlanRefresh(PDML_ETHERNET pEntry ) /* TODO: Retry add making if DM gert fails. * Currently we continue to create VLAN link, if Marking get fails to avoid WAN failure. */ - if (EthLink_GetMarking(pEntry->Alias, &VlanCfg) == ANSC_STATUS_FAILURE) + if (EthLink_GetMarking(pEntry, &VlanCfg) == ANSC_STATUS_FAILURE) { CcspTraceError(("%s Failed to Get Marking, Creating Vlan Interface(%s) without marking \n", __FUNCTION__, pEntry->Alias)); } diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 092b48f..9ce0efa 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -556,10 +556,17 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) VlanCfg.VLANId = pEntry->VLANId; VlanCfg.TPId = pEntry->TPId; - if (EthLink_GetMarking(pEntry->Alias, &VlanCfg) == ANSC_STATUS_FAILURE) { - CcspTraceError(("%s Failed to Get Marking, so Can't Create Vlan Interface(%s) \n", __FUNCTION__, pEntry->Alias)); - return ANSC_STATUS_FAILURE; + INT iEthLinkInstance = -1, EthLinkInstance = -1; + if (strlen(pEntry->LowerLayers) > 0) + sscanf(pEntry->LowerLayers, "Device.X_RDK_Ethernet.Link.%d", &iEthLinkInstance); + PDML_ETHERNET pEthLink = (iEthLinkInstance > 0) ? + (PDML_ETHERNET)EthLink_GetEntry(NULL, (iEthLinkInstance - 1), (PULONG)&EthLinkInstance) : NULL; + if (pEthLink == NULL || EthLink_GetMarking(pEthLink, &VlanCfg) == ANSC_STATUS_FAILURE) + { + CcspTraceError(("%s Failed to Get Marking, so Can't Create Vlan Interface(%s) \n", __FUNCTION__, pEntry->Alias)); + return ANSC_STATUS_FAILURE; + } } vlan_eth_hal_createInterface(&VlanCfg); @@ -601,7 +608,16 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) * skbPort would need tc-filter rules and is not set here. */ strncpy(VlanCfg.L3Interface, pEntry->Name, sizeof(VlanCfg.L3Interface) - 1); VlanCfg.VLANId = pEntry->VLANId; - if (EthLink_GetMarking(pEntry->Alias, &VlanCfg) == ANSC_STATUS_SUCCESS) + { + INT iEthLinkInstance = -1, EthLinkInstance = -1; + if (strlen(pEntry->LowerLayers) > 0) + sscanf(pEntry->LowerLayers, "Device.X_RDK_Ethernet.Link.%d", &iEthLinkInstance); + PDML_ETHERNET pEthLink = (iEthLinkInstance > 0) ? + (PDML_ETHERNET)EthLink_GetEntry(NULL, (iEthLinkInstance - 1), (PULONG)&EthLinkInstance) : NULL; + if (pEthLink != NULL) + EthLink_GetMarking(pEthLink, &VlanCfg); + } + if (VlanCfg.skbMarkingNumOfEntries > 0) { /* egress-qos-map reads skb->priority; CLASSIFY --set-class in utopia firewall sets priority=SKBPort */ for (i = 0; i < (INT)VlanCfg.skbMarkingNumOfEntries; i++) From 15e22a5dd296cf82628306009edf58ef67a1860f Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 6 Aug 2026 14:26:54 +0000 Subject: [PATCH 11/17] Remove unused variable iLoopCount from EthLink_GetMarking function --- source/TR-181/middle_layer_src/ethernet_apis.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index e726348..b941b3d 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -824,7 +824,6 @@ static ANSC_STATUS EthLink_AddMarking(PDML_ETHERNET pEntry) ANSC_STATUS EthLink_GetMarking(PDML_ETHERNET pEntry, vlan_configuration_t *pVlanCfg) { - INT iLoopCount = 0; ANSC_STATUS returnStatus = ANSC_STATUS_FAILURE; if ((pEntry == NULL) || (pVlanCfg == NULL)) From 92a470300530ce894888802dcdd4e654df974796 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Tue, 11 Aug 2026 16:56:11 +0000 Subject: [PATCH 12/17] Add EXEC_CMD macro and Vlan_SetTcClassify function for enhanced VLAN interface management --- source/TR-181/include/ethernet_apis.h | 6 ++- .../TR-181/middle_layer_src/ethernet_apis.c | 7 +--- source/TR-181/middle_layer_src/vlan_apis.c | 41 ++++++++++++++++--- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index 8cfc559..700d2df 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -34,7 +34,7 @@ #ifndef _ETHERNET_APIS_H #define _ETHERNET_APIS_H - +#include #include "vlan_mgr_apis.h" #include "ssp_global.h" #include "vlan_eth_hal.h" @@ -260,4 +260,8 @@ ANSC_STATUS EthLink_GetMacAddr( PDML_ETHERNET pEntry ); ANSC_STATUS EthLink_SendVirtualIfaceVlanStatus(char *path, char *vlanStatus); ANSC_STATUS DmlEthGetParamValues(char *pComponent, char *pBus, char *pParamName, char *pReturnVal); ANSC_STATUS EthLink_GetMarking(PDML_ETHERNET pEntry, vlan_configuration_t *pVlanCfg); + +int EthLink_RunCmd(const char *caller, int line, const char *fmt, ...); +#define EXEC_CMD(fmt, ...) EthLink_RunCmd(__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + #endif diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index b941b3d..264d90e 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -98,11 +98,7 @@ extern ANSC_HANDLE g_MessageBusHandle; int sysevent_fd = -1; token_t sysevent_token; -/* - * EthLink_RunCmd - run a shell command, log it and all output (stdout+stderr), - * and return the exit code. Use EXEC_CMD() to auto-inject __FUNCTION__/__LINE__. - */ -static int EthLink_RunCmd(const char *caller, int line, const char *fmt, ...) +int EthLink_RunCmd(const char *caller, int line, const char *fmt, ...) { char cmd[512] = {0}; char redir[544] = {0}; @@ -151,7 +147,6 @@ static int EthLink_RunCmd(const char *caller, int line, const char *fmt, ...) CcspTraceError(("%s-%d: killed by signal %d: %s\n", caller, line, WTERMSIG(status), cmd)); return -1; } -#define EXEC_CMD(fmt, ...) EthLink_RunCmd(__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) static ANSC_STATUS DmlEthSetParamValues(const char *pComponent, char *pBus, char *pParamName, char *pParamVal, enum dataType_e type, unsigned int bCommitFlag); static ANSC_STATUS DmlEthGetParamNames(char *pComponent, char *pBus, char *pParamName, char a2cReturnVal[][256], int *pReturnSize); diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 9ce0efa..6e2dbbc 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -515,6 +515,31 @@ static ANSC_STATUS Vlan_SetMacAddr( PDML_VLAN pEntry ) } #endif + +#ifdef TC_QOS_CLASSIFY +/* Attach clsact egress filters on the VLAN interface. + * fw filters bridge skb->mark -> skb->priority for egress-qos-map, replacing + * iptables CLASSIFY rules. Network control protocols get DATA priority (1). */ +static void Vlan_SetTcClassify(const char *iface) +{ + EXEC_CMD("tc qdisc add dev %s clsact", iface); + /* SKBPort-encoded mark -> egress-qos-map priority key */ + EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x100000 fw mask 0x0ff00000 action skbedit priority 1", iface); + EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x200000 fw mask 0x0ff00000 action skbedit priority 2", iface); + EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x300000 fw mask 0x0ff00000 action skbedit priority 3", iface); + /* ARP: EtherType 0x0806 */ + EXEC_CMD("tc filter add dev %s egress protocol arp prio 2 u32 match u32 0 0 action skbedit priority 1", iface); + /* ICMPv6: IPv6 Next Header field (byte 6) = 0x3a (58) */ + EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u8 0x3a 0xff at 6 action skbedit priority 1", iface); + /* DHCPv4: proto=UDP (0x11), dport=67 (BOOTP server) */ + EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match ip protocol 17 0xff match ip dport 67 0xffff action skbedit priority 1", iface); + /* DHCPv4: proto=UDP (0x11), dport=68 (BOOTP client) */ + EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match ip protocol 17 0xff match ip dport 68 0xffff action skbedit priority 1", iface); + /* DHCPv6: IPv6 nexthdr=0x11 (UDP) at byte 6; dport 546-547 via 0x0222/0xfffe at byte 42 (hdr40+udp_dport2) */ + EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u8 0x11 0xff at 6 match u16 0x0222 0xfffe at 42 action skbedit priority 1", iface); +} +#endif + /********************************************************************** caller: self @@ -593,8 +618,8 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) return ANSC_STATUS_FAILURE; } - v_secure_system("ip link add link %s name %s type vlan id %u", pEntry->Alias, pEntry->Name, pEntry->VLANId); - v_secure_system("ip link set %s up", pEntry->Name); + EXEC_CMD("ip link add link %s name %s type vlan id %u", pEntry->Alias, pEntry->Name, pEntry->VLANId); + EXEC_CMD("ip link set %s up", pEntry->Name); if (Vlan_SetMacAddr(pEntry) == ANSC_STATUS_FAILURE) { @@ -626,10 +651,10 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) __FUNCTION__, __LINE__, pEntry->Name, VlanCfg.skb_config[i].skbPort, VlanCfg.skb_config[i].skbEthPriorityMark)); - v_secure_system("ip link set %s type vlan egress-qos-map %u:%d", - pEntry->Name, - VlanCfg.skb_config[i].skbPort, - VlanCfg.skb_config[i].skbEthPriorityMark); + EXEC_CMD("ip link set %s type vlan egress-qos-map %u:%d", + pEntry->Name, + VlanCfg.skb_config[i].skbPort, + VlanCfg.skb_config[i].skbEthPriorityMark); } if (VlanCfg.skb_config != NULL) { @@ -637,6 +662,10 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) } } +#ifdef TC_QOS_CLASSIFY + Vlan_SetTcClassify(pEntry->Name); +#endif + return returnStatus; } #endif From b91d1c74e6e1c5435e5b364c18524a78f21b9097 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 13 Aug 2026 10:51:43 +0000 Subject: [PATCH 13/17] Enhance Vlan_SetTcClassify function with improved egress filter commands for VLAN interface --- source/TR-181/middle_layer_src/vlan_apis.c | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 6e2dbbc..63ff1fe 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -519,24 +519,25 @@ static ANSC_STATUS Vlan_SetMacAddr( PDML_VLAN pEntry ) #ifdef TC_QOS_CLASSIFY /* Attach clsact egress filters on the VLAN interface. * fw filters bridge skb->mark -> skb->priority for egress-qos-map, replacing - * iptables CLASSIFY rules. Network control protocols get DATA priority (1). */ + * iptables CLASSIFY rules. Network control protocols get DATA priority (1). +*/ static void Vlan_SetTcClassify(const char *iface) { EXEC_CMD("tc qdisc add dev %s clsact", iface); - /* SKBPort-encoded mark -> egress-qos-map priority key */ - EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x100000 fw mask 0x0ff00000 action skbedit priority 1", iface); - EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x200000 fw mask 0x0ff00000 action skbedit priority 2", iface); - EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x300000 fw mask 0x0ff00000 action skbedit priority 3", iface); - /* ARP: EtherType 0x0806 */ + /* SKBPort-encoded mark -> egress-qos-map priority key; mask via HANDLE/MASK fw syntax */ + EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x100000/0x0ff00000 fw action skbedit priority 1", iface); + EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x200000/0x0ff00000 fw action skbedit priority 2", iface); + EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x300000/0x0ff00000 fw action skbedit priority 3", iface); + /* ARP: EtherType 0x0806 - match-all u32 (mask=0 skips value check) */ EXEC_CMD("tc filter add dev %s egress protocol arp prio 2 u32 match u32 0 0 action skbedit priority 1", iface); - /* ICMPv6: IPv6 Next Header field (byte 6) = 0x3a (58) */ - EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u8 0x3a 0xff at 6 action skbedit priority 1", iface); - /* DHCPv4: proto=UDP (0x11), dport=67 (BOOTP server) */ - EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match ip protocol 17 0xff match ip dport 67 0xffff action skbedit priority 1", iface); - /* DHCPv4: proto=UDP (0x11), dport=68 (BOOTP client) */ - EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match ip protocol 17 0xff match ip dport 68 0xffff action skbedit priority 1", iface); - /* DHCPv6: IPv6 nexthdr=0x11 (UDP) at byte 6; dport 546-547 via 0x0222/0xfffe at byte 42 (hdr40+udp_dport2) */ - EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u8 0x11 0xff at 6 match u16 0x0222 0xfffe at 42 action skbedit priority 1", iface); + /* ICMPv6: IPv6 hdr word@4 = [PayloadLen(2)|NextHdr(1)|HopLimit(1)]; NextHdr=0x3a in bits 15:8 */ + EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u32 0x00003a00 0x0000ff00 at 4 action skbedit priority 1", iface); + /* DHCPv4: IP hdr word@8=[TTL|Proto|Cksum]; Proto=0x11; word@20=[UDPsrc|UDPdst]; dport=67 */ + EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match u32 0x00110000 0x00ff0000 at 8 match u32 0x00000043 0x0000ffff at 20 action skbedit priority 1", iface); + /* DHCPv4: same but dport=68 (BOOTP client) */ + EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match u32 0x00110000 0x00ff0000 at 8 match u32 0x00000044 0x0000ffff at 20 action skbedit priority 1", iface); + /* DHCPv6: IPv6 word@4 NextHdr=0x11(UDP); word@40=[UDPsrc|UDPdst]; dport 546-547 via mask 0xfffe */ + EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u32 0x00001100 0x0000ff00 at 4 match u32 0x00000222 0x0000fffe at 40 action skbedit priority 1", iface); } #endif From 60335573ccd8e014180e7b2477ecfbe7cfec0a99 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 13 Aug 2026 12:10:43 +0000 Subject: [PATCH 14/17] Refactor Vlan_SetTcClassify function to simplify egress filter commands and enhance clarity of comments --- source/TR-181/middle_layer_src/vlan_apis.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 63ff1fe..17d454e 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -524,20 +524,12 @@ static ANSC_STATUS Vlan_SetMacAddr( PDML_VLAN pEntry ) static void Vlan_SetTcClassify(const char *iface) { EXEC_CMD("tc qdisc add dev %s clsact", iface); - /* SKBPort-encoded mark -> egress-qos-map priority key; mask via HANDLE/MASK fw syntax */ + /* SKBPort-encoded mark -> egress-qos-map priority key via fw filters with mask */ EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x100000/0x0ff00000 fw action skbedit priority 1", iface); EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x200000/0x0ff00000 fw action skbedit priority 2", iface); EXEC_CMD("tc filter add dev %s egress protocol all prio 1 handle 0x300000/0x0ff00000 fw action skbedit priority 3", iface); - /* ARP: EtherType 0x0806 - match-all u32 (mask=0 skips value check) */ + /* ARP (EtherType 0x0806): match-all gives network control priority via fwmark set in utopia */ EXEC_CMD("tc filter add dev %s egress protocol arp prio 2 u32 match u32 0 0 action skbedit priority 1", iface); - /* ICMPv6: IPv6 hdr word@4 = [PayloadLen(2)|NextHdr(1)|HopLimit(1)]; NextHdr=0x3a in bits 15:8 */ - EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u32 0x00003a00 0x0000ff00 at 4 action skbedit priority 1", iface); - /* DHCPv4: IP hdr word@8=[TTL|Proto|Cksum]; Proto=0x11; word@20=[UDPsrc|UDPdst]; dport=67 */ - EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match u32 0x00110000 0x00ff0000 at 8 match u32 0x00000043 0x0000ffff at 20 action skbedit priority 1", iface); - /* DHCPv4: same but dport=68 (BOOTP client) */ - EXEC_CMD("tc filter add dev %s egress protocol ip prio 2 u32 match u32 0x00110000 0x00ff0000 at 8 match u32 0x00000044 0x0000ffff at 20 action skbedit priority 1", iface); - /* DHCPv6: IPv6 word@4 NextHdr=0x11(UDP); word@40=[UDPsrc|UDPdst]; dport 546-547 via mask 0xfffe */ - EXEC_CMD("tc filter add dev %s egress protocol ipv6 prio 2 u32 match u32 0x00001100 0x0000ff00 at 4 match u32 0x00000222 0x0000fffe at 40 action skbedit priority 1", iface); } #endif From 93016aa0c5df8ccbc732bdea1b5db6eefe238ba0 Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Thu, 13 Aug 2026 14:30:08 +0000 Subject: [PATCH 15/17] Replace v_secure_system calls with EXEC_CMD macro for VLAN interface deletion --- source/TR-181/middle_layer_src/vlan_apis.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 17d454e..884a1cb 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -128,8 +128,8 @@ static ANSC_STATUS Vlan_DeleteInterface(PDML_VLAN p_Vlan) return ANSC_STATUS_FAILURE; } - v_secure_system("ip link set %s down", p_Vlan->Name); - v_secure_system("ip link delete %s", p_Vlan->Name); + EXEC_CMD("ip link set %s down", p_Vlan->Name); + EXEC_CMD("ip link delete %s", p_Vlan->Name); return ANSC_STATUS_SUCCESS; } @@ -737,8 +737,8 @@ void * Vlan_Enable(void *Arg) } else #else - v_secure_system("ip link set %s down", pEntry->Name); - v_secure_system("ip link delete %s",pEntry->Name); + EXEC_CMD("ip link set %s down", pEntry->Name); + EXEC_CMD("ip link delete %s",pEntry->Name); #endif { CcspTraceInfo(("%s - %s:Successfully deleted VLAN interface %s\n", __FUNCTION__, VLAN_MARKER_VLAN_IF_DELETE, pEntry->Name)); From 2c467896ba1b9330ede8899c4b8ad66fbfdfae1d Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Fri, 14 Aug 2026 14:40:28 +0000 Subject: [PATCH 16/17] Refactor VLAN type mappings and update related commands for consistency in untagged VLAN handling --- config/RdkVlanManager.xml | 2 +- docs/vlan-configuration.md | 34 +++--- source/TR-181/include/ethernet_apis.h | 6 +- .../TR-181/middle_layer_src/ethernet_apis.c | 109 +++++++++--------- source/TR-181/middle_layer_src/vlan_apis.c | 2 +- 5 files changed, 78 insertions(+), 75 deletions(-) diff --git a/config/RdkVlanManager.xml b/config/RdkVlanManager.xml index 33879f5..ee94afe 100644 --- a/config/RdkVlanManager.xml +++ b/config/RdkVlanManager.xml @@ -205,7 +205,7 @@ UntaggedVlanType - string: Bridge(0),MacvlanPrivate(1),MacvlanVepa(2),MacvlanBridge(3),MacvlanPassthru(4),MacvlanSource(5),VlanTag0(6),Tagged(7) + string: MacvlanPrivate(0),MacvlanVepa(1),MacvlanBridge(2),MacvlanPassthru(3),MacvlanSource(4),VlanTag0(5),Bridge(6),Tagged(7) uint32/mapped false diff --git a/docs/vlan-configuration.md b/docs/vlan-configuration.md index 2de9ea5..acba1e7 100644 --- a/docs/vlan-configuration.md +++ b/docs/vlan-configuration.md @@ -85,7 +85,7 @@ An untagged WAN over a Linux bridge (default type): ``` psmcli set dmsb.vlanmanager.1.vlanid -1 -psmcli set dmsb.vlanmanager.1.untaggedvlantype 0 # UNTAGGED_SIMPLE_BRIDGE +psmcli set dmsb.vlanmanager.1.untaggedvlantype 6 # UNTAGGED_SIMPLE_BRIDGE psmcli set dmsb.vlanmanager.1.baseinterface eth0 ``` @@ -115,13 +115,13 @@ flowchart TD | Value | Name | Realisation | Kernel command | |-------|------|-------------|----------------| -| 0 | `Bridge` (default) | Linux bridge, base iface enslaved | `brctl addbr` / `addif` | -| 1 | `MacvlanPrivate` | macvlan, endpoints isolated | `ip link add … type macvlan mode private` | -| 2 | `MacvlanVepa` | macvlan, hairpin via external switch | `… mode vepa` | -| 3 | `MacvlanBridge` | macvlan, local forwarding between endpoints | `… mode bridge` | -| 4 | `MacvlanPassthru` | macvlan, single endpoint owns the lower dev | `… mode passthru` | -| 5 | `MacvlanSource` | macvlan, source-MAC filtered | `… mode source` | -| 6 | `VlanTag0` | 802.1Q VLAN with tag id 0 (priority-tagged) | `ip link add … type vlan id 0` | +| 0 | `MacvlanPrivate` (default) | macvlan, endpoints isolated | `ip link add … type macvlan mode private` | +| 1 | `MacvlanVepa` | macvlan, hairpin via external switch | `… mode vepa` | +| 2 | `MacvlanBridge` | macvlan, local forwarding between endpoints | `… mode bridge` | +| 3 | `MacvlanPassthru` | macvlan, single endpoint owns the lower dev | `… mode passthru` | +| 4 | `MacvlanSource` | macvlan, source-MAC filtered | `… mode source` | +| 5 | `VlanTag0` | 802.1Q VLAN with tag id 0 (priority-tagged) | `ip link add … type vlan id 0` | +| 6 | `Bridge` | Linux bridge, base iface enslaved | `brctl addbr` / `addif` | | 7 | `Tagged` | conventional tagged VLAN (display only) | set automatically when `vlanid > 0` | The MACVLAN modes map 1:1 to the kernel `ip-link(8)` macvlan modes. @@ -131,19 +131,19 @@ The MACVLAN modes map 1:1 to the kernel `ip-link(8)` macvlan modes. | Use case | Recommended type | |----------|------------------| | Operator delivers WAN on a **tagged** VLAN | tagged (`vlanid > 0`) | -| Priority-tagged frames (VID 0, PCP set) with QoS | `VlanTag0 (6)` | -| Plain untagged WAN, want a bridge you can add more ports to later | `Bridge (0)` — default | -| Untagged WAN needing its **own MAC** distinct from the base iface, isolated | `MacvlanPrivate (1)` | -| Multiple virtual endpoints that must talk to each other locally | `MacvlanBridge (3)` | -| Deployment behind a VEPA-capable switch (hairpin) | `MacvlanVepa (2)` | -| One endpoint that must fully own the base iface (e.g. move its MAC) | `MacvlanPassthru (4)` | -| Restrict to a fixed allow-list of source MACs | `MacvlanSource (5)` | +| Priority-tagged frames (VID 0, PCP set) with QoS | `VlanTag0 (5)` | +| Plain untagged WAN, want a bridge you can add more ports to later | `Bridge (6)` | +| Untagged WAN needing its **own MAC** distinct from the base iface, isolated | `MacvlanPrivate (0)` — default | +| Multiple virtual endpoints that must talk to each other locally | `MacvlanBridge (2)` | +| Deployment behind a VEPA-capable switch (hairpin) | `MacvlanVepa (1)` | +| One endpoint that must fully own the base iface (e.g. move its MAC) | `MacvlanPassthru (3)` | +| Restrict to a fixed allow-list of source MACs | `MacvlanSource (4)` | Notes: - Only **tagged** and **VlanTag0** interfaces support 802.1p `egress-qos-map`; bridge and macvlan types cannot carry per-priority PCP marking (see the sequence-diagram doc, *Markings*). -- `Bridge (0)` inherits the base interface MAC automatically (kernel sets the +- `Bridge (6)` inherits the base interface MAC automatically (kernel sets the bridge MAC to the lowest enslaved MAC). The macvlan types honour the EthLink `MACAddrOffSet` to derive a distinct MAC. @@ -165,4 +165,4 @@ init and is not writable from the data model — change it via PSM and restart, via boot-time config once available. Mapped string values: -`Bridge(0),MacvlanPrivate(1),MacvlanVepa(2),MacvlanBridge(3),MacvlanPassthru(4),MacvlanSource(5),VlanTag0(6),Tagged(7)` +`MacvlanPrivate(0),MacvlanVepa(1),MacvlanBridge(2),MacvlanPassthru(3),MacvlanSource(4),VlanTag0(5),Bridge(6),Tagged(7)` diff --git a/source/TR-181/include/ethernet_apis.h b/source/TR-181/include/ethernet_apis.h index 700d2df..b0e71bf 100644 --- a/source/TR-181/include/ethernet_apis.h +++ b/source/TR-181/include/ethernet_apis.h @@ -93,11 +93,11 @@ typedef enum { * interface on top of the base interface. * * Values map to the DM parameter UntaggedVlanType (uint32, mapped to string): - * 0=Bridge, 1=MacvlanPrivate, 2=MacvlanVepa, 3=MacvlanBridge, - * 4=MacvlanPassthru, 5=MacvlanSource, 6=VlanTag0, 7=TaggedVlan + * 0=MacvlanPrivate, 1=MacvlanVepa, 2=MacvlanBridge, 3=MacvlanPassthru, + * 4=MacvlanSource, 5=VlanTag0, 6=Bridge, 7=TaggedVlan * * MACVLAN modes correspond exactly to kernel ip-link(8) macvlan modes. - * UNTAGGED_MACVLAN_PRIVATE is the default (used when not otherwise configured). + * UNTAGGED_MACVLAN_PRIVATE (0) is the default — an absent PSM key returns 0. */ typedef enum _UNTAGGED_VLAN_TYPE diff --git a/source/TR-181/middle_layer_src/ethernet_apis.c b/source/TR-181/middle_layer_src/ethernet_apis.c index 264d90e..a9ccbde 100644 --- a/source/TR-181/middle_layer_src/ethernet_apis.c +++ b/source/TR-181/middle_layer_src/ethernet_apis.c @@ -871,6 +871,49 @@ ANSC_STATUS EthLink_GetMarking(PDML_ETHERNET pEntry, vlan_configuration_t *pVlan return returnStatus; } +#if !defined(VLAN_MANAGER_HAL_ENABLED) +static const char * const macvlan_modes[] = { + [UNTAGGED_MACVLAN_PRIVATE] = "private", + [UNTAGGED_MACVLAN_VEPA] = "vepa", + [UNTAGGED_MACVLAN_BRIDGE] = "bridge", + [UNTAGGED_MACVLAN_PASSTHRU] = "passthru", + [UNTAGGED_MACVLAN_SOURCE] = "source", +}; + +static void EthLink_IpLinkCreateMacvlan(const char *base, const char *name, untagged_vlan_type_t type) +{ + const char *mode = ((unsigned)type < sizeof(macvlan_modes)/sizeof(macvlan_modes[0]) && macvlan_modes[type]) + ? macvlan_modes[type] : "private"; + EXEC_CMD("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", + name, name, name); + EXEC_CMD("ip link add link %s name %s type macvlan mode %s", base, name, mode); + EXEC_CMD("ip link set %s allmulticast on", name); + EXEC_CMD("ip link set %s multicast on", name); + EXEC_CMD("ip link set %s mtu 1500", name); +} + +static void EthLink_IpLinkCreateBridge(const char *base, const char *name) +{ + EXEC_CMD("ip link show %s > /dev/null 2>&1 || brctl addbr %s", name, name); + if ((strcmp(base, name) != 0) && (base[0] != '\0')) + EXEC_CMD("brctl addif %s %s", name, base); +} + +static void EthLink_IpLinkDeleteMacvlan(const char *name) +{ + EXEC_CMD("ip link set %s down", name); + EXEC_CMD("ip link delete %s", name); +} + +static void EthLink_IpLinkDeleteBridge(const char *base, const char *name) +{ + if ((strcmp(base, name) != 0) && (base[0] != '\0')) + EXEC_CMD("brctl delif %s %s", name, base); + EXEC_CMD("ifconfig %s down", name); + EXEC_CMD("brctl delbr %s", name); +} +#endif /* !VLAN_MANAGER_HAL_ENABLED */ + static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; @@ -903,60 +946,28 @@ static ANSC_STATUS EthLink_CreateUnTaggedInterface(PDML_ETHERNET pEntry) */ EthLink_CreateBridgeInterface(TRUE); #else - /* - * Consolidated untagged (VLANID <= 0) interface creation. The realisation - * method is selected by pEntry->UnTaggedVlanType, which is handed over from - * the VLAN entry (Vlan_SetEthLink) or loaded from the EthLink defaults. - */ CcspTraceInfo(("%s-%d: Creating untagged interface %s on base interface %s (type=%d, MAC offset=%d)\n", __FUNCTION__, __LINE__, pEntry->Name, pEntry->BaseInterface, pEntry->UnTaggedVlanType, pEntry->MACAddrOffSet)); switch (pEntry->UnTaggedVlanType) { + case TAGGED_VLAN: + /* tagged path handled by vlan_apis.c — nothing to do here */ + break; case UNTAGGED_MACVLAN_PRIVATE: case UNTAGGED_MACVLAN_VEPA: case UNTAGGED_MACVLAN_BRIDGE: case UNTAGGED_MACVLAN_PASSTHRU: case UNTAGGED_MACVLAN_SOURCE: { - /* MACVLAN in the requested kernel mode (ip-link(8) macvlan). */ - const char *macvlanMode; - switch (pEntry->UnTaggedVlanType) - { - case UNTAGGED_MACVLAN_VEPA: macvlanMode = "vepa"; break; - case UNTAGGED_MACVLAN_BRIDGE: macvlanMode = "bridge"; break; - case UNTAGGED_MACVLAN_PASSTHRU: macvlanMode = "passthru"; break; - case UNTAGGED_MACVLAN_SOURCE: macvlanMode = "source"; break; - default: macvlanMode = "private"; break; - } - - /* Delete any pre-existing interface with this name. */ - EXEC_CMD("ip link show %s > /dev/null 2>&1 && (ip link set %s down; ip link delete %s)", - pEntry->Name, pEntry->Name, pEntry->Name); - - /* Create without custom MAC address — MAC is applied uniformly below. */ - EXEC_CMD("ip link add link %s name %s type macvlan mode %s", - pEntry->BaseInterface, pEntry->Name, macvlanMode); - EXEC_CMD("ip link set %s allmulticast on", pEntry->Name); - EXEC_CMD("ip link set %s multicast on", pEntry->Name); - EXEC_CMD("ip link set %s mtu 1500", pEntry->Name); - CcspTraceInfo(("%s-%d: Created MACVLAN(%s) interface %s\n", - __FUNCTION__, __LINE__, macvlanMode, pEntry->Name)); + EthLink_IpLinkCreateMacvlan(pEntry->BaseInterface, pEntry->Name, pEntry->UnTaggedVlanType); break; } case UNTAGGED_SIMPLE_BRIDGE: default: { - /* Default: Linux bridge via brctl. The base interface is enslaved - * to a bridge that carries untagged traffic. */ - EXEC_CMD("ip link show %s > /dev/null 2>&1 || brctl addbr %s", - pEntry->Name, pEntry->Name); - if ((strcmp(pEntry->BaseInterface, pEntry->Name) != 0) && - (pEntry->BaseInterface[0] != '\0')) - { - EXEC_CMD("brctl addif %s %s", pEntry->Name, pEntry->BaseInterface); - } + EthLink_IpLinkCreateBridge(pEntry->BaseInterface, pEntry->Name); CcspTraceInfo(("%s-%d: Created bridge interface %s\n", __FUNCTION__, __LINE__, pEntry->Name)); break; @@ -1010,29 +1021,21 @@ static ANSC_STATUS EthLink_DeleteUnTaggedInterface(PDML_ETHERNET pEntry) switch (pEntry->UnTaggedVlanType) { - case UNTAGGED_SIMPLE_BRIDGE: - default: - { - /* Simple Linux bridge teardown via brctl. */ - if ((strcmp(pEntry->BaseInterface, pEntry->Name) != 0) && - (pEntry->BaseInterface[0] != '\0')) - { - EXEC_CMD("brctl delif %s %s", pEntry->Name, pEntry->BaseInterface); - } - EXEC_CMD("ifconfig %s down", pEntry->Name); - EXEC_CMD("brctl delbr %s", pEntry->Name); + case TAGGED_VLAN: break; - } - case UNTAGGED_MACVLAN_PRIVATE: case UNTAGGED_MACVLAN_VEPA: case UNTAGGED_MACVLAN_BRIDGE: case UNTAGGED_MACVLAN_PASSTHRU: case UNTAGGED_MACVLAN_SOURCE: { - /* macvlan and vlan tag-0 devices are removed with ip link. */ - EXEC_CMD("ip link set %s down", pEntry->Name); - EXEC_CMD("ip link delete %s", pEntry->Name); + EthLink_IpLinkDeleteMacvlan(pEntry->Name); + break; + } + case UNTAGGED_SIMPLE_BRIDGE: + default: + { + EthLink_IpLinkDeleteBridge(pEntry->BaseInterface, pEntry->Name); break; } } diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 884a1cb..632c147 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -611,7 +611,7 @@ static ANSC_STATUS Vlan_CreateTaggedInterface(PDML_VLAN pEntry) return ANSC_STATUS_FAILURE; } - EXEC_CMD("ip link add link %s name %s type vlan id %u", pEntry->Alias, pEntry->Name, pEntry->VLANId); + EXEC_CMD("ip link add link %s name %s type vlan id %u", pEntry->BaseInterface, pEntry->Name, pEntry->VLANId); EXEC_CMD("ip link set %s up", pEntry->Name); if (Vlan_SetMacAddr(pEntry) == ANSC_STATUS_FAILURE) From 5ad973f37e992ea96231ec32f5748c4c2ae9535c Mon Sep 17 00:00:00 2001 From: Parthiban Selvaraj Date: Mon, 17 Aug 2026 11:28:52 +0000 Subject: [PATCH 17/17] Update Vlan_Disable to conditionally set priTag for EthLink based on VLANId and UnTaggedVlanType --- source/TR-181/middle_layer_src/vlan_apis.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/TR-181/middle_layer_src/vlan_apis.c b/source/TR-181/middle_layer_src/vlan_apis.c index 632c147..40587b8 100644 --- a/source/TR-181/middle_layer_src/vlan_apis.c +++ b/source/TR-181/middle_layer_src/vlan_apis.c @@ -368,7 +368,9 @@ void * Vlan_Disable(void *Arg) pthread_mutex_lock(&vlan_access_mutex); //Set EthLink to False. it will take care UnTagged Created Vlan Interface - if (Vlan_SetEthLink(pEntry, FALSE, FALSE) == ANSC_STATUS_FAILURE) + + BOOL priTag = (pEntry->VLANId > 0 || pEntry->UnTaggedVlanType == UNTAGGED_VLAN_TAG_0) ? TRUE : FALSE; + if (Vlan_SetEthLink(pEntry, FALSE, priTag) == ANSC_STATUS_FAILURE) { CcspTraceError(("%s-%d: Failed to Disable EthLink\n", __FUNCTION__, __LINE__)); }