Oh, nice packet

slankdevの報告

NFVガイドラインのようなものを少しまとめた

以下に置いた(画像部分をhatebuに変換するのが大変だったのでリンクにした) もしリンクがきれていたら, Twitter: @slankdevまで連絡をください. すぐ直します。

github.com

「次世代の通信インフラストラクチャーに対応する効率的な仮想ネットワーク機能(VNF)アーキテクチャー」を読んだのでようやく

  • NFV Whitepaper by Intel HPE
  • Hiroki SHIROKURA @slankdev
  • 2018.07.30

本レポートは以下のLINKのWhitepaperをよんで筆者なりにまとめたものである LINK

続きを読む

DPDKアプリをビルドする自前Makefile

DPDKどドキュメントによると、DPDKを使用したアプリケーションでは用意された雛形のMakefileを 一部変更することでビルド環境を提供しているが、自分で何かをつくりたいときにそんなことを やってられない。

ここでは自分で作成したMakefileでDPDKのアプリケーションをビルドする方法をまとめていく。

答えを見つけるまでのアプローチ方法

以下のアプローチで進めていけば一応絶対わかる。

  • オリジナルのビルド手順をすべて確認する
  • makeにnオプションを与えて実行されるコマンドを確認する
  • そのコマンドから少しずついらないオプションを減らしていく
  • どんなDPDKアプリでもビルドできる状態で限界まで減らす
  • 完成
続きを読む

BSDのNW処理部分の設計実装

自分用雑記. まだ書きかけです.

FreeBSDの黄色い本を読んで自分なりに要約, またSTCPの設計実装のためのメモ ここで出てくる典型的例とはBSDカーネル内での実装のことである.

ソースは以下から入手した - ftp://ftp.freebsd.org/pub/FreeBSD/releases/

続きを読む

BSDのARP実装についてメモ

どこを参照したか

FreeBSDソースの以下のファイル

ファイル名 概要
sys/net/if_arp.h arphdr構造体とかその辺がある
sys/net/if_ethersubr.c Ethernetに関する処理がある
sys/netinet/if_ether.c Ether,ARPに関する大事な実装

ARP処理部分の流れ

  1. init
  2. arpresolve
    1. arprequest

ARPでの代表的関数

関数名 概要
arprequest arpリクエストをブロードキャスト
arpresolve 名前解決を行う
arpintr パケットがarpかを確認前

Glossary

  • lla(Link Lyer Address)

よく使われる構造体

struct   arphdr {
    u_short ar_hrd;     /* format of hardware address */
#define ARPHRD_ETHER    1   /* ethernet hardware format */
#define ARPHRD_IEEE802  6   /* token-ring hardware format */
#define ARPHRD_ARCNET   7   /* arcnet hardware format */
#define ARPHRD_FRELAY   15  /* frame relay hardware format */
#define ARPHRD_IEEE1394 24  /* firewire hardware format */
#define ARPHRD_INFINIBAND 32    /* infiniband hardware format */
    u_short ar_pro;     /* format of protocol address */
    u_char  ar_hln;     /* length of hardware address */
    u_char  ar_pln;     /* length of protocol address */
    u_short ar_op;      /* one of: */
#define ARPOP_REQUEST   1   /* request to resolve address */
#define ARPOP_REPLY 2   /* response to previous request */
#define ARPOP_REVREQUEST 3  /* request protocol address given hardware */
#define ARPOP_REVREPLY  4   /* response giving protocol address */
#define ARPOP_INVREQUEST 8  /* request to identify peer */
#define ARPOP_INVREPLY  9   /* response identifying peer */
/*
 * The remaining fields are variable in size,
 * according to the sizes above.
 */
#ifdef COMMENT_ONLY
    u_char  ar_sha[];   /* sender hardware address */
    u_char  ar_spa[];   /* sender protocol address */
    u_char  ar_tha[];   /* target hardware address */
    u_char  ar_tpa[];   /* target protocol address */
#endif
};

ダブルロックの有用性について

2016.08.01 サイボウズラボユースにて. ずいぶんまえに学んだ内容だが、資料を生理していたらmemoがでてきたので。 ここに吐いておく(間違っていたらすみません)

はじめに通常のロックについて

以下の手順で行われる

lock()
if (inited == false)
    init()
    inited = true
unlock()

このときif文とlock,unlockのレイテンシの重さはだいたい以下のような関係

if() <<<< lock(), unlock()

初期化をする人は以下のように実行する

lock()
if (inited == false)
init()
inited = true
unlock()

それ以降の人はこのように実行する

lock()
unlock()

このときの初期化をする人、それ以降の人の割合は以下のような関係

初期化者 <<<<< 超えられない壁 <<<<<< それ以外

なので、いちいちlock, unlockを毎回させるのは嫌だ!!

これがダブルロックのモチベーション

ダブルロックとは

以下のような手順で行われる

if (inited == false)
    lock()
    if (inited == false)
        init()
        inited = true
    unlock()

初期化者は以下のように実行

if (inited == false)
lock()
if (inited == false)
init()
inited = true
unlock()

それ以外の人は以下のように実行

if (inited == false)

見てわかるようにlock,unlockを回避できた。だがしかし、2000年くらいに ただのダブルロックがすべてのアーキテクチャで安全ではないことが示された。

Intelのアーキとかだと、大体うまく動くようだが、Javaとかだと様々なアーキで 動かすことになるので、その問題が浮き彫りになったっぽい。 その出来事以降、Intelのプロセッサのマニュアルにもその趣旨に関する文が追加されている。 詳しくは以下の4/21日を参照する。

http://homepage1.nifty.com/herumi/diary/1204.html

