20170216_jeffrey - silenceuncrio/diary GitHub Wiki

0925

review

計畫永遠趕不上變化

昨天聽 ariel 說公司一月份虧了 一百多萬

M300 要能換錢回來

昨天來的印度客戶至少就是個相對實際的需求

先就下面這四個我來負責的項目 google 一下

  • DMZ
  • UPnP (IPv4v6)
  • RIP
  • OSPF

1330

ariel 表示 OSPF 不做了

要改用 BGP 來取代 OSPF

參考 動態路由協議全方位比較:RIPv2、EIGRP、OSPF、BGP 原文網址:https://read01.com/0jay5D.html

得知我原本要實作的 RIP, OSPF 其實角色都是相當的

ariel 告知的只是 印度客戶 比較 prefer BGP, 而不是 OSPF

google 到了 Quagga Routing Suite

Quagga is a routing software suite, providing implementations of OSPFv2, OSPFv3, RIP v1 and v2, RIPng and BGP-4 for Unix platforms, particularly FreeBSD, Linux, Solaris and NetBSD. Quagga is a fork of GNU Zebra which was developed by Kunihiro Ishiguro. The Quagga tree aims to build a more involved community around Quagga than the current centralised model of GNU Zebra.

一次解決 RIP, BGP

YOCTO 裡也有 quagga 這個 recipe

1415

目前想到的工作節奏是這樣

先透過 Web server with HTTPS 來熟悉 M300 上的 icos 架構

然後可以先做 DMZUPNP

公司的其他案子有已經完工的 icos module 可以參考

例如 579X

RIPBGP 雖然在 YOCTOquagga recipe 有提供

但這個工作項目相對複雜 - 需要新增相對應的 icos module

所以工作項目的實作順序是這樣

  1. Web server with HTTPS
  2. DMZ
  3. UPnP (IPv4v6)
  4. RIP
  5. BGP

1425

Web server with HTTPS 出發

好好地 trace webcfg.c 來打個底

先看一下 web 這個所謂的 icos module 長甚麼樣

sIcosModule webModule={
    "web",                        // Name
    InitWeb,                      // Init
    ExitWeb,                      // Exit
    ApplyWebSetting,              // Apply
    GetWebSetting,                // GetSetting
    SetWebSetting,                // SetSetting
    VerifyWebSetting,             // VerifySetting
    0,                            // GetStatus
    0,                            // GetStatus
    facotry_default_web_setting,
    0,//period_ddns,
    notify_web,
    msgcb_web,
    termcb_web,
};

我們需要參考 sIcosModule 這個型態的定義

typedef struct sIcosModule_t
{
    char*  szName;                          // module name
    int    (*Init)  (char *pCfgStr);        // module init
    int    (*Exit)  (char *pCfgStr);        // module exit

    int    (*Apply) (int flag, int index, void* pStruct, int structSize);           // Apply  Setting and Save setting to /ETC
    int    (*GetSetting)   (int flag, int index, void* pStruct, int structSize);    // Load   Setting to pStruct
    int    (*SetSetting)   (int flag, int index, void* pStruct, int structSize);    // Save   Setting to Memory only
    int    (*VerifySetting)(int flag, int index, void* pStruct, int structSize);    // Verify Setting is correct or not ?
    int    (*GetStatus)    (int flag, int index, void* pStruct, int structSize);    // Get        Status to pStruct
    int    (*Str2Value)    (int attID, char *pAttValue, int *pValue);               // String to value conversion
    int    (*Factory)      (void);                                                  // Facotry To Default
    int    (*PeriodHandle) (void); // Ariel: only Called in icospromsg
    int    (*NotifyHandler)(PRO_EVENT *pevent); // Ariel: only Called in icospromsg
    int    (*proc_msg_cb)  (char *msg, pid_t pid, int rc);  // redirect process stdout into module call back
    int    (*proc_term_cb) (char *msg, pid_t pid);  // process terminate callback
} sIcosModule;

1435

先來看 Init 這個 callback function 是怎麼被觸發的

這需要說到 icos 這東西是如何被啟動的

M300 開機時會執行 /etc/rc.local 這個 shell script

/etc/rc.local 裡會去執行 /usr/sbin/icosconfig bootinit

看到 icosconfig 這個可執行檔的 source code

/usr/sbin/icosconfig bootinit 所觸發的是 ICOS_Bootinit()

