2019年3月30日 星期六

hotplug2

hotplug2 是輕巧版的 udev,在 OpenWrt 已經由 procd 取代。

程式 /sbin/hotplug2 會常駐,連結到 netlink socket 讀取 uevent,變數拿來跟每個規則比對,符合的就執行對應的指令。

規則比對有 "==" 及 "!=" 檢查字串是否相等、"~~" 及 "!~" 執行正規表示式比對、"is set" 及 "is unset" 檢查有無此變數。每個規則可以有多項比對用「,」隔開,接著是以 { } 包起來的指令。指令也可以有多個,可執行的指令有:
  • print <text>:印訊息
  • print-event [rule label]:印出整個 event。If the rule label is provided, it is printed along with the rule.
  • setenv <key> <value>:設定環境變數
  • remove <file>:移除檔案
  • chown <owner> <file>:改變檔案的擁有者
  • chgrp <group> <file>:改變檔案的群組
  • chmod <mode> <file>:改變檔案的存取模式
  • run <command>:使用 system() 執行 shell 指令
  • exec <command> [arg1 [arg2 [... [argn]]]]:直接執行指令
  • mknod <filepath> <mode>:建立 device node (使用 MAJOR, MINOR 及 SUBSYSTEM 變數)
  • load-firmware <firmware directory>:載入存在 <firmware directory> 的韌體,需要 FIRMWARE 變數
  • serialize [socket:]:
  • next-event:跳到下個 event,也就是不比對接下來的規則。
  • branch-event [success]:如果上個指令執行失敗 (或成功),跳到下個 event。
  • branch-rule [success]:如果上個指令執行失敗 (或成功),跳出此規則,繼續比對接下來的規則。
最後三個是流程控制。

OpenWrt preinit 時,規則是 /etc/hotplug2-init.rules,如果是按鍵 (SUBSYSTEM == button) 就「kill -USR1 1」。

在 init 的 boot 時,規則會改設為 /etc/hotplug2-init.rules,會再包含 /etc/hotplug2-platform.rules 及 /etc/hotplug2-common.rules。這些規則有一部分會去執行 /sbin/hotplug-call,第一個參數是 SUBSYSTEM 變數值或 firmware,會去執行 /etc/hotplug.d/$1/ 下所有的程式

preinit 時, 如果沒有 devfs,則執行
/sbin/hotplug2 --set-worker /lib/hotplug2/worker_fork.so --set-rules-file /etc/hotplug2-init.rules --no-persistent --set-coldplug-cmd /sbin/udevtrigger
/sbin/hotplug2 --set-worker /lib/hotplug2/worker_fork.so --set-rules-file /etc/hotplug2-init.rules --persistent &
在 init 的 boot
/sbin/hotplug2 --override --persistent --set-rules-file /etc/hotplug2.rules --set-coldplug-cmd /sbin/udevtrigger --max-children 1 >/dev/null 2>&1 &
疑問:
  • hotplug 跟 hotplug2 的關係?
參考來源:
  1. https://wiki.openwrt.org/doc/techref/hotplug
  2. hotplug2 原始碼
  3. OpenWrt 原始碼
延伸閱讀:
  • devtmpfs
  • devfs
  • udev
  • mdev (busybox 的簡化版 udev)
  • hotplug ()

2019年3月24日 星期日

OpenWrt procd

OpenWrt 使用 procd 取代傳統 Linux 使用的 init 及 udev。

procd 原始碼除了套件 procd 外,還包括套件 procd-ujail、procd-seccomp、procd-nand、procd-nand-firstboot。procd 套件包括二進位程式 init、procd、askfirst、udevtrigger,shell 指令檔 reload_config 和 procd.sh,以及 hotplug json 檔 hotplug-preinit.json 和 hotplug.json。


在 OpenWrt 開機,Linux 最後會執行腳本 /etc/preinit註1 開始 userspace 的動作,但現在一開始就先插隊執行 /sbin/init,然後才執行原本的 /etc/preinit,最後交棒給 procd 繼續執行,變成:/sbin/init → /etc/preinit → /sbin/procd。