C++11以降はスレッドセーフなロック手法を使っている。

C++のスレッドセーフロックの確認

以下のコードをコンパイルしてasmを見る

struct A {
   int a;
   A(int b) : a(b) {}
};
A& get_instance()
{
    static A a(2);
    return a;
}
$ c++ -std=c++11 -S -Ofast -o out.s main.cc
 .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 11
    .globl  __Z12get_instancev
    .align  4, 0x90
__Z12get_instancev:                     ## @_Z12get_instancev
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    movb    __ZGVZ12get_instancevE1a(%rip), %al
    testb   %al, %al
    jne LBB0_3
## BB#1:
    leaq    __ZGVZ12get_instancevE1a(%rip), %rdi
    callq   ___cxa_guard_acquire
    testl   %eax, %eax
    je  LBB0_3
## BB#2:
    movl    $2, __ZZ12get_instancevE1a(%rip)
    leaq    __ZGVZ12get_instancevE1a(%rip), %rdi
    callq   ___cxa_guard_release
LBB0_3:
    leaq    __ZZ12get_instancevE1a(%rip), %rax
    popq    %rbp
    retq
    .cfi_endproc

.zerofill __DATA,__bss,__ZZ12get_instancevE1a,4,2 ## @_ZZ12get_instancevE1a
.zerofill __DATA,__bss,__ZGVZ12get_instancevE1a,8,3 ## @_ZGVZ12get_instancevE1a

.subsections_via_symbols

これがスレッドセーフなロックのasm. __cxa_guard_acquire, __cxa_guard_releaseがそれである

こうするとスレッドセーフでない従来型なasmをはいてくれる

$ c++ -std=c++11 -S -Ofast -o out.s main.cc -fno-threadsafe-statics
 .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 11
    .globl  __Z12get_instancev
    .align  4, 0x90
__Z12get_instancev:                     ## @_Z12get_instancev
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    movb    __ZGVZ12get_instancevE1a(%rip), %al
    testb   %al, %al
    jne LBB0_2
## BB#1:
    movl    $2, __ZZ12get_instancevE1a(%rip)
    movb    $1, __ZGVZ12get_instancevE1a(%rip)
LBB0_2:
    leaq    __ZZ12get_instancevE1a(%rip), %rax
    popq    %rbp
    retq
    .cfi_endproc

.zerofill __DATA,__bss,__ZZ12get_instancevE1a,4,2 ## @_ZZ12get_instancevE1a
.zerofill __DATA,__bss,__ZGVZ12get_instancevE1a,1,0 ## @_ZGVZ12get_instancevE1a

.subsections_via_symbols

これが従来型。 以上でした。

BPFに関する情報収集

BPFについてサーベイしたので、それのまとめ. BPF for Dummiesのプロトタイプといえるよういしていけたら最高である。 現状は雑記状態なのでご了承いただきたい.

BPFとは,何をするためのものか

正直, 僕自身もよく分からない。 BPFはin kernelのパケットフィルタに最適な 仮想機械として設計実装されたが、現在はkernel内部のあらゆるデータフローを トレーシングやデバッグするために 用いられている。といった感じか。。。

構成

eBPFがattachできるポイントは現状で以下. ちなみにcBPFはsocketのみをサポートしている

  • socket (via setsockopt) (hook skb)
  • kprobe (via bcc) (func-call-infos)
  • uprobe (via bcc) (func-call-infos)
  • trace points (via bcc) (func-call-infos)
  • syscall (via seccmomp) (system-call-infos)
  • tc (no exploring)

みやすくするとこんな感じ(iovisorのスライド)

f:id:slankdev:20170508005046p:plain

引用: https://www.iovisor.org

cBPF,eBPF

eBPF(Extended BPF)の登場後、伝統的なBPFの区別のために伝統的なBPFをcBPF (Classic BPF)とよぶようになりました。現在では一般的にBPFと呼ぶとeBPFを さしていることがほとんどのようです。

違いを簡単にまとめた.

cBPF eBPF
Register 32bit 2 regs 64bit 10 regs
Memory stack stack
Instruction 4B ld/st to stack 1-8B ld/st to stack
Instruction 1-8B ld to packet 1-8B ld/st fo packet
Instruction Cond Jump forward Cond Jump forward/backward
Instruction ALU Instructions Same + Signed Shift + Bswap
Else . Helper Functions
Else . Helper Data Structure

引用: https://www.slideshare.net/PLUMgrid/ebpf-and-linux-networking

Linuxではより高度な作業を可能にするためSKBのフィールドをマクロで参照できるよう にしている。kernel docに概要がのせられているので、以下に示す。

  len                skb->len
  proto              skb->protocol
  type               skb->pkt_type
  poff               Payload start offset
  ifidx              skb->dev->ifindex
  nla                Netlink attribute of type X with offset A
  nlan               Nested Netlink attribute of type X with offset A
  mark               skb->mark
  queue              skb->queue_mapping
  hatype             skb->dev->type
  rxhash             skb->hash
  cpu                raw_smp_processor_id()
  vlan_tci           skb_vlan_tag_get(skb)
  vlan_avail         skb_vlan_tag_present(skb)
  vlan_tpid          skb->vlan_proto
  rand               prandom_u32()

引用: https://www.kernel.org/doc/Documentation/networking/filter.txt

CPUのIDまでとれるらしい。恐ろしい。。

命令セット

ここで書くと長くなってしまうので、別の記事に分割した。 そちらを参照すること。

slankdev.hatenablog.com

slankdev.hatenablog.com

活用例

  • bcc (Generic Tracing Tool)
  • seccomp
  • socket filter

その他キーワード