13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ContainerLabでBGP環境にsFlowを導入!macOS(ARM64)でハマった話と解決法

13
Last updated at Posted at 2025-10-22

はじめに

GMOコネクトの永田です。

前回の記事のBGP最小topologyに対し、sFlowでのテレメトリ収集を入れてみました。
macOSで動作させる場合に、意外と苦労したので、手順をまとめておきます。

まとめ

  • BGPルータにsFlowテレメトリ収集機能を追加
    • FRRルータにhost-sflowを組み込んだカスタムDockerイメージを作成し、別途nfdump/sfcapdのCollectorノードを追加した構成をcontainerlabで構築
  • host-sflowのバージョン問題
    • 最新版(v2.1.16)ではVETHインターフェースがキャプチャ対象外になるため、v2.1.13-2にダウングレードして対応
  • macOS(AppleSilicon ARM64)上のdevcontainerでもsFlowキャプチャを確認
    • srcからdstへのICMP通信を生成し、collectorノードでnfdumpコマンドを使ってsFlowデータ(送信元/宛先IP、パケット数、バイト数など)を確認できることを実証

sFlowとは

皆さんも自宅ルーターに導入しているかもしれないですが、トラフィックの統計情報を収集する技術の1つです。

詳細は以下を参照してください。

最後の参考ページの図にある通り「Exporter」と「Collector」という概念が、アーキテクチャ的には重要です。
今回は既存のRouterが「Exporter」を兼任し、「Collector」を新規に設置します。

試したtopology

今回のトポロジー定義は以下となります。
r1, r2からcollectorへのsFlowの線が増えています。

なお、動作させる環境はいつも通りです。

  • MacBook Pro Apple M4 Max 36GBメモリ
  • VSCode + Devcontainer
  • containerlab 0.71.0

topology設定

では早速containerlabでtopologyを組んでいきます。

前回からの主な変更点

  • ルータノード(r1, r2)にsFlowエージェントを同梱したローカルイメージlocal/frr_sflow:latestを導入
  • sFlowコレクタ用ノードを追加し、ローカルイメージlocal/nfdump-sflow:latestnfdump/sfcapdを常駐
  • テレメトリ収集用に管理ネットワーク(172.100.101.0/24)を分離し、各ノードに管理IPを割り当て
  • ルータのsFlowサンプリング設定(hsflowd.conf)を追加し、BGPピア間・ホスト接続インターフェースの両方を監視対象に設定

clab yml

変更点のポイントは以下です。

  • collectorのIPを固定にしたかったので、mgmt で管理LANを明に指定
    • 各nodeのmgmt-ipv4でIPを明に指定
  • nodeにcollector追加
  • routerのimageはsFlow exporterを組み込んだimageに変更(詳細は後述)
  • routerにhsflowd.confが増えているが後述
name: clab-bgp-sflow-mini-topo
mgmt:
  network: custom_mgmt
  ipv4-subnet: 172.100.101.0/24
topology:
  nodes:
    r1:
      kind: linux
      image: local/frr_sflow:latest # quay.io/frrouting/frr:10.4.1
      mgmt-ipv4: 172.100.101.2
      binds:
        - r1/daemons:/etc/frr/daemons
        - r1/frr.conf:/etc/frr/frr.conf
        - r1/vtysh.conf:/etc/frr/vtysh.conf
        - r1/hsflowd.conf:/etc/hsflowd.conf
    r2:
      kind: linux
      image: local/frr_sflow:latest # quay.io/frrouting/frr:10.4.1
      mgmt-ipv4: 172.100.101.3
      binds:
        - r2/daemons:/etc/frr/daemons
        - r2/frr.conf:/etc/frr/frr.conf
        - r2/vtysh.conf:/etc/frr/vtysh.conf
        - r2/hsflowd.conf:/etc/hsflowd.conf
    src:
      kind: linux
      image: praqma/network-multitool:latest
      mgmt-ipv4: 172.100.101.11
      exec:
        - "ip link set eth1 up"
        - "ip addr add 192.168.1.11/24 dev eth1"
        - "ip route add 192.168.0.0/16 via 192.168.1.1 dev eth1"
    dst:
      kind: linux
      mgmt-ipv4: 172.100.101.12
      image: praqma/network-multitool:latest
      exec:
        - "ip link set eth1 up"
        - "ip addr add 192.168.2.11/24 dev eth1"
        - "ip route add 192.168.0.0/16 via 192.168.2.1 dev eth1"
    collector:
      kind: linux
      image: local/nfdump-sflow:latest
      mgmt-ipv4: 172.100.101.100
  links:
    # for bgp peering
    - endpoints: [r1:eth2, r2:eth2]
    # for host connectivity
    - endpoints: [src:eth1, r1:eth1]
    - endpoints: [dst:eth1, r2:eth1]

