【実務・中級編】 802.1QフレームのPCP(Priority Code Point)フィールドの振る舞い – インフラ・物理&L2/L3ネットワーク基礎実践ガイド

Ethernetの隠し味:802.1Q PCPでパケットに「優先度」を与える方法

ども、お疲れ様です!インフラの現場で長年パケットの海を漂ってきたベテランエンジニアです。Web APIの設計にしても、インフラの運用にしても、結局は「どうやってデータを効率的かつ確実に届けられるか」がキモですよね。今日は、そんなデータ伝送の裏側で、ちょっとした「隠し味」として効いてくる、EthernetフレームのPCPフィールドについて、実務で役立つように深掘りしていきましょう。

なぜ「優先度」が必要なのか?

最近のネットワークは、単にデータを送るだけでなく、色々な種類のトラフィックが混在しています。Webサイトの閲覧、動画ストリーミング、VoIP通話、そしてもちろん、API通信。これらはそれぞれ、遅延への許容度や帯域幅の要求が大きく異なります。

例えば、リアルタイム性が命のVoIP通話が、大量のファイルダウンロードの影に隠れてしまって、声が途切れたり遅延したりしたら、ビジネスになりませんよね。そこで登場するのが、ネットワーク機器がトラフィックに「優先度」をつけて、より重要なパケットを先に処理するための仕組みです。

Ethernetの世界で、この優先度を制御するのが、今回のお題である802.1QフレームのPCPフィールドです。

802.1Qタグって、そもそも何?

まず、PCPフィールドを理解するために、その親玉である802.1Qタグについて触れておきましょう。VLAN(Virtual LAN)を使っている環境なら、きっと見慣れたものだと思います。

802.1Qタグは、Ethernetフレームのヘッダーに挿入される、比較的短い情報(4バイト)です。このタグのおかげで、物理的には同じネットワークセグメントにいるのに、論理的には異なるネットワークとして扱ったり、パケットに優先度を付けたりできるようになります。

802.1Qタグの構造は、ざっくり言うとこんな感じです。

+-----------------+-----------------+-----------------+-----------------+
|  TPID (2 Octets)|   TCI (2 Octets)|
+-----------------+-----------------+-----------------+-----------------+
  • TPID (Tag Protocol Identifier): これは、このフレームが802.1Qタグ付きであることを示す識別子です。通常は0x8100が使われます。
  • TCI (Tag Control Information): こちらが本題。この2バイトの中に、VLAN IDと、今回注目するPCPフィールドが含まれています。

PCPフィールド:3ビットに込められた「優先度」

TCIの中身をもう少し詳しく見てみましょう。

+-------+-----------+---+
| PCP(3)| DEI(1)    |VLAN ID(12)|
+-------+-----------+---+
  • PCP (Priority Code Point): これが、私たちが今回フォーカスする3ビットのフィールドです。0から7までの8段階の優先度を表すことができます。数値が大きいほど、優先度が高いと解釈されるのが一般的です。
  • DEI (Drop Eligible Indicator): こちらは1ビットのフィールドで、ネットワークが混雑した際に、このパケットをドロップ(破棄)しても良いかどうかを示すフラグです。
  • VLAN ID (12 bits): どのVLANに属するパケットかを示す識別子です。

今日のお目当ては、このPCPフィールドです。この3ビットで、ネットワーク機器に「このパケットは重要だから、先に処理してね!」と伝えるわけです。

PCP値と、その「意味」

PCPフィールドは、0から7までの値を持ちますが、これらの値が具体的にどのようなトラフィックに対応するのかは、実は規格で厳密に定義されているわけではありません。しかし、一般的には以下のようなマッピングがよく使われます。

| PCP 値 | 一般的な用途 | 備考 |
| :—– | :———————————– | :——————————————————————- |
| 7 | Network Control (e.g., STP, OAM) | ネットワーク制御用のプロトコル。最優先。 |
| 6 | Network Control (e.g., STP, OAM) | 同上。 |
| 5 | Voice (VoIP) | 音声データ。遅延に非常に敏感。 |
| 4 | Video (Video Conferencing) | 動画データ。遅延に敏感だが、音声ほどではない。 |
| 3 | Streaming Video | ストリーミング映像。 |
| 2 | Call Signaling | 通話制御シグナリング。 |
| 1 | Reserved for future use | 将来のために予約。 |
| 0 | Best Effort (Default) | 通常のデータ通信。優先度なし。 |