entry.c

#define icos_module_name_foreach(id, name) \
    const char *name;\
    int id; \
    for (int keep = 1, count = 0; keep && count < dim(moduleInitAry); keep = !keep, count++) \
        for (name = moduleInitAry[count].pString, \
                id = moduleInitAry[count].value; keep; keep = !keep)

sAttStringSet moduleInitAry[] =
{
    { "MODULE_SYSTEM", MODULE_SYSTEM },
    ...
    { "MODULE_WEB", MODULE_WEB },
    ...
};

sIcosModule* GetIcosModule(int module)
{
    switch (module)
    {
        ...
        case MODULE_WEB:
            return &webModule;
        ...
    }
    eprintf(" module(id:%d) module mapping not exist!\n", module);
    return 0;
}

int _icos_module_init_foreach(int bShowInfo)
{
    ...
    icos_module_name_foreach(module_id, name)
    {
        pIcosModule=GetIcosModule(module_id);
        if (pIcosModule==0) continue;
        ...
        if (pIcosModule->Init)
        {
            res=pIcosModule->Init(szCfgStr);
            if (res<0) printf(" Error: Module %s cfg init failure\n", pIcosModule->szName);
            szCfgStr[module_id]='1';
        }
    }

    return res;
}

int   ICOS_Bootinit(void)
{
    ...
    // =============================================================================
    // |  init modules
    // =============================================================================
    _icos_module_init_foreach(1);
    ...
}

icos_module.h

extern int ICOS_Bootinit(void);

icosmain.c

int    main(int argc, char *argv[])
{
    ...
    if (!strcmp(argv[1], "bootinit"))
    {
        res=ICOS_Bootinit();
    }
    ...
}

從 source code 來看

ICOS_Bootinit() 便會把 webModuleInitWeb() 叫起來

1455

回到 sIcosModule 這個型態所定義的 Exit()

entry.c

int _icos_module_exit_foreach(int bShowInfo)
{
    for (; i >= 0; i--)
    {
        int module_id = moduleInitAry[i].value;
        pIcosModule=GetIcosModule(module_id);
        if (pIcosModule->Exit)
        {
            res=pIcosModule->Exit(szCfgStr);
        }
    }
}

int     ICOS_Shutdown(void)
{
    ...
    _icos_module_exit_foreach(1);
    ...
}

int    ICOS_WarmReboot(int bShowInfo)
{
    ...
    // =============================================================================
    // |  exit modules
    // =============================================================================
    _icos_module_exit_foreach(1);
    ...
}

ICOS_Shutdown() 可由 /usr/sbin/icosconfig shutdown 這命令所觸發

ICOS_WarmReboot() 則是由 /usr/sbin/icosconfig warmreboot 這命令所觸發

這兩者最終都會導致 webModuleExitWeb() 被叫起來

1505

來看 sIcosModule 型態定義的 Apply()

typedef struct sIcosModule_t
{
    int    (*Apply) (int flag, int index, void* pStruct, int structSize);           // Apply  Setting and Save setting to /ETC
} sIcosModule;

entry.c

int    ICOS_Apply(int module, int flag, int index, void* pStruct, int structSize)
{
    ...
    pIcosModule=GetIcosModule(module);
    ...
    res=pIcosModule->Apply(flag, index, pStruct, structSize);
    ...
    return res;
}

icos_module.h

extern int ICOS_Apply        (int module, int flag, int index, void* pStruct, int structSize);

我們若把 icos 當作是個 library 的話

ICOS_Apply() 這個 API 帶入 MODULE_WEB 這個 module 參數

便會呼叫到 webModuleApplyWebSetting()

1520

來看 sIcosModule 型態定義的 GetSetting()

typedef struct sIcosModule_t
{
    int    (*GetSetting)   (int flag, int index, void* pStruct, int structSize);    // Load   Setting to pStruct
} sIcosModule;

entry.c

int   ICOS_GetSetting(int module, int flag, int index, void* pStruct, int structSize)
{
    sIcosModule *pIcosModule;
    pIcosModule=GetIcosModule(module);
    if (pIcosModule==0) return ICOS_FAILURE;

    if (pIcosModule->GetSetting==0)
    {
        eprintf(" module(id:%d) func GetSetting not exist!\n", module);
        return ICOS_FAILURE;
    }
    return pIcosModule->GetSetting(flag, index, pStruct, structSize);
}