FRRouting Config

daemons, frr.conf, vtysh.confは、前回と全て同じなので説明を省略します。

host sflow agent Config(r1/r2)

こちらのOSSをsFlow exporterとして、今回利用します。

Configの設定ドキュメントはこちら。

hsflowd.conf の設定のポイントは以下です。

  • collectorのipを指定
  • 全パケットをキャプチャ対象とする(実運用だとサンプリングだが、今回は検証目的なので)
    • sampling.bps_ratio=0
    • sampling=1
  • mgmtを除いた、hostとBGP peerをキャプチャ対象とする
    • dev=eth1 (ホスト接続)
    • dev=eth2 (BGPピア)
sflow {
  collector { ip=172.100.101.100 }
  sampling.bps_ratio=0
  sampling=1
  pcap { dev=eth1 }
  pcap { dev=eth2 }
}

追加したローカルDockerイメージ

最後に、今回用に追加したDockerイメージをみておきます。

local/frr_sflow:latest

  • ベースはquay.io/frrouting/frr:10.4.1
  • ビルドステージでsflow/host-sflowリポジトリのhsflowdをAlpine上でビルドし、実行イメージにバイナリと設定をコピー
FROM alpine:3.22 AS build
RUN apk --update add \
      build-base \
      gcc \
      git \
      libpcap-dev \
      linux-headers \
 && git clone https://github.com/sflow/host-sflow.git \
 && cd host-sflow \
 && git checkout v2.1.13-2 \
 && sed -i 's/#define SFL_INTERNAL_INTERFACE 0x3FFFFFFF/#define SFL_INTERNAL_INTERFACE 0/g' src/sflow/sflow.h \
 && make FEATURES="PCAP" \
 && make install

FROM quay.io/frrouting/frr:10.4.1
COPY --from=build /usr/sbin/hsflowd /usr/sbin/hsflowd
COPY --from=build /etc/hsflowd/ /etc/hsflowd/
RUN apk add --no-cache dmidecode libpcap
ADD start.sh /
RUN chmod +x /start.sh
ENTRYPOINT [ "/sbin/tini", "--", "/start.sh" ]

start.sh

#!/bin/sh

chown -R frr:frr /etc/frr

/usr/sbin/hsflowd
exec /usr/lib/frr/docker-start
  • hsflowdを起動したあと、既存の/usr/lib/frr/docker-startに処理を委譲

host-sflowのversion

今回、git checkout v2.1.13-2 と特定のtag versionとしています。
本記事執筆時点での最新はv2.1.16-1なのですが、devcontainerで起動するとpcapでのキャプチャが対象外となっていたため、少し古いバージョンで試しています。

v2.1.16の場合、debugで起動( /usr/sbin/hsflowd -ddd )すると以下のようなログがでます。(なお、build時にclangも追加で必要になります)
devType=VETH としてキャプチャがスキップされています。

dbg1:evt_config_first: first valid configuration
dbg1:main: evt_config_changed()
dbg1:evt_config_shake: reply from poll
mod_pcap:skip eth2 (devType=VETH)
mod_pcap:skip eth1 (devType=VETH)
dbg1:evt_config_shake: reply from packet
dbg1:evt_config_shake: sync complete
dbg1:drop_priviliges: getuid=0

v2.1.13の場合は、このように( ethx opened OK )pcapでのキャプチャが開始されます。

dbg1:evt_config_shake: reply from poll
mod_pcap:addBPFSocket(eth2) speed=10000000000
dbg1:eth2 (speed=10000000000) using global_default sampling rate = 1
mod_pcap:device eth2 opened OK
mod_pcap:device eth2 offers DLT=1 (EN10MB)
mod_pcap:device eth2 offers DLT=143 (DOCSIS)
mod_pcap:device eth2 selecting encapsulation=1 (EN10MB)
mod_pcap:addBPFSocket(eth1) speed=10000000000
dbg1:eth1 (speed=10000000000) using global_default sampling rate = 1
mod_pcap:device eth1 opened OK
mod_pcap:device eth1 offers DLT=1 (EN10MB)
mod_pcap:device eth1 offers DLT=143 (DOCSIS)
mod_pcap:device eth1 selecting encapsulation=1 (EN10MB)
dbg1:evt_config_shake: reply from packet
dbg1:evt_config_shake: sync complete
・・・
_root:takeSample: hook=0 tap=eth2 in=eth2 out=<not found> pkt_len=56 cap_len=56 mac_len=14 (AAC1AB93D915 -> 333300000002 et=0x86DD)
_root:selected sampler eth2 ifIndex=1033
_root:takeSample: hook=0 tap=eth1 in=eth1 out=<not found> pkt_len=56 cap_len=56 mac_len=14 (AAC1AB57AD86 -> 333300000002 et=0x86DD)
_root:selected sampler eth1 ifIndex=1035
_root:takeSample: hook=0 tap=eth1 in=<not found> out=<not found> pkt_len=56 cap_len=56 mac_len=14 (AAC1ABC111F4 -> 333300000002 et=0x86DD)

