2013年4月16日 星期二

iPerf 測試 multicast broadcast unicast


[Multicast]
Server: iperf -s -u -B 224.0.55.55 -i 1
Client: iperf -c 224.0.55.55 -b 100M -T 32 -t 60 -i 1

[Broadcast]
Server: iperf -s -u -i 1
Client: iperf -c 192.168.1.255 -b 100M -T 32 -t 60 -i 1

[Unicast]
Server: iperf -s -u -i 1
Client: iperf -c 192.168.1.33 -b 100M -T 32 -t 60 -i 1


  • -s 指定為server
  • -c 指定為client
  • -u 指定為UDP
  • -i 指定report印出來的間隔時間
  • -b 指定throughput
  • -B 指定mulicast binding address
  • -T 指定TTL
  • -t 指定持續時間

2013年3月5日 星期二

VirtualBox 的 share folder 功能


安裝在 Oracle VM VirtualBox 中的 Guest OS,可以和 Host OS 分享資料夾。

以下是個人的使用方式:

Guest OS: Fedora 10
Host OS: Windows 7

在 Host OS 中建立一個資料夾名為 Images。
在 VirtualBox 的選單列中選取「裝置->共用資料夾...」。
新增這個 Images 資料夾到共用資料夾中。

在 Guest OS (Linux) 中輸入以下指令:
# mkdir /home/fedora/IMAGE
# mount -t vboxsf Images /home/fedora/IMAGE

做完上述步驟之後,即可在 Guest 和 Host 之間分享檔案。
唯時間上的同步有一點小問題,對於檔案時間有嚴格要求的分享可能會產生問題。

2012年12月28日 星期五

brctl 的簡介

brctl - ethernet bridge administration

工具套件名稱為 bridge-utils
可以依照自己使用的distribution做軟體安裝的動作
# sudo apt-get install bridge-utils

[BRIDGE INSTANCES]
新增橋接器「br0」
# brctl addbr br0

刪除橋接器
# brctl delbr br0

[PORTS]
將網卡「eth0」新增到橋接器「br0」中
# brctl addif br0 eth0

將網卡「eth0」從橋接器「br0」中移除
# brctl delif br0 eth0

檢視橋接器
# brctl show

2012年11月16日 星期五

程式設計師的自我修養 - 筆記

所謂同步,即指在一個thread存取資料未結束的時候,其他thread不得存取同一個資料

mutex 與 binary semaphore 的不同點:
mutex 的 acqurie 和 release 需要同一個 thread 執行
也就是 解鈴還需繫鈴人
但binary semaphore 可以由不同的 threads 執行

編譯過程一般可分為六步:
掃描(詞法分析) scanner
語法分析 parser
語意分析 semantic analyer
原始碼最佳化 source code optimizer
目的碼產生 code generator
目的碼最佳化 code optimizer

目的檔的內容:
程式碼區段 code section
=> .text | .code
=> 存放編譯後的machine code

資料區段 data section
=> .data
=> 存放全域變數和區域靜態變數 [已初始化]

定數量未初始化區段 Block Started by Symbol section
=> .bss
=> 存放全域變數和區域靜態變數 [未初始化]
=> 在檔案中不佔據空間

唯讀區段
=> .rodata
=> 存放唯讀變數和字串常數

2012年11月15日 星期四

Linux SDIO driver programming

Open Source 的 standard SDIO stack 大約在 2.6.24 的時候,由 Pierre Ossman 加入 Linux kernel。某種程度上,SDIO stack 是基於 MMC stack 發展出來的,所以蠻多功能會用到 MMC 這個詞。稍微簡介一下檔案放置的位置:
  • mmc/host 包含了 host adapter drivers,其中的 sdhci 是本文主要使用的 adapter
  • mmc/core 包含了 mmc subsystem code (mmc_core)
  • mmc/card 包含了使用 MMC/SDIO bus 的 device drivers,sdio_uart 是一個例子
* sdhci: Secure Digital Host Controller Interface

以下節錄自 {kernel_source_tree}/drivers/mmc/card/sdio_uart.c
------------------------------------------------------------------------------------
static const struct sdio_device_id sdio_uart_ids[] = {
        { SDIO_DEVICE_CLASS(SDIO_CLASS_UART)            },
        { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS)             },
        { /* end: all zeroes */                         },
};

MODULE_DEVICE_TABLE(sdio, sdio_uart_ids);

static struct sdio_driver sdio_uart_driver = {
        .probe          = sdio_uart_probe,
        .remove         = sdio_uart_remove,
        .name           = "sdio_uart",  /* 驅動程式名稱 */
        .id_table       = sdio_uart_ids,
};
------------------------------------------------------------------------------------

