linux multipoint gre survey

最近在 survey 與 tunnel 相關的協定與網路虛擬化有關的,除了原有的 tunnel 以外,因應一些雲端應用現在還有 cisco vxlan、microsoft nvgre、nicira STT 等等為了嶄新目的所設計的協定。

但學習還是從根本下手,連 gre 都還沒有很懂,就先來看一下 gre 好了(其實是其他的都看不懂)。

Generic Routing Encapsulation 是 cisco 提出來的 tunnel 協定,採取點對點的方式,將兩個不同的網路透過 internet 串連起來,能形成一個虛擬的網路(不是指 VLAN),實際運作就如同一般 VPN 的應用所達到的效果一樣。如果需要要加密還能搭配 IPsec。

點對點指的是什麼點呢?兩邊子網路各提供一台主機(spoke)負責接收(decapsulate)與發送(encapsulate)。

什麼情況下這 spoke 會處理封包呢?

可以分為兩種模式, layer2 與 layer3,layer2 是針對區網的所有看得到的封包都進行轉送,layer3 則是 client 要將 broker 指定成該子網路的 gateway 才會轉送。

怎麼分別這兩種類型的 gre tunnel 呢?

最簡單的方式就是分辨 broker 的 tunnel interface 是否有設 IP 就能知道了, Layer 3 的有設, layer 2 的沒有。

在 linux 上?

linux 上只要透過 iproute 就能設定讓介面提供 layer 3 的 GRE 的 tunnel 了,而 layer 2 的部份目前我是透過 Open vSwitch 來做,如果用原本的 gretap 的話就要搭配 linux bridge 才能做到。

上述的都是基於 p2p 的做法,那標題寫得 multipoint gre 又是啥呢 🙂 ?

後來 cisco 又提出了 multipoint gre,讓一個 gre 的 tunnel 不只是 p2p ,而可以一個通道多台主機對連,讓設定變得更有彈性,而這個協定的發展似乎與 Dynamic Multipoint VPN 相關,麟瑞科技這篇文章有一些介紹。

接著我在 linux 上想尋找這協定的實作,結果發現一篇文章 Ethernet multipoint GRE over IP(in Google Groups)。似乎在核心最近的版本才有相關的 patch。他們有一些精彩的討論,剛好跟我最近想解決的問題相關,參與討論的包含了 patcher、ovs 的開發者、linux 網路相關的維護者,最終這個 patch 沒有被收納到核心,部份原因是跟 ovs 的存在有些衝突。

該 pacher 提案者提出一個概念,他認為 layer2 multipoint gre 應該要搭配 bridge 的學習機制,不應該無謂的一直將收到的封包像 hub 一樣傳到每個連接的 spoke,但他這樣獨立的實作這個概念與原先的 bridge 與 gre tunnel 的存在有點重複,又與 Open vSwitch 主要想處理的問題又有些衝突。但他還是有的自己的看法,希望此功能獨立存在,但最終還是被打槍了,而且真的讓 davem 覺得他很盧…。

這次在尋找 mailling list 的過程中感覺 gname 線上 web 閱讀介面有點不友善,只是好像其他的也都差不多~最後找到覺得比較好的是 http://www.gossamer-threads.com/lists/linux/kernel

另外也認識了一個人物,David S. Miller ,他在這些討論裡面擔任負責審核 patch 是否能進入核心的關鍵角色。以一個 Linux Kernel 開發的門外漢的角度,從這系列的討論中,讓我理解一些此環境的生態,開發者積極的想要自己的 Patch 被採用許要耗費多少心力去解釋,去獲取人家的認可,在沒有提出適當的理由,或者足夠的原因的程式,或許終究會被一道高牆擋下。

David S. Miller:I’m not applying your patch. 

PVE 疑難雜症…

  • PVE 2.0
  • 叢集設定
  • 叢集的服務基於:cman(corosync)
  • 叢集的檔案系統:pmxcfs
  • 每台叢集的設定檔:/etc/cluster/cluster.conf
  • PVE qemu/kvm 管理工具:qm

管理與確認指令:

$ pvecm status
$ pvecm nodes or cman_tool nodes

$ corosync-quorumtool -l
$ corosync-quorumtool -s

$ cat /var/log/syslog
$ cat /var/log/cluster/corosync.log

$ service cman restart
$ service pve-cluster restart
$ service node-manager restart