註: 在 OpenWrt 開機,Linux 最後會執行腳本 /etc/preinit (`try_to_run_init_process("/etc/preinit")`@init/main.c → do_execve()@fs/exec.c), 執行時會檢查檔案開頭決定何種執行檔,腳本需要以 #! 開頭 (load_script()@fs/binfmt_script.c),/etc/preinit 使用的直譯器是 busybox sh

init

一開始 PREINIT 沒設,執行 init 取代自己
[ -z "$PREINIT" ] && exec /sbin/init
  1. `ulog_open(ULOG_KMSG, LOG_DAEMON, "init")`: 設定 log 方式
  2. SIGTERM、SIGUSR1、SIGUSR2 的處置是 sa_shutdown
  3. `early()`:掛載檔案系統及設定環境變數
  4. `cmdline()`:讀取 Linux 指令行參數 init_debug 設定 debug 等級。
  5. `watchdog_init(1)`:初始化 watchdog,使用 /dev/watchdog
  6. fork() 執行 `/sbin/kmodloader /etc/modules-boot.d/` 載入一些 kernel 模組,並等候結束
  7. fork() 執行 `/sbin/procd -h /etc/hotplug-preinit.json` 處理事件
    • 載入韌體:使用 /sbin/hotplug-call
    • failsafe 按鍵:執行 /etc/rc.button/failsafe 產生 /tmp/failsafe_button
  8. fork() 執行 `PREINIT=1 /bin/sh /etc/preinit`,執行 /etc/preinit 原本該跑的腳本,結束時執行
    1. 如果 hotplug-preinit.json 還在跑,殺了他。
    2. 如果檔案 /tmp/sysupgrade 存在,就一直睡吧不往下執行了 (等候 reboot 嗎?) 
    3. 清掉環境變數 INITRAMFS、PREINIT
    4. 設環境變數 WDTFD 交出 watchdog file descriptor
    5. 交接除錯等級
    6. 改為繼續執行 /sbin/procd

procd

procd 其實可看成是兩個程式,有加 -h 參數是當作 hotplug daemon (hotplug_run()),否則
  1. 繼承除錯等級或重設,並設定 log 方式
  2. `setsid()`:建立新 session 並成為 process goup leader,且成為 process group 唯一的成員,使用 process ID 作為 session ID 及 process group ID,回傳 session ID。no controlling terminal。如果已經是 process group leader,則回傳 -1 且 errno 為 EPERM。
  3. `procd_signal()`:signal 的處置
    • SIGTERM、SIGINT、SIGUSR1、SIGUSR2:sa_shutdown
    • SIGSEGV、SIGBUS:sa_crash
    • SIGHUP、SIGKILL、SIGSTOP:sa_dummy
  4. 如果不是第 1 個 process,一秒後連結到 ubus,否則進入以下 state
  5. STATE_EARLY
    1. 設定 watchdog timeout
    2. hotplug(/etc/hotplug.json) 事件處理
    3. fork() 執行 `udevtrigger`,結束 ... 進入下個 state
  6. STATE_UBUS
    1. 重開 /dev/console stdin/stdout/stderr
    2. ubus timeout:ubus 連上後最後進入下個 state
    3. service_start_early()
  7. STATE_INIT
    1. LOG("- init -\n");
    2. `procd_inittab()`:讀取 inittab 建立 actions 列表 (id:run-level:action:process)
      • process 切出 argv
      • 除了 sysinit 及 shutdown 外,可以有多個
    3. `procd_inittab_run("respawn")`:
    4. `procd_inittab_run("askconsole")`
    5. `procd_inittab_run("askfirst")`
    6. `procd_inittab_run("sysinit")`:依序執行 /etc/rc.d/ 下 S 開始的腳本中的 boot() 部份
    7. `ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd")`:切換到 syslog
  8. STATE_RUNNING:沒做什麼事,只是 log 完成 init
  9. STATE_SHUTDOWN:shutdown 時進入,依序執行 /etc/rc.d/ 下 K 開始的腳本中的 shutdown() 部份
  10. STATE_HALT