有寫過 Linux USB device driver 的人,應該會覺得 SDIO 註冊 device driver 的方式非常類似於 USB,寫起 SDIO 版本的驅動應該就比較不陌生。首先是要先填寫 struct sdio_driver 的結構體,填寫 struct sdio_driver 所要準備的有兩個 callback function 成員,一個是 probe,另一個是 remove,即探測和移除函數,它們分別在裝置插入和拔出的時候被呼叫,用於初始化和釋放軟硬體資源。而 struct sdio_driver 的 id_table 成員描述了這個 SDIO 驅動程式所支援的裝置清單,它指向一個 sdio_device_id 的陣列,你可以使用下列巨集來產生該陣列成員:
  • SDIO_DEVICE( vendor, device )
  • SDIO_DEVICE_CLASS( device_class )

而在填完 struct sdio_driver 之後,你可以使用下列這兩個函數來註冊和註銷 sdio_driver:
  • int sdio_register_driver(struct sdio_driver *);
  • void sdio_unregister_driver(struct sdio_driver *);

註冊完 sdio_driver 之後,系統便可以在裝置插拔的時候呼叫對應的 probe 和 remove 函數。
  • int (*probe)(struct sdio_func *, const struct sdio_device_id *);
  • void (*remove)(struct sdio_func *);

可以看到這兩個函數的第一個指標參數型別都是 struct sdio_func,定義如下:
/*
 * SDIO function devices
 */
struct sdio_func {
        struct mmc_card         *card;          /* the card this device belongs to */
        struct device           dev;            /* the device */
        sdio_irq_handler_t      *irq_handler;   /* IRQ callback */
        unsigned int            num;            /* function number */
        unsigned char           class;          /* standard interface class */
        unsigned short          vendor;         /* vendor id */
        unsigned short          device;         /* device id */
        unsigned                max_blksize;    /* maximum block size */
        unsigned                cur_blksize;    /* current block size */
        unsigned                enable_timeout; /* max enable timeout in msec */
        unsigned int            state;          /* function state */
#define SDIO_STATE_PRESENT      (1<<0 color="#0000ff" font="font" nbsp="nbsp">
                                                       /* present in sysfs */
        u8                      tmpbuf[4];      /* DMA:able scratch buffer */
        unsigned                num_info;       /* number of info strings */
        const char              **info;         /* info strings */
        struct sdio_func_tuple *tuples;
};

這個參數應是 kernel 取得 SDIO device 資訊並填好之後傳過來的,之所以要講到這個參數,是因為 driver code 中會利用到下列巨集設定/取得驅動程式私有的資料結構。
  • sdio_get_drvdata(struct sdio_func*)
  • sdio_set_drvdata(struct sdio_func*, void *data)

假設驅動程式私有資料結構為 struct foo_priv 且其內嵌 struct sdio_func,舉例如下:

static int foo_probe( struct sdio_func *func, const struct sdio_device_id *id )
{
        struct foo_priv *priv = kmalloc( sizeof(struct foo_priv), GFP_KERNEL );
        priv->func = func;
        sdio_set_drvdata(func, priv);
}

static void foo_remove( struct sdio_func *func )
{
        struct foo_priv *priv = sdio_get_drvdata(func);
        priv->func = NULL;
}

接下來,在與 SDIO device 做 IO 之前,需要在 start 函數中 enable device:
  • sdio_claim_host(priv->func);    //取得 MMC host controller 的物理使用權
  • ret = sdio_enable_func(priv->func);    //Enable SDIO function
  • ret = sdio_claim_irq(priv->func, foo_irq);  //註冊 IRQ handler
  • sdio_release_host(priv->func);    //歸還 MMC host controller 的物理使用權

同樣地,做完 IO 之後,需要再 stop 函數之中 disable device:
  • sdio_claim_host(priv->func);    //取得 MMC host controller 的物理使用權
  • sdio_release_irq(priv->func);    //Disable SDIO function
  • sdio_disable_func(priv->func);    //註銷 IRQ handler
  • sdio_release_host(priv->func);    //歸還 MMC host controller 的物理使用權
另外,IO 動作的前後也需要呼叫 sdio_claim_host() 以及 sdio_release_host(),以便完成 MMC host controller 物理使用權的管理,即其取得與歸還。

一些 SDIO 的 Read/Write function 列表如下:

  • 1: sdio_readb
  • 2: sdio_readw
  • 4: sdio_readl
  • 1: sdio_writeb
  • 2: sdio_writew
  • 4: sdio_writel

以上的 SDIO R/W functions 都是基於 mmc_io_rw_direct() 發展出來的。


最後,一個完整實作的例子可以參考
{kernel_source_tree}/drivers/mmc/card/sdio_uart.c

作者 Nicolas Pitre 是利用 SDIO interface 實作一個 UART driver,所以對上層 USER space 的介面是 TTY driver,可是底層 IO 的部分利用到 SDIO 提供的 Read/Write API 做讀寫。


[Reference]
Linux kernel source
http://www.varsanofiev.com/inside/WritingLinuxSDIODrivers.htm
http://blog.csdn.net/gangyanliang/article/details/6873578

2012年11月5日 星期一

How to become a Linux Device Driver Programmer

本文只是想就自己的經驗與資料作個整理,讓一些有志開發 LDD (Linux Device Driver) 的新手可以有跡可循,畢竟這些只是自己跌跌撞撞的經驗,說不上參考,但還是希望能夠幫助到某些人。

第一步,作為使用者來學習 Linux。
這其實是個蠻大的門檻,我覺得在這之中有以下兩點特別重要:
  • Linux kernel 是什麼,它又負責做什麼事情?
  • 檔案與目錄管理,包含權限的了解
這部分可以參考「鳥哥的 Linux 私房菜」網站,該站有非常豐富的資源,講解也是簡單易懂!

第二步,學習 C,並嘗試在 Linux 底下開發可以在 Linux 執行的程式。
有了 Linux 的基礎之後,接下來就是自己嘗試開發程式,這時候開發的程式屬於 User space 範疇,我建議可以在此時多多使用各種 IO 相關的 Linux C API。

這部分我推薦閱讀 K&R 的「The C Programming Language」,這本書其實不太適合程式設計新手,所以可能還要另外找一本自己看得順眼的 C 入門書輔助閱讀。其實 LDD 的開發並沒有什麼太難的 C 語法,能夠通盤理解 K&R 的 C 語言聖經本就已經是非常熟稔 C 語言了。

第三步,開發 kernel module。
這一步我自己走的有點亂,也還沒整理好自己的經驗,不過我推薦以下幾本好書,讀者一定能從其中得到收穫。(之後有空再來重寫這段 XD)

Linux Device Driver 3rd Edition, O'REILLY 出版
Linux 裝置驅動程式之開發詳解 第二版, 松崗出版
Linux Device Driver Programming, 博碩出版

第四步,作為 kernel 開發者來學習 Linux。
之所以要走這一步的原因是因為開發 LDD 跟 kernel 息息相關,kernel 定義了許多介面要求 LDD 開發者遵守,並也提供了大量的 API 供 LDD 開發者使用。這樣有一個好處是分層可以分得很明確,User space program 跟 driver之間就沒有 dependency 的問題。另外,kernel 是由許多的 subsystem 組成,一個 LDD 不可能不跟這些 subsystem 互動,所以理解 kernel 的組成也是很重要的知識。

這部分我推薦閱讀 Robert Love 寫的「Linux kernel Development」,這本書由一種較宏觀的角度來介紹 kernel,細節沒有觸碰得太多,對於 kernel 初學者來說應該是比較好吸收的一本書。另外就是,除了實作需要之外,LDD 開發者也不太需要整個 kernel 都瞭若指掌,用到的時候再深入理解我覺得會比較符合人性,畢竟 kernel 是一隻蠻恐怖的大怪獸。

2012年3月30日 星期五

SSL Programming

[Reference]
http://www.openssl.org/docs/ssl/ssl.html
http://daydreamer.idv.tw/rewrite.php/read-62.html
http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html
http://www.ibm.com/developerworks/cn/linux/l-openssl.html
http://blog.csdn.net/playmud/article/details/1527438
http://www.rtfm.com/openssl-examples/part1.pdf

struct socket & struct sock 分析

User space application 透過下列函式的調用取得 socket descriptor

int socket(int domain, int type, int protocol); 

在system call中,這個sockfd就會被映射成一個表示socket的struct
下面是其完整定義

struct socket {
    socket_state state;
    unsigned long flags;
    const struct proto_ops *ops;
    struct fasync_struct *fasync_list;
    struct file *file;
    struct sock *sk;
    wait_queue_head_t wait;
    short type;
}; 


state用於表示socket所處的狀態,不過此成員只對TCP socket有用
因為TCP是connection-oriented的protocol,需要維護socket狀態



[Reference] http://miox.cc/2009/05/struct-socket.html