icos_module.h

extern int ICOS_GetSetting   (int module, int flag, int index, void* pStruct, int structSize);

我們若把 icos 當作是個 library 的話

ICOS_GetSetting() 這個 API 帶入 MODULE_WEB 這個 module 參數

便會呼叫到 webModuleGetWebSetting()

1550

來看 sIcosModule 型態定義的 SetSetting()

typedef struct sIcosModule_t
{
    int    (*SetSetting)   (int flag, int index, void* pStruct, int structSize);    // Save   Setting to Memory only
} sIcosModule;

entry.c

int    ICOS_SetSetting(int module, int flag, int index, void* pStruct, int structSize)
{
    sIcosModule *pIcosModule;

    pIcosModule=GetIcosModule(module);
    if (pIcosModule==0) return ICOS_FAILURE;
	
    if (CheckIgnoredModules(pIcosModule->szName))  return ICOS_FAILURE; //John20161215

    if (pIcosModule->SetSetting==0)
    {
        eprintf(" module(id:%d) func SetSetting not exist!\n", module);
        return ICOS_FAILURE;
    }
    return pIcosModule->SetSetting(flag, index, pStruct, structSize);
}

icos_module.h

extern int ICOS_SetSetting   (int module, int flag, int index, void* pStruct, int structSize);

我們若把 icos 當作是個 library 的話

ICOS_SetSetting() 這個 API 帶入 MODULE_WEB 這個 module 參數

便會呼叫到 webModuleSetWebSetting()

1610

morris 進行 靜電 相關的測試後告知結果還算滿意

這表示我已經可以做 commit 的動作了

  • uboot env verion - 1.2
    • correct the GPIO setting for ethernet 1 and ethernet 2
    • add some dummy uboot env to try to protect important uboot env

1620

繼續看 sIcosModule 型態定義的 VerifySetting()

typedef struct sIcosModule_t
{
    int    (*VerifySetting)(int flag, int index, void* pStruct, int structSize);    // Verify Setting is correct or not ?
} sIcosModule;

entry.c

int    ICOS_VerifySetting(int module, int flag, int index, void* pStruct, int structSize)
{
    sIcosModule *pIcosModule;

    pIcosModule=GetIcosModule(module);
    if (pIcosModule==0) return ICOS_FAILURE;

    if (pIcosModule->VerifySetting==0)
    {
        eprintf(" module(id:%d) func VerifySetting not exist!\n", module);
        return ICOS_FAILURE;
    }
    return pIcosModule->VerifySetting(flag, index, pStruct, structSize);
}

icos_module.h

extern int ICOS_VerifySetting(int module, int flag, int index, void* pStruct, int structSize);

我們若把 icos 當作是個 library 的話

ICOS_VerifySetting() 這個 API 帶入 MODULE_WEB 這個 module 參數

便會呼叫到 webModuleVerifyWebSetting()

1625

繼續看 sIcosModule 型態定義的 GetStatus()

typedef struct sIcosModule_t
{
    int    (*GetStatus)    (int flag, int index, void* pStruct, int structSize);    // Get        Status to pStruct
} sIcosModule;

entry.c

int    ICOS_GetStatus(int module, int flag, int index, void* pStruct, int structSize)
{
    sIcosModule *pIcosModule;
    pIcosModule=GetIcosModule(module);
    if (pIcosModule==0) return ICOS_FAILURE;

    if (pIcosModule->GetStatus==0)
    {
        eprintf(" module(id:%d) func GetStatus not exist!\n", module);
        return ICOS_FAILURE;
    }
    return pIcosModule->GetStatus(flag, index, pStruct, structSize);
}

icos_module.h

extern int ICOS_GetStatus    (int module, int flag, int index, void* pStruct, int structSize);

ICOS_GetStatus() 這個 API 帶入 MODULE_WEB 這個 module 參數

並不會呼叫到 webModule 的任何 function

sIcosModule webModule={
    "web",                        // Name
    ...
    0,                            // GetStatus
    ...
};

1630

sIcosModule 型態定義的 Str2Value()

typedef struct sIcosModule_t
{
    int    (*Str2Value)    (int attID, char *pAttValue, int *pValue);               // String to value conversion
} sIcosModule;

entry.c