sysinit 跟 shutdown 都是執行 /etc/rc.d/ 下的腳本,這些腳本通常是依所要執行的順序連結到 /etc/init.d/ 下的腳本,在 inittab 可能的內容如下:
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
在 procd 會用 glob() 取出所有 /etc/rc.d/S* 的檔案,全部加到 libubox runqueue 去執行。

askfirst

用在 inittab

udevtrigger

...

procd.sh

共用腳本函數,當 init 腳本使用 procd 方式時 (USE_PROCD=1) 使用。

OpenWrt 的 init 腳本通常透過 /etc/rc.common 執行,在開機時是執行 shell function  boot(),而 boot() 預設是執行 start()。在傳統方式,由 init 腳本提供 start() 功能,但當使用 procd 方式時則改提供 start_service()。
oldprocd
start()start_service() 至少要提供 json command 的部份
stop()已採用 procd_kill 停止程式,stop_service()
reload()如有 reload_service() 則執行,不然執行 start()
running()
trace()
使用 procd 方式的特別之處
  • 所有引數會打包成 json 格式,透過 ubus 送給 procd
    • command
    • respawn
    • ...
  • service_triggers() 可用 procd_add_reload_trigger() 登記哪些設定檔改變後執行 reload_config 需要重新執行。可用 procd_add_network_trigger() 登記網路改變作為重啟的 trigger

範例:package/network/services/dnsmasq

詳情見 OpenWrt package/base-files/files/etc/rc.common。
rc.common 會載入 /lib/functions.sh (一些共同的函數,包括 config_ 開頭的函數)、/lib/config/uci.sh (uci_ 開頭存取 uci 的函數)、及 /lib/functions/service.sh (使用 busybox start-stop-daemon 提供 service_ 開頭的函數)。

reload_config

configd 完成前的臨時替代方案,
檢查設定有改變則呼叫 `ubus call service event { "type": "config.change", "data": { "package": "設定檔名" }}`

開機時會產生設定檔的 MD5 checksum 存在記憶體,更改設定後執行 reload_config 會自動重啟相關的程式。

hotplug-preinit.json 及 hotplug.json。

...

延伸閱讀


/sbin/procd (不設 INITRAMFS,不設 PREINIT)
│ hotplug(/etc/hotplug.json)
├→ udevtrigger
│ubus_connect()...service_init, /etc/inittab
│? /sbin/ubus
├respawn→
├askconsole→
├askfirst→/sbin/askfirst
sysinit⇄用 runqueue 一次跑一個 /etc/rc.d/S* boot,pipe STDOUT/STDERR

hotplug_run() 每次事件發生時
exec→
load-firmware→

libubox uloop
libubox blob, blobmsg
json_script_init
ubus
service
ustream

延伸閱讀:http://data.pavlix.net/installfest/2014/openwrt-software.pdf

2019年3月17日 星期日

行動電話世代

行動電話的世代

1G:類比語音。

2G:數位語音。

  • GSM 系統採用電路交換的語音通道來打電話和傳送簡訊。2G 架構包括基地台子系統 (Base Station Subsystem, BSS) 和 網路子系統(Network SubSystem, NSS)。BSS 由基地台接收站 (Base Transceiver Station, BTS) 以及基地台控制器 (Base Station Controller, BSC) 所組成,負責無線傳輸的排程以及 MAC 的控制訊息。NSS 主要元件為無線交換機中心 (Mobile Switching Center, MSC),負責接入公共交換電話網路(PSTN)。
  • GPRS 系統提供封包交換功能來上網,但仍使用語音通道傳送資料封包,所以速度很慢。2.5G 架構在 GSM 架構加上 GPRS 核心網路,主要由 SGSN (Serving GPRS Support Node) 和 GGSN(Gateway GPRS Support Node) 所組成,負責 IP 網路資料傳遞。BSC 會依據收到的資料決定要傳送到 NSS 或是 GPRS 核心網路。
3G:行動上網。UMTS (Universal Mobile Telecommunications System, 通用行動通訊系統) 由 3GPP 基於 GSM 發展,使用新的 W-CDMA 無線介面等構成的通用無線接入網 (GRAN) 連入不同的骨幹網路 (電路交換或封包交換),如網際網路、ISDN、GSM 或者 UMTS網路,可以用更快的速度上網。
  • 2006 出現智慧型手機

