はじめに
SONiCに興味を持たれてる方には釈迦に説法な感じもしますが一応説明すると、Access Control Listの頭文字を並べてACLです。パケットヘッダの指定フィールドが特定の値(たとえばEthernet Typeの値が0x0800、意味としてはIPv4パケット)を持つとき、そのパケットをdropしたり、指定のポートに転送したりするといったように、条件と実行内容を書き連ねたリストであり、またそのリスト通りに処理を実行する機能の名称としても使われます。
SONiCで設定されたACLは、ホワイトボックススイッチに搭載されているスイッチASICで処理されます。つまりハードウェアで処理されるのですが、ASICに実装されていない機能は当然ですが処理できません。下記で設定可能パラメータを列挙していますが、指定できるからと言ってすべての組み合わせがどのスイッチでも動作するとは限らないことに注意してください。
SONiCのACL基本構造
テーブルを定義して、そのテーブルにルールを書き連ねます。
テーブル
- テーブル名 (任意の文字列)
- テーブルタイプ (L3 or mirror)
- 対象ポート
- ステージ (ingress or egress)
対象ポートがテーブルに紐付いていますので、ポートごとに違うルールを適用したい場合はテーブルを分けます。
ルール
- テーブル名 (定義されたテーブルの名前)
- ルール名 (任意の文字列)
- 優先順位 (0〜999999。値の大きいほうが優先、つまり先に実行される)
- 条件(match)
- 実行内容(action)
条件
組み合わせ(and)で指定できます。orの場合は別のルールを並べます。
ヘッダフィールド一覧
IN_PORTS
OUT_PORTS
SRC_IP
DST_IP
SRC_IPV6
DST_IPV6
L4_SRC_PORT
L4_DST_PORT
ETHER_TYPE
IP_PROTOCOL
NEXT_HEADER
TCP_FLAGS
IP_TYPE
DSCP
L4_SRC_PORT_RANGE
L4_DST_PORT_RANGE
TC
ICMP_TYPE
ICMP_CODE
TUNNEL_VNI
INNER_ETHER_TYPE
INNER_IP_PROTOCOL
INNER_L4_SRC_PORT
INNER_L4_DST_PORT
実行内容
現在4種類の実行内容(アクション)が定義されています。
-
FORWARD
(パケット転送) -
DROP
(パケット破棄) -
REDIRECT
(パケット転送先の変更) -
DO_NOT_NAT
(NAT対象外とする)
ここでひとつ実ハードウェアの話を書いておきます。Broadcom Trident3は、ハードウェア的にあるいはSDKやSAI APIとして、ACLのREDIRECT
アクションをサポートしています。しかし、SAIに対して「どんなアクションがあるか」queryするAPIを呼び出すとエラーが返ってきます(2020年12月時点)。
SONiCのACL実装では、事前のqueryに失敗すると最低限のアクションしか設定できず、他はエラーとして受け付けないようになっています。そのため、Trident3搭載スイッチ上で動かすSONiCではREDIRECT
アクションを使えません。どうしてもREDIRECT
が必要であれば、やや無理やりですがソースコード内の「最低限のアクション」のところにREDIRECT
を書き足してビルドするという手順で対応できます。
Schemaが異なる2つのJSON
OpenConfig YANG model
"acl"
, "acl-sets"
からはじまるJSONは、OpenConfig標準で定義されているACLのフォーマットです。config acl
コマンドやacl-loader
コマンドが受け付けるのはこちらのフォーマットです。
config acl
コマンドは下記のように使います。
-
config acl add TABLE_NAME TABLE_TYPE
- テーブルの追加 -
config acl update ファイル
- ルールの更新 -
config acl remove TABLE_NAME
- テーブルの削除
ZTP (Zero Touch Provisioning)でACL URLを指定されていた場合、このフォーマットのJSONをURLから取得し、起動時に自動的に適用させることができます。
なお、キーワードが上記の説明と若干違っていたりします。YANG Modelの定義を参照してください。
例
sonic-ssh-only
や Sonic-SNMP_ACL
がテーブル名です。ルールにはシーケンス番号を振りますが、名前はありません。
{
"acl": {
"acl-sets": {
"acl-set": {
"sonic-ssh-only": {
"acl-entries": {
"acl-entry": {
"1": {
"config": {
"sequence-id": 1
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"ip": {
"config": {
"protocol": "IP_TCP",
"source-ip-address": "192.168.0.0/18"
}
},
"transport": {
"config": {
"destination-port": "22"
}
}
},
"2": {
"config": {
"sequence-id": 2
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"ip": {
"config": {
"protocol": "IP_TCP",
"source-ip-address": "192.168.192.0/18"
}
},
"transport": {
"config": {
"destination-port": "22"
}
}
}
}
},
"Sonic-SNMP_ACL": {
"acl-entries": {
"acl-entry": {
"1": {
"config": {
"sequence-id": 1
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"ip": {
"config": {
"protocol": "IP_UDP",
"source-ip-address": "192.168.0.0/18"
}
}
}
}
},
"config": {
"name": "Sonic-SNMP_ACL"
}
}
}
}
}
}
config_db.json
config acl
コマンドやacl-loader
コマンドを使って流し込んだ結果としてConfig DBに書き込まれる内容です。設定後に show runningconfiguration all
で参照できます。config save
できますし、あらかじめ/etc/sonic/config_db.json
に書いておくこともできます。
記述する際の注意点ですが、値としてシンボリックネームが使えません。たとえば"IP_PROTOCOL": "TCP"
は無効です。"IP_PROTOCOL": "6"
とキジュする必要があります。ご注意ください。
例
{
"ACL_TABLE": {
"TestTable": {
"ports": {
"Ethernet0"
"Ethernet4",
"Ethernet8"
},
"type": "l3",
"stage": "ingress"
}
},
"ACL_RULE": {
"TestTable|Rule1": {
"PRIORITY": "10",
"SRC_IP": "192.168.0.1",
"PACKET_ACTION": "REDIRECT:Ethernet0"
},
"TestTable|DefaultRule": {
"PRIORITY": "1",
"ETHER_TYPE": "0x0800",
"PACKET_ACTION": "DROP"
}
}
}
どちらを使うべき?
オペレーションや標準に沿うことを考えるとOpenConfigのほうがつぶしが利きます。SONiC依存ではありませんので、他のプラットフォームでも同じ記述を使い回せます。
ただし、機能面から考えると、config_db.json
を使わざるを得ないケースもあるかと思います。一例を挙げると、実装との間に下記のような相違があります。
- OpenConfigには(SONiCでは指定可能な)redirect actionが定義されていない。
- OpenConfigにはL2タイプがある(が、SONiCでは実装がない)
おわりに
YAMAHAのルータなどでCLIを使ってフィルタルールを設定するのと比較すると、どうしても記述が冗長になってしまうのはしかたのないところだと思います。