int ICOS_CheckStr2Value(int module, sIcosModule **pModule)
{
    //LDBG(DBG_INFO, "\n");
    *pModule = GetIcosModule(module);
    if (*pModule==0) return ICOS_FAILURE;

    // check if String to Value callback defined or not?
    if ((*pModule)->Str2Value==0)
    {
        LDBG(DBG_INFO, " module(id:%d) func Str2Value() not defined!\n", module);
        return ICOS_FAILURE;
    }
    return ICOS_SUCCESS;
}

icos_module.h

extern int ICOS_CheckStr2Value(int module, sIcosModule **pModule);

ICOS_GetStatus() 這個 API 帶入 MODULE_WEB 這個 module 參數

並不會呼叫到 webModule 的任何 function

sIcosModule webModule={
    "web",                        // Name
    ...
    0,
    ...
};

因為 webModule 並沒有準備相對應的 function 給 sIcosModule 型態裡的 Str2Value() function poionter

1635

來看 sIcosModule 型態定義的 Factory()

typedef struct sIcosModule_t
{
    int    (*Factory)      (void);                                                  // Facotry To Default
} sIcosModule;

目前沒有任何 export 出去的 API 會使用到

所以 webModulefacotry_default_web_setting 並不會有透過 API 被叫起來的 情況

1640

來看 sIcosModule 型態定義的 PeriodHandle()

typedef struct sIcosModule_t
{
    int    (*PeriodHandle) (void); // Ariel: only Called in icospromsg
} sIcosModule;

entry.c

int PeriodHandle(void)
{
    int res;
    sIcosModule *pIcosModule;

    icos_module_name_foreach(module_id, name)
    {
        pIcosModule=GetIcosModule(module_id);
        if (pIcosModule==0)
        {
            //CPRT("!!!No module(idx=%d)\n", module_id);
            continue;
        }
        if (CheckIgnoredModules(pIcosModule->szName))
        {
            //CPRT("!!!IgnoredModule(Name=%s)\n", pIcosModule->szName);
            continue;
        }
        if (pIcosModule->PeriodHandle)
        {
            CPRT("Process Module %s PeriodHandle()\n", pIcosModule->szName);
            res=pIcosModule->PeriodHandle();
            if (res<0) CPRT(" Error: Module %s PeriodHandle\n", pIcosModule->szName);
        }
    }

    return ICOS_SUCCESS;
}

雖然 webModule 並沒有準備相對應的 function 給 sIcosModule 型態裡的 PeriodHandle() function poionter

不過我們還是來追看看誰會呼叫 entry.cPeriodHandle()

答案是 /usr/sbin/icospromsg

1650

來看 /usr/sbin/icospromsg 的 source code

icospromsg.c

int main(int argc, char **argv)
{

    while (!G_loop_exit)
    {
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        ...
        sel_ret=0;
        sel_ret=select(maxfd+1, &rdset, 0, 0, &timeout);
        if(G_loop_exit)
            break;
        if (sel_ret > 0)
        {
            ...
        }
        else if (sel_ret == 0) //Timeout
        {
            //PRO_PRT("Call PeriodHandle()\n");
            PeriodHandle();
            TimerTS=time(0);
        }
        //PRO_PRT("Call PS_watchdog()\n");
        PS_watchdog();
    }//End_while
    ...
}

簡單來說就是一旦 /usr/sbin/icospromsg 被執行便會在

icospromsg.cmain()while 作 loop

然後每一秒會呼叫一次 PeriodHandle()

1700

來看 sIcosModule 型態定義的 NotifyHandler()

typedef struct sIcosModule_t
{
    int    (*NotifyHandler)(PRO_EVENT *pevent); // Ariel: only Called in icospromsg
} sIcosModule;

entry.c

int BroadcastHandle(PRO_EVENT *pmsg)
{
    int res=0;

    icos_module_foreach(pIcosModule)
    {
        if (pIcosModule==0) continue;
        if (CheckIgnoredModules(pIcosModule->szName))
        {
            continue;
        }
        if (pIcosModule->NotifyHandler)
        {
            CPRT("Process Module %s BroadcastHandle()\n", pIcosModule->szName);
            res=pIcosModule->NotifyHandler(pmsg);
        }
    }
    return res;
}

除了 icos 的 library 之外還要看到 可執行檔 /usr/sbin/icospromsg 的 source code

