私がNiciraに入ったわけ

私は2011年の5月に(当時の)Niciraに入りました。その当時、私は「Fivefront」という、以前Ascendで仕事をしていた時の同僚と起こした会社をやっていました。Fivefrontでは主にNetFlow / sFlowのコレクタ製品の販売に携わっていましたが、新しい商材も探すのも私のミッションの一つでした。あるとき米国の知人(彼もAscend時代の同僚でした)、彼が務めていた会社が日本に進出したいので一度話を聞いてくれないか、と相談があり、我々としても新しい商材を探していたので、一度話を聞かせて欲しいと返事をしました。彼の来日の日取りも決まり来日目前のところで、突然彼の会社が別の会社に買収されてしまったのです。彼はその買収元の会社で働く気はないとのことで、その会社を辞めてしまったため、来日の計画もパー、事業提携の話も白紙になりました。実はその彼が移った先の会社がNiciraだったのです。

彼が移った先の会社がどんなところか興味があったので、Webで調べてみたりしたのですが、当時のNiciraはまだステルスモードだったため、ホームページを見てもほとんど何も分かりません。でも、なんとなく面白そうな事をやっていそうな気配があったので、その彼に「前の会社の話はともかく、移った先の会社の話を聞かせて欲しい」と頼むと、ちょうどNiciraも日本に進出する計画があり、日本にも来る予定があるとの事だったので、その時に話を聞かせてもらう約束をしました。その前に少し勉強ておきたいので何か資料を送って貰えないかと頼んだところ「ステルスモード中なので資料は何も出せない。代わりにこの論文を読んでおけ!」と送られてきたのが、Martin Casadoらが書いた論文2本でした(笑)。そのうちの一本がこれです。

その論文を読んだところ、当時の私には100%理解はできかったものの、非常にドキドキしたの事を深く記憶しています。「ひょっとしたらネットワークが変わるかもしれない。もし変わるとしたら、こういうところから変わるはずだ!」と感じたのでした。後日、彼ともう一人エンジニアのボスが来日した際に話を聞きましたが、この直感は確信に近いものに変わりました。帰り際に「日本に進出するにあたりエンジニアを捜している。今回の来日でも何人かと面接をした。誰かいいエンジニアを知っていたら紹介してくれ」と頼まれました。心が揺れました。この会社に入ってこれからのネットワークを変える仕事に携わりたい、と思ったからでした。一方で、Fivefrontは本当に小さな会社だったので、仮に一人社員を欠くだけで会社に大きな影響を与える事は避けられません。ましてや会社を起業した一人として、一社員とはまったく違う次元の責任を負っています。一生懸命働いて小さな会社を支えている他の同僚の方々に対して大変申し訳なく思う気持ちはありました。しかし最終的には「僕をそのエンジニア候補の一人に加えてもらえないか?」とNicira側に申し出る決断をしました。

その後、Niciraの上層部の人たちから電話面接を受けました。その時の一人はMartinでした。あまり技術的な話をした記憶はありません。そもそも当時の私は仮想化に関する知識はほぼゼロでした。Hypervisorに触った事もありません。OpenFlowという言葉を知ってても、それがどんなものかも知りません。Open vSwitch?、何それ?状態です(笑)。当時、このへんの事についてアンテナを伸ばしていた人はNiciraがどんな会社で何をやろうとしているか、などなんとなく知っていたに違いありません。一方、私はド素人です。にもかかわらず、なぜか私は合格し(これはいまでも不思議でなりません)、晴れてNiciraで日本第一号の社員となりました。

