2020年5月24日 星期日
Ephemeral Port
ephemeral:無常的、短命的、短暫的
IANA 建議範圍 49152 ~ 65535,Linux 使用 32768 ~ 60999,可用
echo "49152 65535" > /proc/sys/net/ipv4/ip_local_port_range
更改範圍,實際上是存在陣列 sysctl_local_port_range 的兩個數字。
如何配置?
bind() 指定 local port
inet_hash_connect() @net/ipv4/inet_hashtables.c:
inet6_hash_connect() @net/ipv6/inet6_hashtables.c:local port 未指定時,範圍內從小到大...
__udp_lib_get_port() @net/ipv4/udp.c
inet_csk_get_port() @net/ipv4/inet_connection_sock.c
selinux_socket_bind() @security/selinux/hooks.c:不在範圍內時 ...
問題:
可針對不同 net_device 而有不同範圍?
最後更新:20200721
2020年5月10日 星期日
Linux Method Dispatch
就同樣 class 的 Object,Method 不像狀態一般不會變,通常收集在另一個 struct,有時稱為「virtual function table (vtable)」,原本 struct 只需要一個指標到這個 table 而節省記憶體。
pure vtable:都是函數指標的 struct,這些函數的第一個引數指到一個 struct,其包含一個指標指到此 vtable。
例如:file_lock_operations 包含兩個函數指標,運作在 struct file_lock。
例如:seq_operations 包含四個函數指標,運作在 struct seq_file。
vtable 取名習慣是運作的 struct 名稱或 abbreviated 加上「_operations」,在 Linux 2.6.39 大約有 30 個「*_operations」。此外有超過 100 個「*_ops」,大部分也是。但也有幾個如 struct mdk_personality,並沒有規則。
函數指標為 NULL:
- 呼叫前要檢查。
- 與其間接執行一個沒功能的函數,檢查是否 NULL 較有效率。
- 如果 NULL 只是少數例外,檢查 NULL 確實浪費程式空間及執行時間。
- 可能有別的方式得知為 NULL,不用實際去檢查,也節省了 memory fetch。
原因:特定 Method 對有些使用情況是無意義的,測試為 NULL 需回傳錯誤。例如:在 inode_operations 的 create() 只有在 inode 是目錄才有意義,所以執行 vfs_create() 檢查為 NULL 而回傳 -EACCES。
原因:界面函數轉換。例如:file_operations 的 ioctl(),在 2.6.11 新增 unlocked_ioctl() 不用 big kernel lock,在 2.6.36 所有驅動程式和檔案系統完成轉換而移除 ioctl()。轉換過程中,一個檔案系統一般只有二者之一,讓另一個為 NULL。
例如:file_operations 的 read()/write() 和 aio_read()/aio_write() 只需要二者之一。aio_read() 用來支援 asynchronous IO,此時 the regular synchronous read() 是不需要的 (實際上是透過 do_sync_read() 使用 aio_read()),但似乎沒有移除 read() 的打算,有些情況 async IO 是 not relevant,例如特殊檔案系統 procfs 和 sysfs。
不純的 vtable:含有其它成員。
例如:struct mdk_personality 提供 particular software RAID level 操作,包含了「owner」、「name」、以及「list」「owner」是提供實作的模組,「name」只是識別(有些 vtable 是字串、有些數字,有些稱作「版本」、「family」、「drvname」、或「level」。)
2020年5月8日 星期五
電腦散熱風扇
| 電源 | 黑 | 紅 | 黃 | 藍 | 說明 |
|---|---|---|---|---|---|
| 大 4 pin | GND | +12V | - | - | 直接接電源跑全速,其實也可以 DC 控制。 |
| 小 2 pin | DC 電壓控制 | - | - | ||
| 小 3 pin | 轉速偵測 | - | |||
| 小 4 pin | +12V | PWM |
轉速 (tachometer) 是每圈兩個方波的 open collector 輸出,需電阻 pull high。鎖住時固定 high 或 low。
PWM 是 25kHz 左右的 5V 方波
直徑:
轉速:
風量:
噪音:
貓頭鷹 S是靜音,F是聚焦,A前或後是進階(或進化),P是平衡
外接控制器
- Noctua NA-FC1 風扇轉速控制器
- 風扇太多嗎? 試試NZXT GRID+ V2風扇控制器吧
- DIY
2020年4月17日 星期五
C: variable argument lists
函數可有未知數目和 type 的引數。
#include <stdarg.h>
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
首先宣告一個 va_list 物件,然後使用 va_start() 初始化物件,和 va_end() 成對使用,之間用 va_arg()、或 vprintf() 等使用 va_list 物件。
va_arg() 將第一個引數定義為 type 後指到下個引數。
#include <stdarg.h>
void my_printf(const char *fmt, ...)
{
va_list ap; //宣告一個 va_list 物件 ap
va_start(ap, fmt); //初始化 ap
vprintf(fmt, ap); //使用 ap 並更新指到下個未用的引數
va_end(ap); //結束 ap
}
va_list 最普遍是一個指標指到函數的 stack frame,複製可以直接指定:
va_list aq = ap
但也有系統是一個陣列,內容是一個指標,需要:
va_list aq; *aq = *ap;
另外,argument 如果是透過暫存器傳遞的系統,va_start() 需要配置記憶體存 arguments 和指示哪個是下個 argument,va_end() 可以釋出配置的記憶體。
因應不同情況, C99 新增 va_copy(),複製變成:
va_list aq; va_copy(aq, ap); ... va_end(aq);
2020年4月10日 星期五
Linux signals
signal 通知 process 事件發生,或稱為軟體中斷,和硬體中斷一樣中斷程式正常流程。signal 來源可能是
- 另一個 process,可作為同步機制或 IPC 原型。
- 自己
- kernel
- hardare exception,如不對的機器指令、除以 0、存取非法位址。
- 終端機特殊字元,如中斷字元 Ctrl-C、suspend 字元 Ctrl-Z。
- software event,收到 file 輸入、視窗改變大小、timer 時間到、超出 CPU 使用時間、child process 結束。
每個 signal 用 1 開始的小數字表示,在 signal.h 名稱定義為 SIGxxx。signal 分成兩類,一是傳統的標準 signal,在 Linux 是 1~31。另一種 realtime signal。
signal 在排程準備要執行時處理,如果已經執行中則馬上處理。signal 從產生 (generated) 到送達 (delivered) 之間是 pending。process 可設遮蔽 (mask) 來 block 特定 signal 而讓其產生後一直 pending,直到 unblock。每個 thread 有自己的 signal mask,pthread_sigmask() 設定 thread 哪些 signal blocked。傳統 single-threaded 應用,sigprocmask() 可用來設定 signal mask (用在 multi-thread 會怎樣?)。fork() 繼承 signal mask,execve() 保留 signal mask (繼承和保留有何不同?)。
signal 送達時執行下列預設「動作」(Action) 之一:
- Ign:忽略,process 不會發現。
- Term:process 結束 (killed),是 abnormal process termination,有別於 exit() 的 normal process termination。
- Core:process core dump 並結束。core dump 包含 process 的 virtual memory image,可作為除錯用。
- Stop:process 暫停。
- Cont:暫停的 process 繼續。
| Signal | 值 | 動作 (預設) | 說明 |
|---|---|---|---|
| SIGHUP | 1 | Term | kill. 控制終端機偵測到 Hangup 或控制行程 death。 |
| SIGINT | 2 | Term | 中斷字元 Ctrl-C 產生。 |
| SIGQUIT | 3 | Core | Quit from keyboard |
| SIGILL | 4 | Core | Illegal Instruction |
| SIGABRT | 6 | Core | abort() 產生,用來產生 core dump。 |
| SIGFPE | 8 | Core | Floating point exception |
| SIGKILL | 9 | Term | Kill signal (無法 caught、blocked、或 ignored) |
| SIGSEGV | 11 | Core | Invalid memory reference |
| SIGPIPE | 13 | Term | Broken pipe: write to pipe with no readers |
| SIGALRM | 14 | Term | Timer signal from alarm(2) |
| SIGTERM | 15 | Term | Termination signal |
| SIGUSR1 | 30,10,16 | Term | User-defined signal 1 |
| SIGUSR2 | 31,12,17 | Term | User-defined signal 2 |
| SIGCHLD | 20,17,18 | Ign | Child stopped or terminated |
| SIGCONT | 19,18,25 | Cont | Continue if stopped |
| SIGSTOP | 17,19,23 | Stop | Stop process (無法 caught、blocked、或 ignored) |
| SIGTSTP | 18,20,24 | Stop | Stop typed at terminal |
| SIGTTIN | 21,21,26 | Stop | Terminal input for background process |
| SIGTTOU | 22,22,27 | Stop | Terminal output for background process |
可用 sigaction() 或 signal() 改變動作,或稱為設定 disposition,可選擇 1) 回復預設動作、2) 忽略、或 3) 執行 signal handler。執行 signal handler 時,稱為 caught。如果想要 signal handler 結束 process,可執行 exit()。如果想要 signal handler core dump 後結束 process,可執行 abort()。signal 的動作是 process 屬性,其下 thread 共用。fork() 繼承。execve() 時,除了忽略的 signal 外,其它回復預設動作。
/proc/PID/status 包含 hex 表示的 bit-mask fields 查看 signal 狀態
SigPnd:per-thread pending
ShdPnd:process-wide pending
SigBlk:blocked
SigIgn:ignored
SigCgt:caught
signal 可以是 process-directed 或 thread-directed。process-directed 的 signal 是 targeted 整個 process,來自 kernel other than a hardware exception,或 kill() 或 sigqueue()。thread-directed 的 signal 是 targeted 特定 thread,這些是來自 hardware exception (如 invalid memory access 產生 SIGSEGV,math error 產生 SIGFPE) 或使用 tgkill() 或 pthread_kill()。process-directed signal 任意由一個沒 block 的 thread 處理。thread 可 sigpending() 取得目前 pending 的 signal,包含 process-directed 和給自己 thread-directed。fork() 一開始 pending signal set 是空的,execve() 保留 pending signal set。
standard signal 各自只有一個,沒有特定處理順序。pending 時再發生也只有一個。
signal handler 預設使用 the normal process stack (是指 thread stack?process 有 stack?),可用 sigaltstack() 改用不同的 stack。
送 signal- raise():送 signal 給自己 thread。
- kill():送 signal 給指定的 process、指定的 process group、或所有 processe。
- killpg():送 signal 給指定的 process group。
- pthread_kill():送 signal 給 process 內指定的 thread。
- tgkill():實作 pthread_kill() 的系統呼叫。
- sigqueue():送 real-time signal 及 accompanying data 給指定的 process。
- 系統呼叫 pause():暫停執行直到補抓到任何 signal。
- 系統呼叫 sigsuspend():暫時改變 signal mask 並暫停執行直到補抓到任何 unmasked 的 signal。
- 系統呼叫 sigwaitinfo()、sigtimedwait()、和 sigwait():暫停執行直到補抓到指定的 signal 並回傳 signal 資訊。
- 系統呼叫 signalfd():回傳 file descriptor 用來讀有關 signal 的資訊,read() 後等候指定的 signal 並得到描述 signal 的資料結構。
可以用 pthread_sigmask() 或 sigprocmask() 設 mask 來讓 signal pending 進不來,直到 unmask。用 sigpending() 查看 pending siganl。
程序管理
INT (Ctrl-C)
TERM (kill 預設)
WINCH
SEGV
EXIT
USR1
USR2
ALARM
HUP
Real-time signals:範圍定義在 SIGRTMIN 和 SIGRTMAX 之間,Linux kernel 支援 32 到 64,但 glibc POSIX thread 實作只用 2 (NPTL) 或 3 (LinuxThreads) 個。real-time signal 運用由應用程式定義,沒有事先定義,預設動作是 Term。real-time signal 的不同...
參考
- man 7 signal
- http://www.gnu.org/software/libc/manual/html_node/Signal-Handling.html
- busybox ping
- busybox dhcpc:用 SIGUSR1 來更新 IP 租約, 用 SIGUSR2 來釋出 IP 租約。
- TLPI §20.1
- 從 /proc/PID/status 了解執行中程式處理 signal 的方式
- http://fcamel-life.blogspot.com/2012/02/core-dump.html
2020年4月3日 星期五
struct net_device
重要成員
- mtu:例如 Ethernet 是 1500,可透過「ifconfig <interface> mtu <mtu>」更改
- flags:可透過 ifconfig 看到 UP BROADCAST RUNNING MULTICAST NOARP
- dev_addr[]:MAC 位址
- promiscuity:設為 promiscuous 模式的次數
- IN_DEV 開頭巨集 (IN_DEV_FORWARD(), IN_DEV_RX_REDIRECTS())
- hard_start_xmit():傳送封包的方式
- ip_ptr
- struct in_device 成員 cnf (ipv4_devconf) 包括 forwarding, accept_redirects, send_redirects 等,對應到 /proc/sys/net/ipv4/conf/all/???。
struct net_device {
char name[IFNAMSIZ];
struct netdev_name_node *name_node;
struct dev_ifalias __rcu *ifalias;
/*
* I/O specific fields
* FIXME: Merge these and struct ifmap into one
*/
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
int irq;
/*
* Some hardware also needs these fields (state,dev_list,
* napi_list,unreg_list,close_list) but they are not
* part of the usual set specified in Space.c.
*/
unsigned long state;
struct list_head dev_list;
struct list_head napi_list;
struct list_head unreg_list;
struct list_head close_list;
struct list_head ptype_all;
struct list_head ptype_specific;
struct {
struct list_head upper;
struct list_head lower;
} adj_list;
netdev_features_t features;
netdev_features_t hw_features;
netdev_features_t wanted_features;
netdev_features_t vlan_features;
netdev_features_t hw_enc_features;
netdev_features_t mpls_features;
netdev_features_t gso_partial_features;
int ifindex;
int group;
struct net_device_stats stats;
atomic_long_t rx_dropped;
atomic_long_t tx_dropped;
atomic_long_t rx_nohandler;
/* Stats to monitor link on/off, flapping */
atomic_t carrier_up_count;
atomic_t carrier_down_count;
#ifdef CONFIG_WIRELESS_EXT
const struct iw_handler_def *wireless_handlers;
struct iw_public_data *wireless_data;
#endif
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
#ifdef CONFIG_NET_L3_MASTER_DEV
const struct l3mdev_ops *l3mdev_ops;
#endif
#if IS_ENABLED(CONFIG_IPV6)
const struct ndisc_ops *ndisc_ops;
#endif
#ifdef CONFIG_XFRM_OFFLOAD
const struct xfrmdev_ops *xfrmdev_ops;
#endif
#if IS_ENABLED(CONFIG_TLS_DEVICE)
const struct tlsdev_ops *tlsdev_ops;
#endif
const struct header_ops *header_ops;
unsigned int flags;
unsigned int priv_flags;
unsigned short gflags;
unsigned short padded;
unsigned char operstate;
unsigned char link_mode;
unsigned char if_port;
unsigned char dma;
/* Note : dev->mtu is often read without holding a lock.
* Writers usually hold RTNL.
* It is recommended to use READ_ONCE() to annotate the reads,
* and to use WRITE_ONCE() to annotate the writes.
*/
unsigned int mtu;
unsigned int min_mtu;
unsigned int max_mtu;
unsigned short type;
unsigned short hard_header_len;
unsigned char min_header_len;
unsigned short needed_headroom;
unsigned short needed_tailroom;
/* Interface address info. */
unsigned char perm_addr[MAX_ADDR_LEN];
unsigned char addr_assign_type;
unsigned char addr_len;
unsigned char upper_level;
unsigned char lower_level;
unsigned short neigh_priv_len;
unsigned short dev_id;
unsigned short dev_port;
spinlock_t addr_list_lock;
unsigned char name_assign_type;
bool uc_promisc;
struct netdev_hw_addr_list uc;
struct netdev_hw_addr_list mc;
struct netdev_hw_addr_list dev_addrs;
#ifdef CONFIG_SYSFS
struct kset *queues_kset;
#endif
unsigned int promiscuity;
unsigned int allmulti;
/* Protocol-specific pointers */
#if IS_ENABLED(CONFIG_VLAN_8021Q)
struct vlan_info __rcu *vlan_info;
#endif
#if IS_ENABLED(CONFIG_NET_DSA)
struct dsa_port *dsa_ptr;
#endif
#if IS_ENABLED(CONFIG_TIPC)
struct tipc_bearer __rcu *tipc_ptr;
#endif
#if IS_ENABLED(CONFIG_IRDA) || IS_ENABLED(CONFIG_ATALK)
void *atalk_ptr;
#endif
struct in_device __rcu *ip_ptr;
#if IS_ENABLED(CONFIG_DECNET)
struct dn_dev __rcu *dn_ptr;
#endif
struct inet6_dev __rcu *ip6_ptr;
#if IS_ENABLED(CONFIG_AX25)
void *ax25_ptr;
#endif
struct wireless_dev *ieee80211_ptr;
struct wpan_dev *ieee802154_ptr;
#if IS_ENABLED(CONFIG_MPLS_ROUTING)
struct mpls_dev __rcu *mpls_ptr;
#endif
/*
* Cache lines mostly used on receive path (including eth_type_trans())
*/
/* Interface address info used in eth_type_trans() */
unsigned char *dev_addr;
struct netdev_rx_queue *_rx;
unsigned int num_rx_queues;
unsigned int real_num_rx_queues;
struct bpf_prog __rcu *xdp_prog;
unsigned long gro_flush_timeout;
rx_handler_func_t __rcu *rx_handler;
void __rcu *rx_handler_data;
#ifdef CONFIG_NET_CLS_ACT
struct mini_Qdisc __rcu *miniq_ingress;
#endif
struct netdev_queue __rcu *ingress_queue;
#ifdef CONFIG_NETFILTER_INGRESS
struct nf_hook_entries __rcu *nf_hooks_ingress;
#endif
unsigned char broadcast[MAX_ADDR_LEN];
#ifdef CONFIG_RFS_ACCEL
struct cpu_rmap *rx_cpu_rmap;
#endif
struct hlist_node index_hlist;
/*
* Cache lines mostly used on transmit path
*/
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
unsigned int num_tx_queues;
unsigned int real_num_tx_queues;
struct Qdisc *qdisc;
unsigned int tx_queue_len;
spinlock_t tx_global_lock;
struct xdp_dev_bulk_queue __percpu *xdp_bulkq;
#ifdef CONFIG_XPS
struct xps_dev_maps __rcu *xps_cpus_map;
struct xps_dev_maps __rcu *xps_rxqs_map;
#endif
#ifdef CONFIG_NET_CLS_ACT
struct mini_Qdisc __rcu *miniq_egress;
#endif
#ifdef CONFIG_NET_SCHED
DECLARE_HASHTABLE (qdisc_hash, 4);
#endif
/* These may be needed for future network-power-down code. */
struct timer_list watchdog_timer;
int watchdog_timeo;
struct list_head todo_list;
int __percpu *pcpu_refcnt;
struct list_head link_watch_list;
enum { NETREG_UNINITIALIZED=0,
NETREG_REGISTERED, /* completed register_netdevice */
NETREG_UNREGISTERING, /* called unregister_netdevice */
NETREG_UNREGISTERED, /* completed unregister todo */
NETREG_RELEASED, /* called free_netdev */
NETREG_DUMMY, /* dummy device for NAPI poll */
} reg_state:8;
bool dismantle;
enum {
RTNL_LINK_INITIALIZED,
RTNL_LINK_INITIALIZING,
} rtnl_link_state:16;
bool needs_free_netdev;
void (*priv_destructor)(struct net_device *dev);
#ifdef CONFIG_NETPOLL
struct netpoll_info __rcu *npinfo;
#endif
possible_net_t nd_net;
/* mid-layer private */
union {
void *ml_priv;
struct pcpu_lstats __percpu *lstats;
struct pcpu_sw_netstats __percpu *tstats;
struct pcpu_dstats __percpu *dstats;
};
#if IS_ENABLED(CONFIG_GARP)
struct garp_port __rcu *garp_port;
#endif
#if IS_ENABLED(CONFIG_MRP)
struct mrp_port __rcu *mrp_port;
#endif
struct device dev;
const struct attribute_group *sysfs_groups[4];
const struct attribute_group *sysfs_rx_queue_group;
const struct rtnl_link_ops *rtnl_link_ops;
/* for setting kernel sock attribute on TCP connection setup */
#define GSO_MAX_SIZE 65536
unsigned int gso_max_size;
#define GSO_MAX_SEGS 65535
u16 gso_max_segs;
#ifdef CONFIG_DCB
const struct dcbnl_rtnl_ops *dcbnl_ops;
#endif
s16 num_tc;
struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
u8 prio_tc_map[TC_BITMASK + 1];
#if IS_ENABLED(CONFIG_FCOE)
unsigned int fcoe_ddp_xid;
#endif
#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
struct netprio_map __rcu *priomap;
#endif
struct phy_device *phydev;
struct sfp_bus *sfp_bus;
struct lock_class_key qdisc_tx_busylock_key;
struct lock_class_key qdisc_running_key;
struct lock_class_key qdisc_xmit_lock_key;
struct lock_class_key addr_list_lock_key;
bool proto_down;
unsigned wol_enabled:1;
struct list_head net_notifier_list;
};
eth_mangle_rx (OpenWrt 特有?)
許多網路界面是 PCI devices 會使用 PCI 通用的函數如 pci_register_driver() 和 pci_enable_device()。有些是 USB devices。驅動程式可見 ldd3 chap17。
註:bonding:兩個以上網路界面使用相同 IP,作為 load balancing 及 high availability 使用。
參考來源:
- Linux Kernel Networking by Rami Rosen at Haifux, August 2007
http://www.haifux.org/lectures/187/netLec3.pdf
2020年4月1日 星期三
RS232 isolation
https://www.analog.com/en/products/adum226n.html
SIP header Via
所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...
-
網路界面驅動程式有兩種接收封包的方式 -- 中斷驅動和 NAPI。傳統是用中斷驅動,在中斷服務程式裡接收封包,但封包量大時會有中斷次數太多而效能變差的問題。NAPI (意思是 New API) 改成中斷服務程式只通知有封包,Kernel 再排程一次接收多個封包來提昇效能。 中...
-
busybox ntpd 是 NTP client,也可作為 NTP server。 參數 -d:Verbose -n:不常駐 -q:(quit) 時間設完後結束 -N:高優先權執行 -w:不設定時間,只是詢問 peers,隱含 -n -l:作為 NTP ser...
-
驅動程式除了 read()/write() 外,通常可以透過 ioctl() 系統呼叫進行一些控制或設定,如鎖門、退片、回報錯誤、改變 baud rate、或 self destruct 等。 在 user space 格式如下: #include <sys/ioctl...