重要なのは、これらのマッピングは「デファクトスタンダード」であり、ネットワーク機器の設定や、組織のポリシーによって変更される可能性があるということです。

L2スイッチにおけるPCPの振る舞い

では、このPCPフィールドが、実際にL2スイッチでどのように使われるのでしょうか?

スイッチは、受信したEthernetフレームのPCPフィールドの値を見て、パケットを「キュー(Queue)」と呼ばれる待ち行列に振り分けます。そして、各キューには異なる処理優先度が割り当てられているため、優先度の高いキューにあるパケットから順に転送される、という仕組みです。

通信フロー(シーケンス)

1. 送信元デバイス: アプリケーションから送信されるデータは、OSのネットワークスタックを通過します。もし、そのアプリケーションが(例えばVoIPクライアントなど)優先度を意識した設計になっている場合、または、OSやミドルウェアがトラフィックの種類を判別して、802.1QタグにPCP値を設定する場合、タグ付きフレームが生成されます。
2. L2スイッチ(入力ポート): スイッチはフレームを受信し、802.1Qタグがあれば、その中のPCP値を確認します。
3. キューへの振り分け: スイッチは、PCP値に基づいて、フレームを適切な出力キューに振り分けます。例えば、PCP=5のVoIPパケットは、VoIP用の優先キューに入ります。
4. L2スイッチ(出力ポート): スイッチは、各キューの優先度に従って、パケットを転送します。優先度の高いキューにあるパケットが、優先度の低いキューのパケットよりも先に、出力ポートから送信されます。
5. 宛先デバイス: 宛先デバイスは、受信したフレームのPCP値を参照し、必要に応じて処理を行います。

コード例:PCP値の設定(概念)

実際のPCP値の設定は、ネットワーク機器のCLIやAPIで行われます。ここでは、概念的な説明として、どのような設定が行われるかを示します。

1. スイッチの設定(Cisco IOS風)

多くのL2スイッチでは、ポート単位や、VLAN単位で、受信したトラフィックのPCP値を変更したり、PCP値に基づいてキューイングポリシーを設定したりします。

# ポートに受信したトラフィックのPCP値を、トラフィックの種類に応じて書き換える
# 例: VoIPトラフィック(UDPポート 5060, 10000-20000)はPCP=5に設定
interface GigabitEthernet1/0/1
  description Uplink to Core
  switchport mode trunk
  mls qos  # QoS (Quality of Service) を有効にする
  // ここで、トラフィッククラスにPCP値をマッピングする設定が入る
  // 例: policy-map for-ingress
  //   class voice
  //     set cos 5  // COS (Class of Service) はPCPとほぼ同義で使われることが多い
  //   class video
  //     set cos 4
  //   class class-default
  //     set cos 0
  // mls qos input-output-map ip-dscp cos  // DSCPからCOSへのマッピング例
  // mls qos map cos-tos 0 1 2 3 4 5 6 7 output-queue 1 2 3 4 5 6 7 8  // COS値と出力キューのマッピング
  // service-policy input policy-map-ingress
!

解説:

  • mls qos: QoS機能を有効にします。
  • set cos <値>: 受信したパケットのPCP(またはCOS)値を指定した値に設定します。
  • class <クラス名>: トラフィックを分類するためのクラスです。
  • service-policy input <ポリシーマップ名>: ポートに入ってくるトラフィックに対して、定義したポリシーを適用します。

2. Linuxカーネルでの設定(tcコマンド)

Linuxサーバーでも、tcコマンドを使って、パケットの優先度を制御できます。これは、サーバー自身がL2スイッチのように振る舞う場合や、サーバーから送信されるパケットのPCP値を制御したい場合に役立ちます。

# tcコマンドを使ったPCP値の設定例(概念)
# まず、qdisc (キューイングディスク) を追加
sudo tc qdisc add dev eth0 root handle 1: prio bands 8

