一、背景描述
某系列产品中,不同产品、国家和地区支持不同的配置项(但差异不大)。各配置项均由其BranchLeaf结点值(BLV)唯一标识。
作为ONU通用配置媒介之一,某模块对各配置项创建合法性校验函数IsBranchLeafValid(…),其中包含的结点列表表示产品缺省支持的所有配置项,类似“白名单”;此外根据各国家地区的要求创建屏蔽函数IsBranchLeafScreened
(…),其中包含的结点列表表示该国家/地区不予支持的配置项,类似“黑名单”。其中,“黑名单”列表为“白名单”列表的子集。两个名单结合起来对接收到的OLT配置帧进行校验,从而表现出不同的支持能力。
因此,对于M个产品,N个国家地区,在物理上将需要M+N个黑白名单。具体实现上,黑白名单函数内充斥着大量if...else与switch...case结构:
1 /* 每个产品对应一个Product_Adapter.c文件,内含IsBranchLeafValid实现 */
2 BOOL IsBranchLeafValid(OAM_BRANCH_LEAF eBranchLeaf)
3 {
4 BOOLEAN retcode = 1;
5 switch(eBranchLeaf)
6 {
7 case OnuSn:
8 case FirmwareVer:
9 case ChipsetID:
10 case EthDSRateLimit:
11 case QosConfig:
12 case FastLeaveState:
13 case FastLeaveCtrl:
14 case FaxModemConf:
15 case SIPDigitMap:
16 //Dozens of eBranchLeaf... ...
17 {
18 retcode = 1;
19 }
20 break;
21
22 default:
23 {
24 retcode = 0;
25 }
26 break;
27 }
28
29 return retcode;
30 }
31
32
33 BOOL IsBranchLeafScreened(INT32U dwdwdwRegionVer, OAM_BRANCH_LEAF eBranchLeaf)
34 {
35 if(dwdwRegionVer == DEFAULT_XINJIANG_CFG)
36 {
37 switch(eBranchLeaf)
38 {
39 case VlanConfig:
40
41 case FaxModemConf:
42 case SIPDigitMap:
43 //Dozens of eBranchLeaf... ...
44 return 1;
45 default:
46 return 0;
47 }
48 }
49 else if(dwdwRegionVer == DEFAULT_JIANGSU_CFG)
50 {
51 switch(eBranchLeaf)
52 {
53 case VlanConfig:
54 return 1;
55 default:
56 return 0;
57 }
58 }
59 else
60 {
61 return 0;
62 }
63 }
后续若增加其他产品、国家和地区,需要不断增加文件或扩展函数。此外,各名单的BLV列表内容互有重叠,代码冗余度很高。
二、改进方案
定义产品、国家、地区掩码,掩码中各比特表示某BLV的相应产品、国家和地区支持情况。这里将国家和地区分开是为了扩展掩码支持范围。
例如下面的简化格式(前两比特表示产品支持,后两比特表示地区支持):
对于某BLV,上面的0b‘1001表示F420V2上海版本支持该配置项,以此类推。
这样就无需IsBranchLeafScreened和IsBranchLeafValid黑白名单函数,校验时只需根据掩码对应比特(偏移)来判断相应的BLV是否支持。
对于产品掩码,可在预编译阶段设置掩码偏移值;对于国家和地区,可在ONU启动初始化时通过查询国家地区码来设置掩码偏移值。
三、实践情况
目前已定义的EPON
SFU产品有F420V2/F411V2/F420G/F400G/F1420/F460/F460V2/F460M等等,国家地区码(非指本文“掩码”)如下:
1 /* 国家码 */
2 #define DEFAULT_CFG 0 /* 基本默认配置文件 */
3 #define DEFAULT_RUSSIA_CFG 1 /* 俄罗斯默认配置文件 */
4 #define DEFAULT_LITHUANIA_CFG 2 /* 立陶宛默认配置文件 */
5 //… …
6
7 /* 地区码 */
8 #define DEFAULT_JIANGSU_CFG 200 /* 江苏省默认配置文件 */
9 #define DEFAULT_XINJIANG_CFG 201 /* 新疆默认配置文件 */
10 #define DEFAULT_HAINAN_CFG 202 /* 海南默认配置文件 */
11 #define DEFAULT_TIANJIN_CFG 203 /* 天津默认配置文件 */
12 #define DEFAULT_ANHUI_CFG 204 /* 安徽默认配置文件 */
13 #define DEFAULT_SHANGHAI_CFG 205 /* 上海默认配置文件 */
14 //… …
因此,可将产品掩码定义为1字节,掩码偏移比特定义如下:
1 /*ONU产品掩码定义(根据新增产品而扩展)*/
2 #if defined(CONFIG_CSP_PRODUCT_F411) || defined(CONFIG_CSP_PRODUCT_F420) || defined(CONFIG_CSP_PRODUCT_F420G)
3 #define PRODUCT_SHIFT 0
4 #elif defined(CONFIG_CSP_PRODUCT_F400G)
5 #define PRODUCT_SHIFT 1
6 #elif defined(CONFIG_CSP_PRODUCT_F1420)
7 #define PRODUCT_SHIFT 2
8 #else
9 #define PRODUCT_SHIFT 3
10 #endif
国家掩码定义为4字节长整型,从低位到高位依次对应国家码编号,即掩码bit-0表示缺省版本支持情况(恒为1),bit-1表示俄罗斯版本支持情况;地区掩码与国家掩码类似,应注意掩码bit-0恒为1以避免与国家掩码冲突(只能有一个缺省版本),bit-1表示江苏版本支持情况。国家、地区掩码偏移比特定义如下:
1 VOID GetRegionMask(INT32U dwRegionVer, INT8U *pucNatShift, INT8U *pucRegShift)
2 {
3 if(dwRegionVer < DEFAULT_JIANGSU_CFG)
4 *pucNatShift = dwRegionVer;
5 else
6 *pucRegShift = dwRegionVer - 199;
7 }
具体掩码结构如下OAM_CMD_MAP结构定义如下图所示:
1 typedef FUNC_STATUS(*OAM_GET_CMD_HANDLER)(OAM_HEAD_INFO*, INT8U*, INT32U*, CTC_OAM_ACK*);
2 typedef FUNC_STATUS(*OAM_SET_CMD_HANDLER)(OAM_HEAD_INFO*, INT8U*, INT32U*, CTC_OAM_ACK*);
3 typedef struct{
4 OAM_BRANCH_LEAF eBranchLeaf;
5 INT8U ucProductMask;
6 INT32U dwNationMask;
7 INT32U dwRegionMask;
8 OAM_GET_CMD_HANDLER fnGetCmdHandler;
9 OAM_SET_CMD_HANDLER fnSetCmdHandler;
10 }OAM_CMD_MAP;
11
12 #define DEF_8U 0xFF
13 #define DEF_32U 0xFFFFFFFF
14 #define GC(NAME) OAM_##NAME##_Get_Cmd
15 #define SC(NAME) OAM_##NAME##_Set_Cmd
16
17 /*OAM命令处理函数映射表 */
18 OAM_CMD_MAP gOamCmdFuncMap[] = {
19 {OnuSn, DEF_8U, DEF_32U, DEF_32U, GC(ONU_SN), NULL},
20 {FirmwareVer, DEF_8U, DEF_32U, DEF_32U, GC(FirmwareVer), NULL},
21 {ChipsetID, DEF_8U, DEF_32U, DEF_32U, GC(ChipsetID), NULL},
22 {EthDSRateLimit, DEF_8U, DEF_32U, DEF_32U, GC(EthDSRateLimit), SC(EthDSRateLimit)},
23 {QosConfig, DEF_8U, DEF_32U, DEF_32U, GC(QosConfig), SC(QosConfig)},
24 {FastLeaveState, DEF_8U, DEF_32U, 0xFFFFFFBF, GC(FastLeaveState), NULL},
25 {FastLeaveCtrl, DEF_8U, DEF_32U, 0xFFFFFFBF, NULL, SC(FastLeaveCtrl)},
26 {FaxModemConf, 0xFD, DEF_32U, 0xFFFFFFBD, GC(FaxModemConf), SC(FaxModemConf)},
27 {SIPDigitMap, 0xFD, DEF_32U, 0xFFFFFFBB, NULL, SC(SIPDigitMap)},
28 //... ...
29 };
30 const INT32U gOamCmdMapNum = sizeof(gOamCmdFuncMap) / sizeof(OAM_CMD_MAP);
其中,第一列为BLV结点值,第2~4列分别为产品、国家、地区掩码,后2列为处理函数指针。
例如。BranchLeaf名FaxModemConf对应的地区掩码为0xFFFFFFBD(1...10111101)表示江苏省和上海地区不支持该配置项。产品掩码含义与之类似。校验时黑白名单由下面的函数代替:
1 BOOL IsBranchLeafSupported(OAM_BRANCH_LEAF eBranchLeaf)
2 {
3 INT32U dwMapIdx = 0;
4 for(dwMapIdx = 0; dwMapIdx < gOamCmdMapNum; dwMapIdx++)
5 {
6 if(eBranchLeaf == gOamCmdFuncMap[dwMapIdx].eBranchLeaf)
7 break;
8
9 }
10 if(dwMapIdx == gOamCmdMapNum)
11 {
12 CtcOamLog(FUNCTION_Oam,"Unknown BranchLeaf(0x%08X)!\n", eBranchLeaf);
13 return FALSE;
14 }
15
16 if(GET_BIT(gOamCmdFuncMap[dwMapIdx].ucProductMask, PRODUCT_SHIFT) //也可先&&后GET_BIT
17 && GET_BIT(gOamCmdFuncMap[dwMapIdx].dwNationMask, gdwRegionVer.ucNatShift)
18 && GET_BIT(gOamCmdFuncMap[dwMapIdx].dwRegionMask, gdwRegionVer.ucRegShift))
19 return TRUE;
20
21 return FALSE;
22 }
四、总结说明
1. 采用掩码的表示方法,可极大地消除冗余度和增强扩展性。
可支持10个产品、32个国家及31个地区的不同配置能力,已支持5个产品、1个国家(缺省)和两个地区,后续新增产品、国家、地区只需要修改掩码值即可,无需增加代码。
2.
相比原有做法,掩码方式在可读性和易用性方面稍嫌不足,可编写掩码的生成和解析函数或工具予以弥补。
采用掩码方式简化产品国家地区支持能力的表示,布布扣,bubuko.com