gobgpのgrpcとかbgpのflowspecとか見てきた流れで、ならばgobgpdつかっているときにcliスクリプトからflowspec投げるには?ということで、とりあえずできるようになる要点をピックアップ。デーモンconfigurationではafi-safi-name = "ipv4-flowspec", afi-safi-name = "ipv6-flowspec"を設定。
必須import
from google.protobuf.any_pb2 import Any import gobgp_pb2 import gobgp_pb2_grpc import attribute_pb2
デーモンとの通信チャネル作成
def connfactory(host, port): channel = grpc.insecure_channel(host + ':' + str(50051)) stub = gobgp_pb2_grpc.GobgpApiStub(channel) return stub
最後の実行で、デーモンサイトのlocal-asnが必要
def getbgp(stub): g = stub.GetBgp(gobgp_pb2.GetBgpRequest()) ret = {} for c in g.ListFields()[0]: if c.__class__.__name__ != "Global": continue for f in c.ListFields(): if f[0].__class__.__name__ == "FieldDescriptor": ret[f[0].name] = f[1] return ret
IPv4 or Ipv6 on flowspec おまじない変数
def family(v): afi = (v==4 and gobgp_pb2.Family.AFI_IP or gobgp_pb2.Family.Family.AFI_IP6) return gobgp_pb2.Family(afi=afi, safi=gobgp_pb2.Family.SAFI_FLOW_SPEC_UNICAST)
Network Layer Reachability Information部分の作成
- RFC的には”設定する順番には責任もってね"とある。typeを守るのは容易。複数の値条件の部分が?
- OptionのE bit(続くか終わりか)はライブラリがつけてくれている気がする。
- operatorで試してあるのは==だけ。。ANDも試せてない。
- type 7以降もやってないけども、特にtype11 DSCPというのが?
def build_flowspecipprefix(rules, typeval, ipprefix): assert(typeval in (1, 2)) s = ipprefix.split('/') prefix = s[0] prefix_len = (len(s)==2 and int(s[1])) or (prefix.find(':')>-1 and 128 or 32) # be more seriously o = Any() o.Pack(attribute_pb2.FlowSpecIPPrefix(type=typeval,prefix_len = prefix_len, prefix = prefix)) rules.append(o) def build_flowspeccomponent(rules, typeval, conditions): assert(typeval in (3, 4, 5, 6,)) items = [] for op, value in conditions: items.append(attribute_pb2.FlowSpecComponentItem(op=op, value=value)) o = Any() o.Pack(attribute_pb2.FlowSpecComponent(type=typeval, items=items)) rules.append(o)
flowspec action
- 今回の例ではtraffic-rateだけ*1
- TrafficRateExtendedには引数に'as’が定義されているが、文法上の理由で、pythonスクリプトから設定できない。この領域にはASNの下位2byteをいれておけとあるが、デフォルト値0(だとおもわれる)で問題ないのだと思う。*2
def build_action(rate): rate = float(rate) o = Any() o.Pack(attribute_pb2.TrafficRateExtended(rate=rate)) # can't let into 'as' return attribute_pb2.ExtendedCommunitiesAttribute(communities=[o])
AddPathで必要な引数コンテナの作成ヘルパ
def build_pattrs(v, nlri, rate, origin): ac = Any() ac.Pack(build_action(rate)) nullip = (v==4 and "0.0.0.0" or "::0") nh = Any() nh.Pack(attribute_pb2.MpReachNLRIAttribute(family=family(v), nlris=[nlri], next_hops=[nullip])) og = Any() og.Pack(attribute_pb2.OriginAttribute(origin=origin)) return (ac, nh, og) def build_nlri(rules): o = Any() o.Pack(attribute_pb2.FlowSpecNLRI(rules=rules)) return o
材料がそろったところで実行例。
src: 1.2.3.4/32
dst:9.8.7.6/32
protocol: udp
port(両方向): 1900,11211
rate-limit 0.0 bytes/sec :=> discard
の条件について
ver = 4 rules = [] build_flowspecipprefix(rules, 1, "1.2.3.4/32") build_flowspecipprefix(rules, 2, "9.8.7.6/32") build_flowspeccomponent(rules, 3, [(1,17)]) build_flowspeccomponent(rules, 4, [(1,1900),(1,11211),]) nlri = build_nlri(rules) stub = connfactory('127.0.0.1', 50051) source_asn = getbgp(stub)['as'] path = gobgp_pb2.Path(family=family(ver), nlri=nlri, pattrs=build_pattrs(ver, nlri, 0.0, 0), source_asn=source_asn) stub.AddPath(gobgp_pb2.AddPathRequest(table_type=gobgp_pb2.GLOBAL,path=path),timeout=10)
情報が入ったかどうかをgobgpコマンドで確認
nao@hnd:~/gobgp$ ./gobgp global rib -a ipv4-flowspec Network Next Hop AS_PATH Age Attrs *> [destination: 1.2.3.4/32][source: 9.8.7.6/32][protocol: ==udp][port: ==1900 ==11211] fictitious 00:00:27 [{Extcomms: [discard]} {Origin: i}]
以上です。
参考: