2014年9月10日 星期三

Mapping of Address and Port (MAP)

最近在研究MAP這個東東,
這個東西主要是用來做什麼的呢?

眾所皆知, IPv4 address都已經發完了。
IPv6絕對是未來的方向。

可以想像的,
IPv4未來會成為IPv6網路的孤島。

可能會有總總因素,會讓使用者(client)或服務提供者(server)只能使用IPv4 network的情況,
而如何透過IPv6的網路來傳送IPv4的封包,
就是MAP要做的事情。

而要在IPv6的網路上傳輸,必需要有IPv6 address。
問題是如何把IPv4轉換成IPv6 address。

通常有兩個主要的方式,
stateful, stateless

什麼是stateful呢?
就是在每一個IPv4與IPv6轉換的設備上會有轉換的記錄,
例如:
292.11.45.1→2001:34:55:99:ac::2
292.45.11.3→2001:34:55:99:ac::3
也就是說每當要轉換時,必需由讀取這一個記錄,
才能了解要怎麼轉換。

而stateless則是會有一個演算法,
使得IPv4與IPv6可以直接透過這一個演算法來互相轉換。
一般來說都會比較推薦stateless的方式(原因是什麼我目前還不太清楚)。

而MAP主要分為
Mapping of Address and Port with Encapsulation (MAP-E)
與
Mapping of Address and Port with Translation (MAP-T).

這兩個主要的差別在於MAP-E是用封裝的方式,
直接在IPv4的封包外再加上IPv6的header,
這樣的好處是可以完整保存IPv4的封包。
但是,要傳送的封包是會比較大一點,因為額外加了IPv6的封包了嘛。

而MAP-T則是把IPv4的header轉換成IPv6的header,
缺點是額外做轉換的動作,
效能來說可能會比較慢一點。

先暫時寫到這裡,
最近一直在研究這個東西,
應該還會持續一段時間。

參考資料:
【自由谈】城域网IPv6过渡技术——MAP技术(1)

2014年9月1日 星期一

linux下停用IPv6

直接寫入1到
/proc/sys/net/ipv6/conf/all/disable_ipv6
就可以關掉整個IPv6的支援。

可以填到
/usr/etc/rcS裡面寫入
echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6

其它方式可以參考
Linux 下關閉支援 IPv6 提升效能

2014年8月11日 星期一

顯示make編譯信息

現在在編code的時候,因為在確認一些細節,想了解實際的的編
但是,編譯的過程中,並沒有把make的實際細節顯示出來。

我知道可以透過@與-s或--silent把完整的訊息隱藏起來,
但我的Makefile並沒有這一些東西啊,為什麼還是會隱藏起來呢?

原來是在build kernel module的時候,會使用的linux kernel的makefile,而kernel的makefile有預設隱藏這一些訊息。

有兩個方式
1. 則要到kernel的makefile把這一些部分註解掉。
要俢改的檔案位置是在/usr/src/linux-2.6.38.8/Makefile
...
ifeq ($(KBUILD_VERBOSE),1)
# quiet =
# Q =
else
# quiet=quiet_
# Q = @
endif

# If the user is running make -s (silent mode), suppress echoing of
# commands

ifneq ($(findstring s,$(MAKEFLAGS)),)
# quiet=silent_
endif

#export quiet Q KBUILD_VERBOSE
...

如此一來,重新編譯的時候,就可以顯示完整的編譯過程了。

2. 使用make V=1就可以顯示完整的訊息了, 這個方式就超級方便的了。

參考資料:
顯示make編譯信息
Linux內核make命令選項

2014年6月4日 星期三

pipe的用法

使用 pipe() 可建立一組雙向的管線,
通常會使用一個陣列來建立pipe
例:
int pfd[2];
這是一條水管,
從 pfd[0] 進入的東西會從 pfd[1] 出來,
反之亦然,
除此之外,
它也是可以跨 Process,
達成兩個程式溝通的目的。

實做上必須注意以下幾個重點

1.有複製,就要有關閉,一個dup2搭一個close,保持file descriptor的單純性
(此為血淚經驗談,自己實做就知道…)

2.fork出去的程式,沒用到的file descriptor一定要記得關
舉例來說,本來shell主程式裡面有一個pipe,若是此時fork出子程序來exec指令,主程序下wait指令等待子程序執行完畢且主程序沒有關閉pipe,則主程序會卡住。因為當fork的時候,一個pipe實際上會變成兩個pipe,當指派子程序接收pipe資料的時候,如果還有其他pipe沒有關閉,則子程序會判定pipe資料流尚未結束,而繼續癡癡等待輸入,若是主程序有pipe沒關閉的話,結果就是主程序在等子程序結束,子程序又在等待主程序的pipe輸入資料,造成死結。

參考:
C/C++, Linux, Web 相關技術, 程式心得筆記, 系統研發手札
pipe @ Linux Kernel
[程設] Linux C 的file descriptor以及pipe操作相關筆記(上)
[程設] Linux C 的file descriptor以及pipe操作相關筆記(下)

2014年5月21日 星期三

Linux C - gcc 預先定義的巨集

在Linux下使用gcc編譯,
有幾個內建的變數可以非常好用,
在Debug的時候,
占非常重要的角色。

1. __BASE_FILE__
完整的原始檔案路徑

2. __cplusplus
表示該檔案由 g++ 所編譯,當成 C++ 的檔案

3. __DATE__
編譯的日期

4. __TIME__
編譯的時間

5. __FILE__
原始檔名

6. __LINE__
所在行數

7. __VERSION__
gcc 版本

8. __func__
替代 __FUNCTION__,__FUNCTION__ 已被 GNU 不推薦使用

參考資料:
LinuxC – gcc 預先定義的巨集

2014年5月9日 星期五

如何開啟windows 7的telnet與tftp

為了把image燒到測試的板子上面,
必需要用到tftp這一個指令。

而在windows 7預設是把telnet與tftp關掉。

如何把這兩個功能打開呢?

開啟控制台→程式集→開啟或關閉Windows功能



選擇「Telnet用戶端」與「TFTP用戶端」的選擇,
再按確定。



這樣就可以使用telnet與tftp了。

參考資料:
Win7 開啟 telnet and tftp

2014年5月5日 星期一

union

因為IPv6的address一共有128bit,
若要處理的話,
目前long int也只有4 bytes(32bit),
double只有8bytes(64bit)
沒有一個變數可以儲存到128bit,
這個時候就要用到union

直接寫下

/* IPv6 address */
struct in6_addr {
  union {
    uint8_t  u6_addr8[16];
    uint16_t u6_addr16[8];
    uint32_t u6_addr32[4];
  } in6_u;
#define s6_addr   in6_u.u6_addr8
#define s6_addr16  in6_u.u6_addr16
#define s6_addr32  in6_u.u6_addr32
};

這個宣告方式,可以讓128bit,
各別的使用8bit在運算。

下面是我寫的一個sub function,
也因為有了這個,
要運算IPv6才會變的比較簡單。

/*
 * Filter the IPv6 by prefix to Network ID or Interface ID
 *
 * @param IPv6_Addr_Src     the source for filtering
 * @param IPv6_Addr_Dst     the result of the filtering process
 * @param PrefixLen         the prefix of the network
 * @param MaskType          if the value is NetworkPrefix, network prefix would be reserved
 *                          if the value is InterfaceIdentifier, the interface identifier would be reserved
 */
static void
MaskIPv6 (
  struct in6_addr   IPv6_Addr_Src,
  struct in6_addr   *IPv6_Addr_Dst,
  int               PrefixLen,
  enum MaskType     Direction
  )
{
  char            *AddrPtr, *IndexAddrPtr;
  int             FullByteNumber, BitNumber;
  char            Mask;
  int             Index;
  int             CurrentPosition;

  //
  // The bytes of network id part
  //
  FullByteNumber = PrefixLen / 8;
  //
  // The bits of network id part
  //
  BitNumber = PrefixLen % 8;

  //
  // filter the bytes of Network ID part
  //
  for (CurrentPosition = 0; CurrentPosition < FullByteNumber; CurrentPosition++) {
    if (Direction == NetworkPrefix) {
      IPv6_Addr_Src.s6_addr[CurrentPosition] = IPv6_Addr_Src.s6_addr[CurrentPosition] & 0xFF;
    } else {
      IPv6_Addr_Src.s6_addr[CurrentPosition] = IPv6_Addr_Src.s6_addr[CurrentPosition] & 0x00;
    }
  }

  //
  // filter the bits of Network ID part and the bits of Interface ID part
  //
  Mask = 0;
  if (BitNumber != 0) {
    for (Index = 0; Index < BitNumber; Index++) {
      Mask = (Mask << 1) | 1;
    }

    for (Index = 0; Index < 8 - BitNumber; Index++) {
      Mask = Mask << 1;
    }

    if (Direction == InterfaceIdentifier) {
      Mask = ~Mask;
    }

    IPv6_Addr_Src.s6_addr[CurrentPosition] = IPv6_Addr_Src.s6_addr[CurrentPosition] & Mask;

    CurrentPosition++;
  }

  //
  // filter the bytes of Interface ID part
  //
  for (; CurrentPosition < 16; CurrentPosition++) {
    if (Direction == NetworkPrefix) {
      IPv6_Addr_Src.s6_addr[CurrentPosition] = IPv6_Addr_Src.s6_addr[CurrentPosition] & 0x00;
    } else {
      IPv6_Addr_Src.s6_addr[CurrentPosition] = IPv6_Addr_Src.s6_addr[CurrentPosition] & 0xFF;
    }
  }

  //
  // Copy the modified IPv6_Addr_Src context for return
  //
  memcpy (IPv6_Addr_Dst, &IPv6_Addr_Src, sizeof (IPv6_Addr_Src));

}