# 各優先度レベルに対応するキューを作成
sudo tc qdisc add dev eth0 parent 1:1 handle 10: sfq
sudo tc qdisc add dev eth0 parent 1:2 handle 11: sfq
sudo tc qdisc add dev eth0 parent 1:3 handle 12: sfq
sudo tc qdisc add dev eth0 parent 1:4 handle 13: sfq
sudo tc qdisc add dev eth0 parent 1:5 handle 14: sfq
sudo tc qdisc add dev eth0 parent 1:6 handle 15: sfq
sudo tc qdisc add dev eth0 parent 1:7 handle 16: sfq
sudo tc qdisc add dev eth0 parent 1:8 handle 17: sfq

# 特定のトラフィック(例: UDPポート 5060)をPCP=5のキューに割り当てる
# これには、iptablesとの連携が必要になる場合が多い
# sudo iptables -t mangle -A POSTROUTING -p udp --dport 5060 -j MARK --set-mark 5
# sudo tc filter add dev eth0 parent 1: protocol ip prio 1 handle fw flow mark 5

解説:

  • tc qdisc add dev eth0 root handle 1: prio bands 8: eth0インターフェースに、8つのバンド(優先度レベル)を持つprioキューイングメカニズムを追加します。
  • tc qdisc add dev eth0 parent 1:N handle NN: sfq: 各優先度バンドに対応する実際のキュー (sfq – Stochastic Fairness Queuing) を作成します。
  • iptables -t mangle -A POSTROUTING -p udp --dport 5060 -j MARK --set-mark 5: iptablesで、UDPポート5060のパケットにマーキング(5)を付けます。
  • tc filter add ... handle fw flow mark 5: tcで、iptablesによって付けられたマーキング5を持つパケットを、優先度5のキューに振り分けます。

このLinuxの例は、少し高度ですが、サーバー側でもパケットの優先度を細かく制御できることを示しています。

Web APIとPCP:意外な関係性

「Web APIとPCP? どこが関係あるんだ?」と思われるかもしれません。

実は、Web APIの通信も、最終的にはEthernetフレームに乗ってネットワークを流れていきます。APIリクエストやレスポンスが、もしリアルタイム性や低遅延を要求されるようなアプリケーション(例:リアルタイムゲームのバックエンドAPI、金融取引システム、IoTデバイスとの連携)で使われている場合、その通信の品質を保証するためにPCP値が活用されることがあります。

通信フロー(Web APIの場合)

1. クライアント(Webブラウザ、モバイルアプリ、他のサーバー):

  • APIリクエストを生成します。
  • OSのネットワークスタックが、HTTP/HTTPSリクエストをTCP/IPパケットにエンカプセル化します。
  • もし、クライアント側のOSやアプリケーションが、ネットワークトラフィックの品質を管理する機能(例:OSのQoS設定、特定のアプリケーションによるタグ付け)を持っている場合、生成されるEthernetフレームにPCP値が設定されることがあります。

2. ネットワーク経由: パケットは、スイッチ、ルーターなどを経由してサーバーへ向かいます。途中のL2スイッチは、PCP値を見て、パケットの優先度を判断し、キューイングを行います。
3. サーバー:

  • 受信したパケットは、OSのネットワークスタックを通過します。
  • Webサーバー(Nginx, Apache, etc.)やアプリケーションサーバーがHTTP/HTTPSリクエストを処理します。
  • サーバー側のOSやネットワークインターフェースカード(NIC)が、PCP値を認識し、それに応じた処理(例:CPUスケジューリング、I/O処理の優先度付け)を行うこともあります。

コード例:Fetch APIでのPCP値の直接的な操作は限定的

残念ながら、ブラウザのJavaScriptから直接Fetch APIを使って、送信するHTTPリクエストのEthernetフレームにPCP値を設定することはできません。PCP値は、OSのネットワークスタックや、ネットワーク機器の設定によって管理される、より低レベルな情報だからです。

しかし、間接的に影響を与えることは可能です。

  • OSレベルでのQoS設定: サーバー側で、特定のアプリケーション(例えば、Webサーバープロセス)からのアウトバウンドトラフィックに対して、OSのtcコマンドなどでPCP値を高く設定することは可能です。これにより、APIレスポンスが優先的に転送されるようになります。
  • ネットワーク機器の設定: ネットワークの入り口や出口にあるスイッチやルーターで、特定の送信元IPアドレス(APIサーバー)や宛先IPアドレス(APIクライアント)からのトラフィックを識別し、PCP値を設定・操作することは一般的です。