4G:完全 IP 封包化,行動寬頻上網。

  • 4G (2008)
  • 4G LTE (2010)
  • LTE Advanced:引進 CA、MIMO,1Gbps
  • LTE Advanced Pro: >3Gbps, < 2ms 延遲。引進 Full Dimension Massive MIMO、低速低功耗網路。

4G LTE 的傳輸是使用 IP 分封交換 (Packet Switching),不同於 2G / 3G 所使用的電路交換 (Circuit Switched) 傳輸方式。
語音通話服務可以透過 CSFB、SGLTE 或 VoLTE 等方法來達到 。

* CSFB (Circuit Switched Fallback):上網用 4G,語音切回 3G
* SGLTE (Simultaneous GSM and LTE):同時使用 4G 及 GSM (較耗電)
* SVLTE (Simultaneous Voice and LTE):同時使用 4G 及 CDMA (較耗電)
* SRVCC (Single Radio Voice Call Continuity):3GPP 標準,話音通話在 VoLTE 跟 2G/3G 之間切換時能維持通話連續性,在 LTE 覆蓋率不佳的環境可確保通話不中斷。

### VoLTE [[教學]何謂VoLTE?認識新一代高品質語音通話服務]

5G:三大面向:大容量 (達 20Gbps),低延遲 (<1ms),大量低價 IoT 連結。M2M
  • 應用:更高畫質的影片、更快的檔案傳輸、可靠的即時控制應用...
  • Band Steering (頻段引導):引導使用較好的頻段
  • Client Steering (裝置引導):引導使用較好的 AP
  • Seamless Roaming (無縫漫遊):毫秒切換 AP
世代系統名稱調變方式多工方式通道頻寬資料傳輸率頻譜效率
2GGSMGMSKFDMA/TDMA200KHz9.6K/14.4K0.05/0.07
2.5GGPRSGMSKFDMA/TDMA200KHz9.6K/115K0.05/0.58
2.75GEDGE8PSKFDMA/TDMA200KHz384K/384K1.92/1.92
3GW-CDMAQPSKFDMA/CDMA5MHz64K/2M0.01/0.40
3.5GHSDPA16QAMFDMA/CDMA5MHz384K/14.4M0.08/2.88
3.75GHSUPAQPSKFDMA/CDMA5MHz5.76M/14.4M1.15/2.88
4GLTE64QAMFDMA/OFMA20MHz50M/100M2.5/5
4GLTE-A64QAMFDMA/OFMA100MHz500M/1G5/10
4.5GLTE-A Pro256QAM?/???/3G (32CA)?/?
「頻譜效率」(Spectrum efficiency) 是單位頻寬 (Hz) 有多少資料傳輸率 (bps)。

調變技術 (Modulation)

2G 以後是採用數位調變,用不同波形 (symbol) 的類比電磁波 (包括用振幅大小、頻率高低、相位不同等) 來代表 0 與 1 的數位訊號。數位調變的優點包括可以偵錯與除錯、壓縮與解壓縮、加密與解密、更好的抗雜訊能力等。

多工技術 (Multiplex)

將電磁波給不同的使用者使用,常見的包括下列 4 種:
  • 分時多工接取 (TDMA):依照「時間先後」區分。
  • 分頻多工接取 (FDMA):依照「頻率範圍不同」區分。
  • 分碼多工接取 (CDMA):用不同的碼加密資料後傳送,只有有特定碼的接收端以不同的密碼來分辨要接收的訊號。
  • 正交分頻多工 (OFDM):使用彼此頻率「正交」的 FDMA。LTE / LTE-A、無線區域網路 (IEEE802.11a/g/n)、數位電視 (DTV)、數位音訊廣播 (DAB) 都有使用。
通常同時使用兩種以上的多工技術來增加資料傳輸率,滿足每個人都要使用的需求。

參考來源

http://technews.tw/2015/10/12/3g、4g、5g-meaning-part-two

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...