int main(int argc, char **argv)
{
    ...
    while (!G_loop_exit)
    {
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        ...
        sel_ret=0;
        sel_ret=select(maxfd+1, &rdset, 0, 0, &timeout);

        if (sel_ret > 0)
        {
            // Check Events
            if (FD_ISSET(usfd, &rdset))
            {
                PRO_EVENT *pmsg=NULL;
                unsigned char *sp=msg_buffer;
                read_bytes = recv(usfd, sp, sizeof(PRO_EVENT),MSG_DONTWAIT | MSG_NOSIGNAL);
                pmsg = (PRO_EVENT*)sp;
                ...
                if (pmsg->dst_id == 0) // 0: means broadcast
                {
                    BroadcastHandle(pmsg);
                }
                else
                {
                    NotifyHandle(pmsg);
                }
            }
            ProcMsgHandler(&rdset);
        }
        ...
    }//End_while
    ...
}

一旦 /usr/sbin/icospromsg 被執行便會在

icospromsg.cmain()while 作 loop

一旦收到 PRO_EVENT message 的話

便依據 dst_id 來決定是呼叫 BroadcastHandle() 還是 NotifyHandle()

試情況 webModulenotify_web() 便會被呼叫了

注意到不管是 BroadcastHandle() 還是 NotifyHandle()

都需要再呼叫 ProcMsgHandler()

先不追 ProcMsgHandler()

1720

來看 sIcosModule 型態定義的 proc_msg_cb()

typedef struct sIcosModule_t
{
    int    (*proc_msg_cb)  (char *msg, pid_t pid, int rc);  // redirect process stdout into module call back
} sIcosModule;

icos_process.c

int ProcMsg(int module_id, char *msg, pid_t pid, int rc)
{
    ...
    pIcosModule=GetIcosModule(module_id);

    if (pIcosModule->proc_msg_cb)
    {
        res=pIcosModule->proc_msg_cb(msg, pid, rc);
    }
    return res;
}

void ProcMsgHandler(fd_set *readfds)
{
    ...
    while (ps_ctx)
    {
        if (ps_ctx->ptyfd > 0 && FD_ISSET(ps_ctx->ptyfd, readfds) )
        {
            rc=read(ps_ctx->ptyfd, buf, MSG_LEN-1);
            if (rc>0)
            {
                buf[rc]='\0';
                ProcMsg(ps_ctx->module_id, buf, ps_ctx->pid, rc);
            }
        }
        ps_ctx = ps_ctx->next;
    }
}

這邊的 ProcMsgHandler() 便和前頭的 BroadcastHandle()NotifyHandle() 串起來了

也就是試情況 webModulenotify_web() 被呼叫後 就換 msgcb_web() 被叫起來做事

1730

來看 sIcosModule 型態定義的 proc_term_cb()

typedef struct sIcosModule_t
{
    int    (*proc_term_cb) (char *msg, pid_t pid);  // process terminate callback
} sIcosModule;

icos_process.c

int ProcTerminate(int module_id, char *msg, pid_t pid)
{
	sIcosModule *pIcosModule;
	pIcosModule=GetIcosModule(module_id);
	int res=0;
	if (pIcosModule==0) return ICOS_FAILURE;
	if (CheckIgnoredModules(pIcosModule->szName))  return ICOS_FAILURE;

	if (pIcosModule->proc_term_cb)
	{
		PRO_PRT("Process Module %s ProcTerminate()\n", pIcosModule->szName);
		res=pIcosModule->proc_term_cb(msg, pid);
	}
	return res;
}

void PS_watchdog(void)
{
    struct proc_ctx *ps_ctx=NULL;
    ...
    ps_ctx = phead_proc;
    while (ps_ctx)
    {
        ...
        if (ps_ctx->state == PS_STATE_EXITED)
        {
            pIcosModule=GetIcosModule(ps_ctx->module_id);

            if (pIcosModule->proc_term_cb)
            {
                pIcosModule->proc_term_cb(buf, ps_ctx->pid);
            }
            continue;
        }
        ps_ctx = ps_ctx->next;
    }
}

目前並沒有看到誰在使用 ProcTerminate()

所以只有 PS_watchdog() 有可能會去呼叫 webModuletermcb_web()

至於 PS_watchdog() 在什麼狀況下會去呼叫 webModuletermcb_web() 呢?

這就需要再去追了

但不是現在需要去追的事