入社して最初の週にたまたまSales/SEが一同に本社(カリフォルニア州パロアルト)に集まる機会があり、私もそれに出席しました。ただ、皆が何を話しているかさっぱり分かりません。新手のプロトコルかと思った4文字英語が実は客の名前だったりして、まったく話が噛み合いません(爆)。また、その日初めてNVP(NSXの前身)に触りました。「ほら、これ見てやってみろ」と、”Getting Started Guide” というドキュキュメントを渡されて、NVPの設定を初めて行いました。実はその時に初めてHypervisorというものに触りました。フムフム、Hypervisorって、こんなふうになってるのか。。ただ、ここをこうしてこう設定しろ、ってGetting Started Guideに書いてあるのですが、何のためにそれをしているのかさっぱりわかりません。そんな状態ですので、思ったように動かなかった場合の切り分けできようはずもありません。もうもなかば泣きながら設定をしました。当然予定されていた時間内に終わらず、居残り作業です。もう一人いた同時期入社のSEと夜遅くまで頑張りました。

そんな感じで始まったNiciraでの日々ですが、ステルスモードが明けてからあれよあれよという間にVMwareに買収され、NVPがNSXとして進化し、今日に至っています。その間、沢山の苦労もありました。長かったようでもあり短かったようでもあり。でも、今、自分がここにいれて本当に良かったと思っています。

BGP4 library implementation by Ruby

前職にいた時に書いた拙作のBGPのライブラリコードをGitHubに公開する事にしました。

https://github.com/mshindo/bgp-server

このライブラリを使うと簡単にBGP4を喋るコードを書く事ができます。例えば以下のような感じ。

#
# example1.rb
#
require 'bgp-server'

open = Open.new(7675, '172.16.167.1')
openmsg = BgpMsg.new(open)

origin = Origin.new
pathseg1 = AsPathSegment.new([100, 101, 102])
aspath = AsPath.new
aspath.add(pathseg1)
nexthop = NextHop.new('11.0.0.2')
localpref = LocalPreference.new

path_attr = PathAttribute.new
path_attr.add(origin)
path_attr.add(aspath)
path_attr.add(nexthop)
path_attr.add(localpref)

nlri = Nlri.new(['10.0.0.0/8', '20.0.0.0/16'])
update = Update.new(path_attr, nlri)
updatemsg = BgpMsg.new(update)

keepalive = KeepAlive.new
keepalivemsg = BgpMsg.new(keepalive)

bgp = Bgp.new
bgp.start
bgp.send openmsg
puts "OPEN sent"
bgp.send keepalivemsg
puts "KEEPALIVE sent"

bgp.send updatemsg
puts "UPDATE sent"

loop do
  sleep 30
  bgp.send keepalivemsg
  puts "KEEPALIVE sent"
end

このようなコードを書いたきっかけは、ま、ちゃんとしたルータを買うお金がなかったってこともありましたが(笑)、大量の経路をGenieATMというBGPを喋るフローコレクターに注入する必要があったからです。最初はzebraを使って試そうと思ったのですが、さすがに100万経路くらいになると、いったんメモリに全経路を読み込まなければいけないzebraでは厳しくて(貧弱なマシンを使ってましたし)、じゃ、経路を注入するコードを書いちゃおう、と思い立ったのでした。

その後、いろいろなBGP関連の試験をする必要が出てきて、より汎用的なコードになっていきました。例えばJuniperとForce10のCapabilityの送り方が異なる事によるデバッグなどに役に立ちました。JuniperはOptional Parameterの中にCapability Advertisementを複数入れて、それぞれのCapability Advertisementの中に1つずつCapabilityが入っている形で広告されます。一方、Force10のほうはCapability Advertisementは1つだけで、その中に複数のCapabilityが並んだ形で広告されます。このような異なったBGPの実装をシミュレートするには、このコードは大変役に立つと思います。

このような経緯で生まれたコードなので、本コードはBGPの抽象度が少々低く実装されています。もう少し抽象度の高くする事もできたと思うのですが、そうするとBGPメッセージを組み立てる自由度が犠牲になるのでこのような形になっています。