PythonでのPCP値の(間接的な)操作例

PythonでWeb APIサーバーを構築している場合、サーバー自身のネットワークスタックで、送信するパケットのPCP値を制御したい場面があるかもしれません。これは、scapyのようなライブラリを使って、パケットを直接構築・送信することで実現できます。ただし、これにはroot権限が必要になることが多く、一般的なWebアプリケーションの範疇を超える操作となります。

# scapyを使ったPCP値付きEthernetフレームの構築例(root権限が必要)
from scapy.all import Ether, IP, TCP, sendp

# Ethernetヘッダーの設定
# dst: 宛先MACアドレス (例: スイッチのMACアドレス)
# src: 送信元MACアドレス (例: サーバーのMACアドレス)
# type: EtherType (0x8100 は 802.1Q タグを示す)
ether_layer = Ether(src="00:11:22:33:44:55", dst="AA:BB:CC:DD:EE:FF", type=0x8100)

# 802.1Q タグの設定
# vlan: VLAN ID (例: 10)
# PCP: Priority Code Point (例: 5 - VoIP相当)
# DEI: Drop Eligible Indicator (例: 0 - ドロップ対象外)
dot1q_layer = Dot1Q(vlan=10, pcp=5, dei=0)

# IPヘッダーの設定
# src: 送信元IPアドレス
# dst: 宛先IPアドレス
ip_layer = IP(src="192.168.1.100", dst="192.168.1.200")

# TCPヘッダーの設定
# sport: 送信元ポート (例: APIサーバーのポート)
# dport: 宛先ポート (例: APIクライアントのポート)
tcp_layer = TCP(sport=8000, dport=8080, flags="S") # SYNフラグ

# パケットの結合
packet = ether_layer / dot1q_layer / ip_layer / tcp_layer

# パケットの送信 (raw socketを使用するため、root権限が必要)
# iface: 送信インターフェース (例: 'eth0')
sendp(packet, iface="eth0", verbose=False)

print("802.1Qタグ付きパケットを送信しました (PCP=5)。")

解説:

  • Ether(): Ethernetヘッダーを定義します。type=0x8100で802.1Qタグ付きであることを示します。
  • Dot1Q(): 802.1Qタグの情報を定義します。pcp=5で優先度を5に設定しています。
  • IP()、TCP(): IPおよびTCPヘッダーを定義します。
  • sendp(): 指定したインターフェースから、レイヤー2(Ethernet)レベルでパケットを送信します。

このコードは、あくまで「パケットを構築する」という例であり、実際のAPI通信でこのようにパケットを直接生成して送信するケースは稀です。通常は、OSやネットワーク機器が自動的に適切なPCP値を付与、または操作します。

まとめ:PCPを理解し、ネットワークを「味付け」する

802.1QのPCPフィールドは、Ethernetフレームに「優先度」という概念を吹き込むための、小さくも強力な仕組みです。Web APIの通信も、結局はこのEthernetフレームに乗って運ばれるため、ネットワークの品質が求められる場面では、PCP値が重要な役割を果たします。

  • PCPは802.1QタグのTCIフィールドの一部で、3ビット(0-7)の優先度を表す。
  • 一般的に、値が大きいほど優先度が高い。
  • L2スイッチはPCP値を見て、パケットを異なる優先度のキューに振り分ける。
  • VoIPや動画ストリーミングなど、リアルタイム性が求められるトラフィックに高いPCP値が割り当てられることが多い。
  • Web APIの文脈では、サーバー側OSやネットワーク機器の設定を通じて、API通信の品質に影響を与える可能性がある。

実務では、ネットワーク機器のQoS設定を理解し、PCP値がどのように扱われているかを把握することが、トラブルシューティングやパフォーマンスチューニングの鍵となります。

「うちのAPI、なんか遅いんだよな…」と感じたら、もしかしたら、ネットワークのどこかで、パケットが「優先度」をうまく与えられずに、順番待ちをしているのかもしれません。そんな時は、このPCPフィールドの存在を思い出してみてください。きっと、問題解決の糸口が見つかるはずです。

それでは、また現場で会いましょう!

コメント

タイトルとURLをコピーしました