local/nfdump-sflow:latest

次にsFlow collectorのDocker imageです。
こちらのOSSを利用します。

  • ベースはdebian:12-slim
  • apt install nfdump-sflowsfcapdなどcollectorを導入
  • /tmp/sflow_capにフローを保存するためのディレクトリを作成
  • デフォルトCMDでsfcapdをTCP/UDP 6343(デフォルトsFlowポート)で常駐させ、キャプチャファイルをローテーション
FROM debian:12-slim
RUN apt update && apt install -y nfdump-sflow
RUN mkdir -p /tmp/sflow_cap
CMD ["sh", "-c", "/usr/bin/sfcapd -D -p 6343 -w /tmp/sflow_cap && tail -f /dev/null"]

動かしてみた

以下はリポジトリルートで実行した手順です。ローカルビルドした2つのDockerイメージを使ってトポロジーを起動し、ICMPトラフィックのsFlowサンプルをnfdumpで確認します。

1. FRR+sFlow exporterイメージとsFlow Collectorイメージをビルド

cd clab-bgp-sflow-mini-topo/docker/apline_frr_sflow
docker buildx build . -t local/frr_sflow:latest

cd ../debian12_nfdump
docker buildx build . -t local/nfdump-sflow:latest

2. containerlabでトポロジーを起動

containerlab deploy --topo bgp-sflow-mini-topo.clab.yml

3. srcからdstへのICMPを生成(サンプリング対象トラフィック)

docker exec clab-clab-bgp-sflow-mini-topo-src ping -c 5 192.168.2.11

4. collectorsfcapdが出力したキャプチャファイルをnfdumpで照会

docker exec -it clab-clab-bgp-sflow-mini-topo-collector \
  nfdump -r /tmp/sflow_cap/$(ls /tmp/sflow_cap | tail -n1) -o raw | head

-o rawオプションをつけると、より詳細な情報もみれます。

collector# nfdump -o raw -r nfcapd.202510210410

Flow Record: 
  RecordCount  =              1649
  Flags        =              0x02 SFLOW v5, Sampled
  Elements     =                 7: 1 2 4 6 7 12 15 
  size         =               164
  engine type  =                 0
  engine ID    =                 0
  export sysid =                 2
  first        =     1761020096934 [2025-10-21 04:14:56.934]
  last         =     1761020096934 [2025-10-21 04:14:56.934]
  received at  =     1761020096934 [2025-10-21 04:14:56.934]
  proto        =                 1 ICMP
  tcp flags    =              0x00 ........
  ICMP         =               0.0  type.code
  in packets   =                 1
  in bytes     =               102
  src addr     =      192.168.2.11
  dst addr     =      192.168.1.11
  input        =               623
  output       =                 0
  src mask     =                 0 /0
  dst mask     =                 0 /0
  fwd status   =                 0
  dst tos      =                 0
  direction    =                 0
  biFlow Dir   =              0x00 
  end reason   =              0x00 
  src vlan     =                 0
  dst vlan     =                 0
  src as       =                 0
  dst as       =                 0
  ip exporter  =     172.100.101.3
  in src mac   = aa:c1:ab:e4:78:c7
  out dst mac  = aa:c1:ab:d1:16:da
  in dst mac   = 00:00:00:00:00:00
  out src mac  = 00:00:00:00:00:00

期待通り、src --> dstへのping(ICMP)が記録されていますね!

(再掲)まとめ

  • BGPルータにsFlowテレメトリ収集機能を追加
    • FRRルータにhost-sflowを組み込んだカスタムDockerイメージを作成し、別途nfdump/sfcapdのCollectorノードを追加した構成をcontainerlabで構築
  • host-sflowのバージョン問題
    • 最新版(v2.1.16)ではVETHインターフェースがキャプチャ対象外になるため、v2.1.13-2にダウングレードして対応
  • macOS(AppleSilicon ARM64)上のdevcontainerでもsFlowキャプチャを確認
    • srcからdstへのICMP通信を生成し、collectorノードでnfdumpコマンドを使ってsFlowデータ(送信元/宛先IP、パケット数、バイト数など)を確認できることを実証

最後に、GMOコネクトでは研究開発や国際標準化に関する支援や技術検証をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。

お問合せ: https://gmo-connect.jp/contactus/

13
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?