また、このコードを使ってテストをする対象が主にGenieATMだったために、いくつか制限・制約があります。まず、本コードはBGPセッションを自分からは張りにいきません。相手からセッションが張られる事を期待しています(BGP「サーバー」の実装)。また、相手からBGPメッセージが来てもそれを読む事は基本せずに、自分からメッセージを送る事しかしません。いろいろなメッセージを送ってピアのBGPスピーカーの挙動を調べることに主眼を置いているためにこのようになっています。

もちろん、BGPの全ての機能を実装しているわけではありませんし、zebraに比べたら1万分の一の事もしていない「超なんちゃってBGP実装」ですから、あまり有用でないかも知れませんが、世の中の物好きな人に少しでも役に立てば、と思い、恥ずかしながら公開する事にしました。公開に関して私の背中を押してくれた田島@アイマトリックスさんに感謝をしたいと思います。

LinuxCon Japan 2012

LinuxCon Japan 2012Open vSwitchのリードエンジニアの一人であるJesse GrossがLinuxConでスピーカーを務める事になった事もあり、私も初めてLinuxConというイベントに参加することにした。

いくつかのトラックがあったが、私はVirtualization MiniSummitというトラックとoVirt Workshopに参加した。横浜パシフィコでの開催であり、参加者の8割くらいは日本人と思われる状態だが、全てのセッションは英語で行われる。日本人のスピーカーとほぼ日本人の受講者で構成されるセッションででも英語でやる、というのは私としては珍しい体験w

最後のパネルディスカッションも面白かった。Jesseが登壇した “Linux Virtualization” というセッションも面白かったが、Parallels社のCTOであるJames Bottomleyが行った”Social vs Technical Engineering in the Kernel: What This Means for Japanese Developers” は面白かった。昔はLinux Kernelに機能追加にしろバグフィックスにしろパッチを入れるのはさして難しい事ではなかったが、今はそれは簡単な事ではなくSocialな面も要求される。日本人のKernel Developerはどうするべきなのか、という話。

日本には優れたエンジニアが沢山いるのに、言葉や文化の障壁により世界に出て行く事が出来ないのはなんとももったいない事である。かくいう私も最近はすっかりご無沙汰な状況。深く反省。。まずはサンシャイン牧場を止めないと・・w

ありがとう、Steve。

ほぼ2年ぶりに書くBlogがこの話になるとは思ってもみなかった。

Steve Jobs。

彼は間違いなく少なからず僕の人生に影響を与えてくれた人のうちの一人だ。

Appleの時の彼は、もちろんAppleの創業者の一人として認識していたものの、当時僕自身はAppleユーザではなかったこともあり、それ以上の存在では無かった。その後、Appleを追われ、NeXT Computer(以下NeXT)を立ち上げた頃から、彼との接点が多くなったように思う。

僕にとってNeXTは強烈であった。僕にとって初めてのUNIXワークステーションがNeXTであったというのもあるが、それ以上に、NeXTが僕がそれまで知っていたコンピュータとあまりに異なっていたせいだと思う。美しい筐体とディスプレー、そして当時としては先進的なMOを搭載。ハードウェアも奇抜だったが、一番驚いたのはソフトウェアだ。特にInterface Builder(IB)にはただ驚くばかりだった。なぜ、インタプリタ言語ではないObjective-Cで書いた自分のコードが、リンクする事なしにその場でユーザインターフェースと結合テストができるのか? 静的なバインディングの世界しか知らなかった僕にとって、あの動的な世界は衝撃であった。ウィンドウシステムも、当時一般的であったX WindowではなくDisplay PostScriptを採用。そして、カーネルにマイクロカーネルのMachを採用した。これも斬新であった。僕がMachを生んだカーネギーメロン大学(CMU)に行く大きな動機となった。