問題:

  • Corosync 因為 Quorum 開不起來,訊息是  Unable to load new config in corosync,代表 該台主機的 /etc/cluster/cluster.conf 內容可能出問題了,可以比較一下節點間該檔案的差異,如果不一樣可以手動同步。
  • 叢集運作是基於 multicast ,因此需要在同一個 layer 2 network,而且 switch 要支援與設定啟用群播功能(預設可能已經開了)。

node.js child_process send function

最近在用 node.js 寫一些系統管理層面的程式,有些複雜的工作需要 fork process 來做,主要的 process 用來跑 Web 跟處理主要流程,所以不打算做太多額外的工作。

var child = require('child_process').fork('./child.js');

在這裡實作的過程中想到一些設計,第一個部份是我的 child 應該設計成一個適合 require 的子模組,由他自己提供輔助函式,也由該模組 fork 自己。

var child = require('./child.js');
child.start();
child.stop();
var process;
exports.start = function() {
  var cp = require('child_process');
  process = cp.fork('./child.js');
  child.send('message', {cmd: 'start'});
}
exports.stop = function() {
  if(process)
    process.kill();
}
process.on('message', function(msg) {
  if(msg.cmd == 'start') {
     // child process start
     // do something
  }
});

由於 fork 出去的 child process 是一個子模組,所以對 parent 來說還是有一些事情想要呼叫 child 來做。依照習慣要寫一些匿名函式當參數,意思就是這個函式希望是在 child process 去跑,而不是單純用來當回呼函式使用,結果實際到這邊發現有些事情跟想像的不太一樣,process.send 當參數如果傳函式到 child process 竟然會接不到~。

仔細想想好像也不完全無道理,由於要 IPC,而 json 對函式的轉換好像本來就不太支援。

範例繼續延續上面的,這範例 msg 將收不到傳過去的函式。

..
child.helper(function(res) {
  // ...
});
..
var process;
exports.start = function() {
  var cp = require(''child_process);
  process = cp.fork('./child.js');
  child.send('message', {cmd: 'start'})
}
exports.stop = function() {
  if(process)
    process.kill();
}
exports.helper = function(handler) {
  process.send({cmd: 'helper', handler: handler});
});
process.on('message', function(msg) {
  if(msg.cmd == 'start') {
     // child process start
     // do something
  }
  else if(msg.cmd == 'helper'){
     console.log(msg);
     // { msg: 'helper' }
  }
});

這裡就讓我想到曾經看過一篇文章…撰寫乾淨的 eval 程式碼的技巧,因此就依樣畫葫蘆…就能動了!

只是要注意透過這種方式傳過去的函式所能存取到的變數已經不是表面上看到的了。而是透過 eval 執行時的 child process 的 context 了。

exports.helper = function(handler) {
  process.send({cmd: 'helper', handler: handler.toString()});
});
process.on('message', function(msg) {
  if(msg.handler) {
    eval('var handler = ' + msg.handler);
  }
  if(msg.cmd == 'start') {
     // child process start
     // do something
  }
  else if(msg.cmd == 'helper' && handler){
     handler([1, 2, 3]);
  }
});

Glab tomato install

Glab tomato Project : https://github.com/dswd/ToMaTo

ubuntu

$ apt-get install python-setuptools apache2-utils
# install south 0.7.3
$ wget http://www.aeracode.org/releases/south/south-0.7.3.tar.gz
$ tar zxvf south-0.7.3.tar.gz
$ cd south
$ ./setup.py install
# install django 1.3 https://www.djangoproject.com/download/
$ wget https://www.djangoproject.com/download/1.3.1/tarball/
$ tar zxvf Django-1.3.1.tar.gz  -O Django-1.3.1.tar.gz
$ cd Django-1.3.1
$ ./setup.py install

# install ToMaTo
$ git clone https://github.com/dswd/ToMaTo.git
$ mkdir /etc/tomato /var/lib/tomato
$ cp ToMaTo/web/web.conf.example /etc/tomato/web.conf
$ cp ToMaTo/backend/backend.conf.example /etc/tomato/backend.conf
# login account and passwd
$ htpasswd -d -c /etc/tomato/users admin
# run backend
$ cd ToMaTo/backend/
$ ./server
# run web 
$ cd ToMaTo/web/
$ ./manage runserver $IP:$PORT