SteveがAppleに復帰後、傾きかけていたAppleにiMacを投入し、そこからの成功劇はみなさんも良くご存知の事と思う。無骨なコンピュータをスタイリッシュなものに変身させ、音楽をネットワークからダウンロードできるビジネスモデルを作り、携帯電話の世界を変えてみせた。単にコンピュータだけではなく、我々の生活環境を確実に変えてくれた。そんな人はいままでいなかったと思う。

彼が生きていたら、これからどれだけ我々の生活を変えてくれたのだろうか、と思うと本当に残念でならない。この言葉はもう彼には届かないけれども、とにかく心から感謝の意を表しておきたい。ありがとう Steve。

Michael

久しぶりに無線ネタです。
先日Tews/Beckが発表したTKIPに対する攻撃では、Michaelが一方向関数になっていないことを利用していますが、これが本当かどうかを確かめるためにMichaelとその逆関数を実装してみました。うーーん、確かに平文とMichaelの64bitハッシュ値があれば、MIC Keyが逆算できますね。こら、盲点だった。言われて初めて気が付きました。
この64ビットMIC Keyは、256ビットのPairwise Master Key (PMK) を512ビットに拡張して得られるPairwise Transient Key (PTK) の1/8に相当するわけですので、大ざっぱに言うとPMKの1/8に相当する部分が解読されたことになりますが、PMKをPTKに拡張する際には、PMKをかなり激しくHMAC-SHA-1で攪拌していますので、解読できたMIC KeyからPMKを解読するのは、直観的にはかなり厳しそうに思えます。
Tews/Beckの攻撃は現実的には大きな脅威ではありませんが、TKIP攻撃に関しては大きな一歩を踏み出したと言えるでしょう。
以下、コードです。
#include 
#include 
#include 
#include 

u_int32_t lrot(u_int32_t a, int n)
{
    u_int32_t t;

    if (n == 0 || n == 32)
        return a;
    t = (a >> (32 - n));
    return (a << n) + t;
}

u_int32_t rrot(u_int32_t a, int n)
{
    u_int32_t t;

    if (n == 0 || n == 32)
        return a;
    t = (a << (32 - n));     return t + (a >> n);
}

u_int32_t xswap(u_int32_t a)
{
    u_int8_t b[4];

    b[0] = (a & 0x0000ff00) >> 8;
    b[1] = a & 0x000000ff;
    b[2] = (a & 0xff000000) >> 24;
    b[3] = (a & 0x00ff0000) >> 16;

    return (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + b[0]; 
}

void b(u_int32_t l, u_int32_t r, u_int32_t *lv, u_int32_t *rv) {
    r = r ^ (lrot(l, 17));
    l = l + r;
    r = r ^ xswap(l);
    l = l + r;
    r = r ^ (lrot(l, 3));
    l = l + r;
    r = r ^ (rrot(l, 2));
    l = l + r;
    *lv = l;
    *rv = r;
}

void b_inv(u_int32_t l, u_int32_t r, u_int32_t *lv, u_int32_t *rv) {
    l = l - r;
    r = r ^ (rrot(l, 2));
    l = l - r;
    r = r ^ (lrot(l, 3));
    l = l - r;
    r = r ^ xswap(l);
    l = l - r;
    r = r ^ (lrot(l, 17));
    *lv = l;
    *rv = r;
}

void michael(u_int32_t k0, u_int32_t k1, u_int8_t msg[], int n, u_int32_t *lv, u_int32_t *rv) {
    u_int32_t l, r, ll, rr;
    u_int8_t *ptr;
    u_int32_t *m;
    int i;

    ptr = calloc(n + 8, sizeof(u_int8_t));
    memcpy(ptr, msg, n);
    *(ptr+n) = 0x5a;
    m = (u_int32_t *)ptr;

    l = k0;
    r = k1;
    for (i=0; i < n/4 + 2; i++) {
        l = l ^ *m;
        b(l, r, &ll, &rr);
        l = ll;
        r = rr;
        m++;
    }
    *lv = l;
    *rv = r;
    free(ptr);
}

void michael_inv(u_int32_t *k0, u_int32_t *k1, u_int8_t msg[], int n, u_int32_t lv, u_int32_t rv) {
    u_int32_t l, r, ll, rr;
    u_int8_t *ptr;
    u_int32_t *m;
    int i;

    ptr = calloc(n + 8, sizeof(u_int8_t));
    memcpy(ptr, msg, n);
    *(ptr+n) = 0x5a;
    m = (u_int32_t *)ptr + n/4 + 1;

    l = lv;
    r = rv;
    for (i=0; i < n/4 + 2; i++) {         b_inv(l, r, &ll, &rr);         l = ll;         r = rr;         l = l ^ *m;         m--;     }     *k0 = l;     *k1 = r;     free(ptr); }   void michael_print(u_int32_t l, u_int32_t r) {     printf("%02x%02x%02x%02x",             (l & 0x000000ff),             ((l >>  8) & 0x000000ff),
            ((l >> 16) & 0x000000ff),
            ((l >> 24) & 0x000000ff));
        printf("%02x%02x%02x%02xn",
            (r & 0x000000ff),
            ((r  >> 8) & 0x000000ff),
            ((r >> 16) & 0x000000ff),
            ((r >> 24) & 0x000000ff));
}

int main()
{
    u_int32_t l, r, lv, rv;
    u_int32_t k0, k1;
    u_int8_t msg[] = {'M', 'i', 'c', 'h', 'a', 'e', 'l'};
    int i;

    /*
        test vectors for block function
    */
    b(0x0, 0x0, &lv, &rv);
    printf("b(00000000, 00000000) * 1 = (%08x, %08x)n", lv, rv);
    /* (00000000, 00000000) */

    b(0x0, 0x1, &lv, &rv);
    printf("b(00000000, 00000001) * 1 = (%08x, %08x)n", lv, rv);
    /* (c00015a8, c0000b95) */

    b(0x1, 0x0, &lv, &rv);
    printf("b(00000001, 00000000) * 1 = (%08x, %08x)n", lv, rv);
    /* (6b519593, 572b8b8a) */

    b(0x1234567, 0x83659326, &lv, &rv);
    printf("b(01234567, 83659326) * 1 = (%08x, %08x)n", lv, rv);
    /* (441492c2, 1d8427ed) */

    l = 0x1;
    r = 0x0;
    for (i=0; i<1000; i++) {
        b(l, r, &lv, &rv);
        l = lv;
        r = rv;
    }
    printf("b(00000001, 00000000) * 1000 = (%08x, %08x)n", lv, rv);
    /* (9f04c4ad, 2ec6c2bf) */

    /********
     inverse
    *********/
    b_inv(0x0, 0x0, &lv, &rv);
    printf("b_inv(0x0, 0x0) * 1 = (%08x, %08x)n", lv, rv);
    /* (00000000, 00000000) */

    b_inv(0xc00015a8, 0xc0000b95, &lv, &rv);
    printf("b_inv(0xc00015a8, 0xc0000b95) * 1 = (%08x, %08x)n", lv, rv);
    /* (00000000, 00000001) */

    /************************
     test vectors for michael
    *************************/
    l = 0x0;
    r = 0x0;
    michael(l, r, msg, 0, &l, &r);
    michael_print(l, r); // 82925c1ca1d130b8
    michael(l, r, msg, 1, &l, &r);
    michael_print(l, r); // 434721ca 40639b3f
    michael(l, r, msg, 2, &l, &r);
    michael_print(l, r); // e8f9becae97e5d29
    michael(l, r, msg, 3, &l, &r);
    michael_print(l, r); // 90038fc6cf13c1db
    michael(l, r, msg, 4, &l, &r);
    michael_print(l, r); // d55e100510128986
    michael(l, r, msg, 7, &l, &r);
    michael_print(l, r); // 0a942b124ecaa546

    /****************************
     test vectors for michael^-1
    *****************************/
    michael_inv(&k0, &k1, msg, 0, 0x1c5c9282, 0xb830d1a1);
    printf("*** k0 = %08x k1 = %08x ***n", k0, k1);

    michael_inv(&k0, &k1, msg, 1, 0xca214743, 0x3f9b6340);
    printf("*** k0 = %08x k1 = %08x ***n", k0, k1);

    return 0;
}

Rails事情

久しぶりにRuby on Railsと格闘した。最後にRailsに触ったのはバージョンが1.1の頃だったと思う。今回触ったのは2.2。かなーり変わってますね。とくにRoutingまわり。RESTfulを強く意識するようになったようで、いまいち勝手がわからん。もいっかい勉強せんといかんな。。

REXML::Document#write

Ruby REXMLを使ったコードを書いていて、ライブラリの不具合を踏んだ。

$ ruby api.rb
/usr/lib/ruby/1.8/rexml/document.rb:189:in `write’: uninitialized constant REXML::Formatters::Transitive (NameError)
    from api.rb:29
    from api.rb:17:in `each’
    from api.rb:17
$ ruby -v
ruby 1.8.6 (2008-08-11 patchlevel 287) [i386-linux]

どうやら、

 http://redmine.ruby-lang.org/issues/show/553

みたい。

1.9.1では直っていそうだが、これだけのために1.9.1に上げるのもなんなので、手動で1.8.6添付のライブラリにパッチを当てた。おかげでNameErrorは出なくなった。めでたし。

NetFlow V9 RFCいけてない

NetFlow V9のRFC (3954) は、さすがにInformationalなRFCだけあって、いまいちだわ。。悩んでしまったゾ。
 
RFC3954によると、Options Template FlowSetのフォーマットは、
 
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       FlowSet ID = 1          |          Length               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Template ID           |      Option Scope Length      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        Option Length          |       Scope 1 Field Type      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Scope 1 Field Length      |               …             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Scope N Field Length      |      Option 1 Field Type      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Option 1 Field Length     |             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Option M Field Length     |           Padding             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
となっていることから、Option Scopeは複数含めることができる事が分かる。

 

しかし、Option Data Record Formatのほうは、

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |    FlowSet ID = Template ID   |          Length               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 1 – Scope 1 Value    |Record 1 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 1 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 2 – Scope 1 Value    |Record 2 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 2 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 3 – Scope 1 Value    |Record 3 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 3 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              …              |            Padding            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

という例が示されており、Scopeが1つしか入っていないケースしか示されていない。間違いではないがよい例ではないだろう。

本来は、

     0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |    FlowSet ID = Template ID   |          Length               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 1 – Scope 1 Value    |   Record 1 – Scope 2 Value   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             …               |Record 1 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 1 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 2 – Scope 1 Value    |   Record 2 – Scope 2 Value   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             …               |Record 2 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 2 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 3 – Scope 1 Value    |   Record 3 – Scope 2 Value   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             …               |Record 3 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 3 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Record 3 – Scope 1 Value    |   Record 3 – Scope 2 Value   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             …               |Record 3 – Option Field 1 Value|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Record 3 – Option Field 2 Value|             …               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              …              |            Padding            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 

とすべきだと思う。実際に1つのOption Templateに複数のScopeが含まれているTemplate FlowSetは見たことがないので、本当に上記のようになるのか確かめたことはないが、論理的に考えると上記のようになるはずである。また、Scopeが複数含まれていた場合のsemanticsもいまいちはっきりしない。

さすがに、IPFIXでは、このへんはすっきりしている。
 
   +————————————————–+
   | Template Record Header                           |
   +————————————————–+
   | Field Specifier                                  |
   +————————————————–+
   | Field Specifier                                  |
   +————————————————–+
    …
   +————————————————–+
   | Field Specifier                                  |
   +————————————————–+
 
 
   +————————————————–+
   | Options Template Record Header                   |
   +————————————————–+
   | Field Specifier                                  |
   +————————————————–+
   | Field Specifier                                  |
   +————————————————–+
    …
   +————————————————–+
   | Field Specifier                                  |
   +————————————————–+

のようにどちらも同じ枠組み(Field Specifier)で扱うことができるようになっている(もちろんTemplate Record HeaderとOption Template Record Headerは異なる)。また、複数のScopeが指定された場合のsemanticsについても言及されている。

 
InformationalなRFCと、Proposed StandardなRFCの成熟度の違いを見るにはとてもよい例だと思う。 

ディスク換装

普段使っているノートPCのディスクが手狭になってきました。そこで、内蔵の160GBのSATAディスク(Seagate ST9160821AS)を、500GBのSeagate ST9500325ASに換装することにしました。500GBの2.5"ディスクが1万円強で買えるんですね。いい時代です 🙂
 
最初は、以前ディスクの換装に行った時に買ったAcronics True Image 7.0を使ってやろうと思ったのですが、どうやらこれではSATAのディスクを認識しない模様で、使えませんでした。新たにソフトウェアを買おうかとも思ったのですが、フリーなものでできないかちょっと調べてみたらいろいろ手がありそうだったので、今回はフリーなものでやってみることにしました。
 
まず、ディスクのコピーのために使ったのは、EASEUS Disk Copy (http://www.easeus.com/disk-copy/)。これはセクターごとにディスクをコピーしていくもので、物理ディスク丸ごとコピーするモードとパーティションごとにコピーするモードが選べます。今回はディスクを丸ごとコピーして、パーティションの切りなおしは別のツールを使うことにしました。EASUS Disk Copyの操作は極めて直観的で、迷うところはありません。コピー速度はおおよそ1GB/分くらいで、2時間半程度でコピーは無事に終了しました。
 
次にパーティションの編集ソフトウェアでパーティションの切りなおしを行います。これもいろいろフリーなツールはありましたが、今回はgparted(http://gparted.sourceforge.net/)を使うことにしました。こちらの使い方には少々戸惑ったものの、最終的には無事に自分の意図したようなパーティションにすることができました。こちらの所要時間はおよそ5時間(もっとスマートな操作の仕方をすれば2~3時間で終わったかも)。
 
どちらのソフトウェアもISOイメージが用意されていてBootable CDから実行できますので安心です。
 
これで、無事に私のディスクに空きができるようになりました。これらの素晴らしいソフトウェアを作ってくれた方々に感謝!

WindowsメールでのSASL認証

下の娘と二人で実家に来ています。先日、父がPCをVistaにしたので、再度メールの設定をして欲しい、というもので、再設定をしてあげることにしました。メールサーバーは私の自宅に置いてあるサーバーのIMAP/SMTPをover SSLで使うことになります。
 
私が自己署名したCA証明書を入れて、IMAP over SSLはすんなり動くようになりましたが、SMTP Auth over SSLがうまく動きません。SMTPしようとすると、
 

Jan 3 10:48:23 ober postfix/smtpd[12381]: warning: xxx.xxx.xxx.xxx.st.bbexcite.jp [xxx.xxx.xxx.xxx]: SASL NTLM authentication failed: authentication failure Jan 3 10:48:23 ober postfix/smtpd[12381]: warning: SASL authentication failure: client didn't issue valid NTLM response

というようなエラーが沢山出ます。SASL側のconfigかなと思い、ちょっと調べてみたものの、NTLM認証が使えるようにするためのオプションは見つからず。

で、困った時のGoogleさんに聞いてみたところ、

http://shinshu.fm/MHz/77.88/archives/0000181142.html

という情報が見つかり、試してみたらバッチリ動くようになりました。本来はSASLのライブラリで対処するべきなのでしょうが、とりあえず今回はクライアント側で回避することにしました。