diff --git a/src/yangerd/go.mod b/src/yangerd/go.mod index 5894534d..ee8dc783 100644 --- a/src/yangerd/go.mod +++ b/src/yangerd/go.mod @@ -8,16 +8,17 @@ require ( github.com/mdlayher/ethtool v0.4.1 github.com/mdlayher/genetlink v1.3.2 github.com/mdlayher/netlink v1.8.0 - github.com/osrg/gobgp/v3 v3.37.0 github.com/vishvananda/netlink v1.3.1 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 ) require ( github.com/google/go-cmp v0.7.0 // indirect github.com/mdlayher/socket v0.5.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/vishvananda/netns v0.0.5 // indirect + golang.org/x/crypto v0.41.0 // indirect golang.org/x/net v0.43.0 // indirect - golang.org/x/sync v0.3.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.35.0 // indirect + golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect ) diff --git a/src/yangerd/go.sum b/src/yangerd/go.sum index d5acd9f1..3422b646 100644 --- a/src/yangerd/go.sum +++ b/src/yangerd/go.sum @@ -1,10 +1,5 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -17,30 +12,23 @@ github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5Yyvvl github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/osrg/gobgp/v3 v3.37.0 h1:+ObuOdvj7G7nxrT0fKFta+EAupdWf/q1WzbXydr8IOY= -github.com/osrg/gobgp/v3 v3.37.0/go.mod h1:kVHVFy1/fyZHJ8P32+ctvPeJogn9qKwa1YCeMRXXrP0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= +golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ= diff --git a/src/yangerd/internal/monitor/monitor.go b/src/yangerd/internal/monitor/monitor.go index 7bf3a25b..bb534873 100644 --- a/src/yangerd/internal/monitor/monitor.go +++ b/src/yangerd/internal/monitor/monitor.go @@ -51,13 +51,14 @@ type NLMonitor struct { // staging holds raw ip-json data used as input to iface.Transform(). // Protected by mu. - mu sync.Mutex - links json.RawMessage // ip -json -s -d link show (includes stats+details) - addrs json.RawMessage // ip -json -d addr show (details only, no stats) - fdb map[string]json.RawMessage - mdb map[string]json.RawMessage - ethernet map[string]json.RawMessage // ifname → ethtool JSON - wifi map[string]json.RawMessage // ifname → wifi JSON + mu sync.Mutex + links json.RawMessage // ip -json -s -d link show (includes stats+details) + addrs json.RawMessage // ip -json -d addr show (details only, no stats) + fdb map[string]json.RawMessage + mdb map[string]json.RawMessage + ethernet map[string]json.RawMessage // ifname → ethtool JSON + wifi map[string]json.RawMessage // ifname → wifi JSON + wireguard map[string]json.RawMessage // ifname → WireGuard peer-status JSON lastOperStatus map[string]string } @@ -79,6 +80,7 @@ func New(linkBatch, addrBatch *ipbatch.IPBatch, brBatch *bridgebatch.BridgeBatch mdb: make(map[string]json.RawMessage), ethernet: make(map[string]json.RawMessage), wifi: make(map[string]json.RawMessage), + wireguard: make(map[string]json.RawMessage), lastOperStatus: make(map[string]string), } } @@ -112,6 +114,23 @@ func (m *NLMonitor) SetWifiData(ifname string, data json.RawMessage) { m.rebuild() } +// SetWireguardData updates the staged WireGuard peer-status data for an +// interface and triggers a full rebuild of the YANG document. +func (m *NLMonitor) SetWireguardData(ifname string, data json.RawMessage) { + m.mu.Lock() + m.wireguard[ifname] = data + m.mu.Unlock() + m.rebuild() +} + +// Links returns a copy of the current staged links data. +func (m *NLMonitor) Links() json.RawMessage { + m.mu.Lock() + cp := append(json.RawMessage{}, m.links...) + m.mu.Unlock() + return cp +} + // Run starts the netlink monitor loop and returns on context cancellation, // channel closure, or subscription errors. func (m *NLMonitor) Run(ctx context.Context) error { @@ -339,6 +358,7 @@ func (m *NLMonitor) removeInterface(name string) { delete(m.mdb, name) delete(m.ethernet, name) delete(m.wifi, name) + delete(m.wireguard, name) delete(m.lastOperStatus, name) m.mu.Unlock() @@ -393,20 +413,21 @@ func (m *NLMonitor) rebuild() { wfi := copyStringMap(m.wifi) fdb := copyStringMap(m.fdb) mdb := copyStringMap(m.mdb) + wg := copyStringMap(m.wireguard) m.mu.Unlock() var brSTP, ptSTP map[string]json.RawMessage resolver := stpquery.NewLinksIfIndexResolver(linksCopy) brSTP, ptSTP = stpquery.Query(linksCopy, resolver) - doc = mergeAugments(doc, eth, wfi, fdb, mdb, brSTP, ptSTP) + doc = mergeAugments(doc, eth, wfi, fdb, mdb, brSTP, ptSTP, wg) m.tree.Set(treeKey, doc) } // mergeAugments adds ethernet, wifi, and bridge data into the // complete ietf-interfaces document produced by iface.Transform(). -func mergeAugments(doc json.RawMessage, ethernet, wifi, fdb, mdb, bridgeSTP, portSTP map[string]json.RawMessage) json.RawMessage { - if len(ethernet) == 0 && len(wifi) == 0 && len(fdb) == 0 && len(mdb) == 0 && len(bridgeSTP) == 0 && len(portSTP) == 0 { +func mergeAugments(doc json.RawMessage, ethernet, wifi, fdb, mdb, bridgeSTP, portSTP, wireguard map[string]json.RawMessage) json.RawMessage { + if len(ethernet) == 0 && len(wifi) == 0 && len(fdb) == 0 && len(mdb) == 0 && len(bridgeSTP) == 0 && len(portSTP) == 0 && len(wireguard) == 0 { return doc } @@ -480,6 +501,13 @@ func mergeAugments(doc json.RawMessage, ethernet, wifi, fdb, mdb, bridgeSTP, por } } + if wgData, ok := wireguard[name]; ok { + var wgObj any + if err := json.Unmarshal(wgData, &wgObj); err == nil { + ifaceObj["infix-interfaces:wireguard"] = wgObj + } + } + ifaceArr[i] = ifaceObj } diff --git a/src/yangerd/internal/monitor/monitor_test.go b/src/yangerd/internal/monitor/monitor_test.go index ce8c1aaf..081a69e3 100644 --- a/src/yangerd/internal/monitor/monitor_test.go +++ b/src/yangerd/internal/monitor/monitor_test.go @@ -344,7 +344,7 @@ func TestMergeAugments(t *testing.T) { "br0": json.RawMessage(`[{"mac":"00:11:22:33:44:55"}]`), } - got := mergeAugments(doc, eth, nil, fdb, nil, nil, nil) + got := mergeAugments(doc, eth, nil, fdb, nil, nil, nil, nil) var root map[string]any if err := json.Unmarshal(got, &root); err != nil { @@ -370,7 +370,7 @@ func TestMergeAugments(t *testing.T) { func TestMergeAugmentsNoOp(t *testing.T) { doc := json.RawMessage(`{"interface":[{"name":"lo"}]}`) - got := mergeAugments(doc, nil, nil, nil, nil, nil, nil) + got := mergeAugments(doc, nil, nil, nil, nil, nil, nil, nil) if string(got) != string(doc) { t.Fatalf("expected no-op, got %s", string(got)) } @@ -379,7 +379,7 @@ func TestMergeAugmentsNoOp(t *testing.T) { func TestMergeAugmentsInvalidDoc(t *testing.T) { doc := json.RawMessage(`{invalid`) eth := map[string]json.RawMessage{"eth0": json.RawMessage(`{}`)} - got := mergeAugments(doc, eth, nil, nil, nil, nil, nil) + got := mergeAugments(doc, eth, nil, nil, nil, nil, nil, nil) if string(got) != string(doc) { t.Fatalf("expected passthrough on invalid doc, got %s", string(got)) } diff --git a/src/yangerd/internal/wgquery/wgquery.go b/src/yangerd/internal/wgquery/wgquery.go new file mode 100644 index 00000000..c9a35b24 --- /dev/null +++ b/src/yangerd/internal/wgquery/wgquery.go @@ -0,0 +1,107 @@ +package wgquery + +import ( + "encoding/json" + "strconv" + "time" + + "golang.zx2c4.com/wireguard/wgctrl" +) + +func Query(links json.RawMessage) map[string]json.RawMessage { + wgIfaces := findWireguardIfaces(links) + if len(wgIfaces) == 0 { + return nil + } + + client, err := wgctrl.New() + if err != nil { + return nil + } + defer client.Close() + + result := make(map[string]json.RawMessage) + now := time.Now().UTC() + + for _, ifname := range wgIfaces { + dev, err := client.Device(ifname) + if err != nil { + continue + } + if len(dev.Peers) == 0 { + continue + } + + var peers []map[string]any + for _, p := range dev.Peers { + peer := map[string]any{ + "public-key": p.PublicKey.String(), + "connection-status": connectionStatus(p.LastHandshakeTime, now), + } + + if !p.LastHandshakeTime.IsZero() { + peer["latest-handshake"] = p.LastHandshakeTime.UTC().Format("2006-01-02T15:04:05+00:00") + } + + if p.Endpoint != nil { + peer["endpoint-address"] = p.Endpoint.IP.String() + peer["endpoint-port"] = p.Endpoint.Port + } + + if p.TransmitBytes > 0 || p.ReceiveBytes > 0 { + peer["transfer"] = map[string]any{ + "tx-bytes": strconv.FormatInt(p.TransmitBytes, 10), + "rx-bytes": strconv.FormatInt(p.ReceiveBytes, 10), + } + } + + peers = append(peers, peer) + } + + if len(peers) == 0 { + continue + } + + out, err := json.Marshal(map[string]any{"peer-status": map[string]any{"peer": peers}}) + if err != nil { + continue + } + result[ifname] = out + } + + if len(result) == 0 { + return nil + } + return result +} + +func findWireguardIfaces(links json.RawMessage) []string { + var ifaces []map[string]any + if json.Unmarshal(links, &ifaces) != nil { + return nil + } + + var result []string + for _, iface := range ifaces { + linkinfo, _ := iface["linkinfo"].(map[string]any) + if linkinfo == nil { + continue + } + if kind, _ := linkinfo["info_kind"].(string); kind == "wireguard" { + if name, _ := iface["ifname"].(string); name != "" { + result = append(result, name) + } + } + } + return result +} + +func connectionStatus(handshake time.Time, now time.Time) string { + if handshake.IsZero() { + return "down" + } + if now.Sub(handshake) < 180*time.Second { + return "up" + } + return "down" +} diff --git a/src/yangerd/vendor/github.com/osrg/gobgp/v3/LICENSE b/src/yangerd/vendor/github.com/osrg/gobgp/v3/LICENSE deleted file mode 100644 index 5c304d1a..00000000 --- a/src/yangerd/vendor/github.com/osrg/gobgp/v3/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/yangerd/vendor/github.com/osrg/gobgp/v3/pkg/log/logger.go b/src/yangerd/vendor/github.com/osrg/gobgp/v3/pkg/log/logger.go deleted file mode 100644 index fb978bc8..00000000 --- a/src/yangerd/vendor/github.com/osrg/gobgp/v3/pkg/log/logger.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (C) 2021 Nippon Telegraph and Telephone Corporation. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package log - -import ( - "github.com/sirupsen/logrus" -) - -type LogLevel uint32 - -const ( - PanicLevel LogLevel = iota - FatalLevel - ErrorLevel - WarnLevel - InfoLevel - DebugLevel - TraceLevel -) - -const ( - FieldFacility = "_facility" -) - -var ( - FacilityUnspecified interface{} = "unspecified" - FacilityConfig interface{} = "config" -) - -type Fields map[string]interface{} - -func (fields Fields) HasFacility(facility interface{}) bool { - if fieldsFacility, hasFacility := fields[FieldFacility]; hasFacility && fieldsFacility == facility { - return true - } - return false -} - -type Logger interface { - Panic(msg string, fields Fields) - Fatal(msg string, fields Fields) - Error(msg string, fields Fields) - Warn(msg string, fields Fields) - Info(msg string, fields Fields) - Debug(msg string, fields Fields) - SetLevel(level LogLevel) - GetLevel() LogLevel -} - -type DefaultLogger struct { - logger *logrus.Logger -} - -func (l *DefaultLogger) Panic(msg string, fields Fields) { - l.logger.WithFields(logrus.Fields(fields)).Panic(msg) -} - -func (l *DefaultLogger) Fatal(msg string, fields Fields) { - l.logger.WithFields(logrus.Fields(fields)).Fatal(msg) -} - -func (l *DefaultLogger) Error(msg string, fields Fields) { - l.logger.WithFields(logrus.Fields(fields)).Error(msg) -} - -func (l *DefaultLogger) Warn(msg string, fields Fields) { - l.logger.WithFields(logrus.Fields(fields)).Warn(msg) -} - -func (l *DefaultLogger) Info(msg string, fields Fields) { - l.logger.WithFields(logrus.Fields(fields)).Info(msg) -} - -func (l *DefaultLogger) Debug(msg string, fields Fields) { - l.logger.WithFields(logrus.Fields(fields)).Debug(msg) -} - -func (l *DefaultLogger) SetLevel(level LogLevel) { - l.logger.SetLevel(logrus.Level(level)) -} - -func (l *DefaultLogger) GetLevel() LogLevel { - return LogLevel(l.logger.GetLevel()) -} - -func NewDefaultLogger() *DefaultLogger { - return &DefaultLogger{ - logger: logrus.New(), - } -} diff --git a/src/yangerd/vendor/github.com/osrg/gobgp/v3/pkg/packet/bgp/bgp.go b/src/yangerd/vendor/github.com/osrg/gobgp/v3/pkg/packet/bgp/bgp.go deleted file mode 100644 index 3f6c86b8..00000000 --- a/src/yangerd/vendor/github.com/osrg/gobgp/v3/pkg/packet/bgp/bgp.go +++ /dev/null @@ -1,15538 +0,0 @@ -// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package bgp - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "errors" - "fmt" - "math" - "net" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "sync" -) - -type MarshallingOption struct { - AddPath map[RouteFamily]BGPAddPathMode - Attributes map[BGPAttrType]bool - ImplicitPrefix AddrPrefixInterface -} - -// GetImplicitPrefix gets the implicit prefix associated with decoding/serialisation. This is used for -// the MRT representation of MP_REACH_NLRI (see RFC 6396 4.3.4). -func GetImplicitPrefix(options []*MarshallingOption) AddrPrefixInterface { - for _, opt := range options { - if opt != nil && opt.ImplicitPrefix != nil { - return opt.ImplicitPrefix - } - } - - return nil -} - -func IsAddPathEnabled(decode bool, f RouteFamily, options []*MarshallingOption) bool { - for _, opt := range options { - if opt == nil { - continue - } - if o := opt.AddPath; o != nil { - if decode && o[f]&BGP_ADD_PATH_RECEIVE > 0 { - return true - } else if !decode && o[f]&BGP_ADD_PATH_SEND > 0 { - return true - } - } - } - return false -} -func IsAttributePresent(attr BGPAttrType, options []*MarshallingOption) bool { - for _, opt := range options { - if opt == nil { - continue - } - if o := opt.Attributes; o != nil { - _, ok := o[attr] - return ok - } - } - return false -} - -const ( - AFI_IP = 1 - AFI_IP6 = 2 - AFI_L2VPN = 25 - AFI_LS = 16388 - AFI_OPAQUE = 16397 -) - -const ( - SAFI_UNICAST = 1 - SAFI_MULTICAST = 2 - SAFI_MPLS_LABEL = 4 - SAFI_ENCAPSULATION = 7 - SAFI_VPLS = 65 - SAFI_EVPN = 70 - SAFI_LS = 71 - SAFI_SRPOLICY = 73 - SAFI_MUP = 85 - SAFI_MPLS_VPN = 128 - SAFI_MPLS_VPN_MULTICAST = 129 - SAFI_ROUTE_TARGET_CONSTRAINTS = 132 - SAFI_FLOW_SPEC_UNICAST = 133 - SAFI_FLOW_SPEC_VPN = 134 - SAFI_KEY_VALUE = 241 -) - -const ( - BGP_ORIGIN_ATTR_TYPE_IGP uint8 = 0 - BGP_ORIGIN_ATTR_TYPE_EGP uint8 = 1 - BGP_ORIGIN_ATTR_TYPE_INCOMPLETE uint8 = 2 -) - -const ( - BGP_ASPATH_ATTR_TYPE_SET = 1 - BGP_ASPATH_ATTR_TYPE_SEQ = 2 - BGP_ASPATH_ATTR_TYPE_CONFED_SEQ = 3 - BGP_ASPATH_ATTR_TYPE_CONFED_SET = 4 -) - -const ( - BGP_ATTR_NHLEN_IPV6_GLOBAL = 16 - BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL = 32 -) - -// RFC7153 5.1. Registries for the "Type" Field -// RANGE REGISTRATION PROCEDURES -// 0x00-0x3F Transitive First Come First Served -// 0x40-0x7F Non-Transitive First Come First Served -// 0x80-0x8F Transitive Experimental Use -// 0x90-0xBF Transitive Standards Action -// 0xC0-0xCF Non-Transitive Experimental Use -// 0xD0-0xFF Non-Transitive Standards Action -type ExtendedCommunityAttrType uint8 - -const ( - EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x00 - EC_TYPE_TRANSITIVE_IP6_SPECIFIC ExtendedCommunityAttrType = 0x00 // RFC5701 - EC_TYPE_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x01 - EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x02 - EC_TYPE_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x03 - EC_TYPE_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x04 - EC_TYPE_COS_CAPABILITY ExtendedCommunityAttrType = 0x05 - EC_TYPE_EVPN ExtendedCommunityAttrType = 0x06 - EC_TYPE_FLOWSPEC_REDIRECT_MIRROR ExtendedCommunityAttrType = 0x08 - EC_TYPE_MUP ExtendedCommunityAttrType = 0x0c - EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x40 - EC_TYPE_NON_TRANSITIVE_LINK_BANDWIDTH ExtendedCommunityAttrType = 0x40 - EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC ExtendedCommunityAttrType = 0x40 // RFC5701 - EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x41 - EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x42 - EC_TYPE_NON_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x43 - EC_TYPE_NON_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x44 - EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL ExtendedCommunityAttrType = 0x80 - EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 ExtendedCommunityAttrType = 0x81 // RFC7674 - EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 ExtendedCommunityAttrType = 0x82 // RFC7674 -) - -// RFC7153 5.2. Registries for the "Sub-Type" Field -// RANGE REGISTRATION PROCEDURES -// 0x00-0xBF First Come First Served -// 0xC0-0xFF IETF Review -type ExtendedCommunityAttrSubType uint8 - -const ( - EC_SUBTYPE_ROUTE_TARGET ExtendedCommunityAttrSubType = 0x02 // EC_TYPE: 0x00, 0x01, 0x02 - EC_SUBTYPE_ROUTE_ORIGIN ExtendedCommunityAttrSubType = 0x03 // EC_TYPE: 0x00, 0x01, 0x02 - EC_SUBTYPE_LINK_BANDWIDTH ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x40 - EC_SUBTYPE_GENERIC ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x02, 0x42 - EC_SUBTYPE_OSPF_DOMAIN_ID ExtendedCommunityAttrSubType = 0x05 // EC_TYPE: 0x00, 0x01, 0x02 - EC_SUBTYPE_OSPF_ROUTE_ID ExtendedCommunityAttrSubType = 0x07 // EC_TYPE: 0x01 - EC_SUBTYPE_BGP_DATA_COLLECTION ExtendedCommunityAttrSubType = 0x08 // EC_TYPE: 0x00, 0x02 - EC_SUBTYPE_SOURCE_AS ExtendedCommunityAttrSubType = 0x09 // EC_TYPE: 0x00, 0x02 - EC_SUBTYPE_L2VPN_ID ExtendedCommunityAttrSubType = 0x0A // EC_TYPE: 0x00, 0x01 - EC_SUBTYPE_VRF_ROUTE_IMPORT ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x01 - EC_SUBTYPE_CISCO_VPN_DISTINGUISHER ExtendedCommunityAttrSubType = 0x10 // EC_TYPE: 0x00, 0x01, 0x02 - - EC_SUBTYPE_OSPF_ROUTE_TYPE ExtendedCommunityAttrSubType = 0x06 // EC_TYPE: 0x03 - EC_SUBTYPE_COLOR ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x03 - EC_SUBTYPE_ENCAPSULATION ExtendedCommunityAttrSubType = 0x0C // EC_TYPE: 0x03 - EC_SUBTYPE_DEFAULT_GATEWAY ExtendedCommunityAttrSubType = 0x0D // EC_TYPE: 0x03 - - EC_SUBTYPE_ORIGIN_VALIDATION ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x43 - - EC_SUBTYPE_MUP_DIRECT_SEG ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x0c - - EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE ExtendedCommunityAttrSubType = 0x06 // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION ExtendedCommunityAttrSubType = 0x07 // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_REDIRECT ExtendedCommunityAttrSubType = 0x08 // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK ExtendedCommunityAttrSubType = 0x09 // EC_TYPE: 0x80 - EC_SUBTYPE_L2_INFO ExtendedCommunityAttrSubType = 0x0A // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6 ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x80 - - EC_SUBTYPE_MAC_MOBILITY ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x06 - EC_SUBTYPE_ESI_LABEL ExtendedCommunityAttrSubType = 0x01 // EC_TYPE: 0x06 - EC_SUBTYPE_ES_IMPORT ExtendedCommunityAttrSubType = 0x02 // EC_TYPE: 0x06 - EC_SUBTYPE_ROUTER_MAC ExtendedCommunityAttrSubType = 0x03 // EC_TYPE: 0x06 - EC_SUBTYPE_L2_ATTRIBUTES ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x06 - - EC_SUBTYPE_UUID_BASED_RT ExtendedCommunityAttrSubType = 0x11 -) - -// RFC6624 -type Layer2EncapsulationType uint8 - -const ( - LAYER2ENCAPSULATION_TYPE_FRAMERELAY Layer2EncapsulationType = 1 - LAYER2ENCAPSULATION_TYPE_ATM_AAL5 Layer2EncapsulationType = 2 - LAYER2ENCAPSULATION_TYPE_ATM_TRANSPARENT Layer2EncapsulationType = 3 - LAYER2ENCAPSULATION_TYPE_ETHERNET_VLAN Layer2EncapsulationType = 4 - LAYER2ENCAPSULATION_TYPE_ETHERNET_RAW Layer2EncapsulationType = 5 - LAYER2ENCAPSULATION_TYPE_CISCO_HDLC Layer2EncapsulationType = 6 - LAYER2ENCAPSULATION_TYPE_PPP Layer2EncapsulationType = 7 - LAYER2ENCAPSULATION_TYPE_SONET Layer2EncapsulationType = 8 - LAYER2ENCAPSULATION_TYPE_ATM_VCC Layer2EncapsulationType = 9 - LAYER2ENCAPSULATION_TYPE_ATM_VPC Layer2EncapsulationType = 10 - LAYER2ENCAPSULATION_TYPE_IP_LAYER2 Layer2EncapsulationType = 11 - LAYER2ENCAPSULATION_TYPE_VPLS Layer2EncapsulationType = 19 -) - -func (l Layer2EncapsulationType) String() string { - switch l { - case LAYER2ENCAPSULATION_TYPE_FRAMERELAY: - return "framerelay" - case LAYER2ENCAPSULATION_TYPE_ATM_AAL5: - return "atm-aal5" - case LAYER2ENCAPSULATION_TYPE_ATM_TRANSPARENT: - return "atm-transparent" - case LAYER2ENCAPSULATION_TYPE_ETHERNET_VLAN: - return "ethernet-vlan" - case LAYER2ENCAPSULATION_TYPE_ETHERNET_RAW: - return "ethernet-raw" - case LAYER2ENCAPSULATION_TYPE_CISCO_HDLC: - return "cisco-hdlc" - case LAYER2ENCAPSULATION_TYPE_PPP: - return "ppp" - case LAYER2ENCAPSULATION_TYPE_SONET: - return "sonet" - case LAYER2ENCAPSULATION_TYPE_ATM_VCC: - return "atm-vcc" - case LAYER2ENCAPSULATION_TYPE_ATM_VPC: - return "atm-vpc" - case LAYER2ENCAPSULATION_TYPE_IP_LAYER2: - return "ip-layer2" - case LAYER2ENCAPSULATION_TYPE_VPLS: - return "vpls" - default: - return fmt.Sprintf("Layer2EncapsulationType(%d)", uint8(l)) - } -} - -type TunnelType uint16 - -const ( - TUNNEL_TYPE_L2TP3 TunnelType = 1 - TUNNEL_TYPE_GRE TunnelType = 2 - TUNNEL_TYPE_IP_IN_IP TunnelType = 7 - TUNNEL_TYPE_VXLAN TunnelType = 8 - TUNNEL_TYPE_NVGRE TunnelType = 9 - TUNNEL_TYPE_MPLS TunnelType = 10 - TUNNEL_TYPE_MPLS_IN_GRE TunnelType = 11 - TUNNEL_TYPE_VXLAN_GRE TunnelType = 12 - TUNNEL_TYPE_MPLS_IN_UDP TunnelType = 13 - TUNNEL_TYPE_SR_POLICY TunnelType = 15 - TUNNEL_TYPE_GENEVE TunnelType = 19 -) - -func (p TunnelType) String() string { - switch p { - case TUNNEL_TYPE_L2TP3: - return "l2tp3" - case TUNNEL_TYPE_GRE: - return "gre" - case TUNNEL_TYPE_IP_IN_IP: - return "ip-in-ip" - case TUNNEL_TYPE_VXLAN: - return "vxlan" - case TUNNEL_TYPE_NVGRE: - return "nvgre" - case TUNNEL_TYPE_MPLS: - return "mpls" - case TUNNEL_TYPE_MPLS_IN_GRE: - return "mpls-in-gre" - case TUNNEL_TYPE_VXLAN_GRE: - return "vxlan-gre" - case TUNNEL_TYPE_MPLS_IN_UDP: - return "mpls-in-udp" - case TUNNEL_TYPE_SR_POLICY: - return "sr-policy" - case TUNNEL_TYPE_GENEVE: - return "geneve" - default: - return fmt.Sprintf("TunnelType(%d)", uint8(p)) - } -} - -type PmsiTunnelType uint8 - -const ( - PMSI_TUNNEL_TYPE_NO_TUNNEL PmsiTunnelType = 0 - PMSI_TUNNEL_TYPE_RSVP_TE_P2MP PmsiTunnelType = 1 - PMSI_TUNNEL_TYPE_MLDP_P2MP PmsiTunnelType = 2 - PMSI_TUNNEL_TYPE_PIM_SSM_TREE PmsiTunnelType = 3 - PMSI_TUNNEL_TYPE_PIM_SM_TREE PmsiTunnelType = 4 - PMSI_TUNNEL_TYPE_BIDIR_PIM_TREE PmsiTunnelType = 5 - PMSI_TUNNEL_TYPE_INGRESS_REPL PmsiTunnelType = 6 - PMSI_TUNNEL_TYPE_MLDP_MP2MP PmsiTunnelType = 7 -) - -func (p PmsiTunnelType) String() string { - switch p { - case PMSI_TUNNEL_TYPE_NO_TUNNEL: - return "no-tunnel" - case PMSI_TUNNEL_TYPE_RSVP_TE_P2MP: - return "rsvp-te-p2mp" - case PMSI_TUNNEL_TYPE_MLDP_P2MP: - return "mldp-p2mp" - case PMSI_TUNNEL_TYPE_PIM_SSM_TREE: - return "pim-ssm-tree" - case PMSI_TUNNEL_TYPE_PIM_SM_TREE: - return "pim-sm-tree" - case PMSI_TUNNEL_TYPE_BIDIR_PIM_TREE: - return "bidir-pim-tree" - case PMSI_TUNNEL_TYPE_INGRESS_REPL: - return "ingress-repl" - case PMSI_TUNNEL_TYPE_MLDP_MP2MP: - return "mldp-mp2mp" - default: - return fmt.Sprintf("PmsiTunnelType(%d)", uint8(p)) - } -} - -type EncapSubTLVType uint8 - -const ( - ENCAP_SUBTLV_TYPE_ENCAPSULATION EncapSubTLVType = 1 - ENCAP_SUBTLV_TYPE_PROTOCOL EncapSubTLVType = 2 - ENCAP_SUBTLV_TYPE_COLOR EncapSubTLVType = 4 - ENCAP_SUBTLV_TYPE_EGRESS_ENDPOINT EncapSubTLVType = 6 - ENCAP_SUBTLV_TYPE_UDP_DEST_PORT EncapSubTLVType = 8 - ENCAP_SUBTLV_TYPE_SRPREFERENCE EncapSubTLVType = 12 - ENCAP_SUBTLV_TYPE_SRBINDING_SID EncapSubTLVType = 13 - ENCAP_SUBTLV_TYPE_SRENLP EncapSubTLVType = 14 - ENCAP_SUBTLV_TYPE_SRPRIORITY EncapSubTLVType = 15 - ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST EncapSubTLVType = 128 - ENCAP_SUBTLV_TYPE_SRCANDIDATE_PATH_NAME EncapSubTLVType = 129 -) - -const ( - _ = iota - BGP_MSG_OPEN - BGP_MSG_UPDATE - BGP_MSG_NOTIFICATION - BGP_MSG_KEEPALIVE - BGP_MSG_ROUTE_REFRESH -) - -const ( - BGP_OPT_CAPABILITY = 2 -) - -type BGPCapabilityCode uint8 - -const ( - BGP_CAP_MULTIPROTOCOL BGPCapabilityCode = 1 - BGP_CAP_ROUTE_REFRESH BGPCapabilityCode = 2 - BGP_CAP_CARRYING_LABEL_INFO BGPCapabilityCode = 4 - BGP_CAP_EXTENDED_NEXTHOP BGPCapabilityCode = 5 - BGP_CAP_GRACEFUL_RESTART BGPCapabilityCode = 64 - BGP_CAP_FOUR_OCTET_AS_NUMBER BGPCapabilityCode = 65 - BGP_CAP_ADD_PATH BGPCapabilityCode = 69 - BGP_CAP_ENHANCED_ROUTE_REFRESH BGPCapabilityCode = 70 - BGP_CAP_LONG_LIVED_GRACEFUL_RESTART BGPCapabilityCode = 71 - BGP_CAP_FQDN BGPCapabilityCode = 73 - BGP_CAP_SOFT_VERSION BGPCapabilityCode = 75 - BGP_CAP_ROUTE_REFRESH_CISCO BGPCapabilityCode = 128 -) - -var CapNameMap = map[BGPCapabilityCode]string{ - BGP_CAP_MULTIPROTOCOL: "multiprotocol", - BGP_CAP_ROUTE_REFRESH: "route-refresh", - BGP_CAP_CARRYING_LABEL_INFO: "carrying-label-info", - BGP_CAP_GRACEFUL_RESTART: "graceful-restart", - BGP_CAP_EXTENDED_NEXTHOP: "extended-nexthop", - BGP_CAP_FOUR_OCTET_AS_NUMBER: "4-octet-as", - BGP_CAP_ADD_PATH: "add-path", - BGP_CAP_ENHANCED_ROUTE_REFRESH: "enhanced-route-refresh", - BGP_CAP_ROUTE_REFRESH_CISCO: "cisco-route-refresh", - BGP_CAP_LONG_LIVED_GRACEFUL_RESTART: "long-lived-graceful-restart", - BGP_CAP_FQDN: "fqdn", - BGP_CAP_SOFT_VERSION: "software-version", -} - -func (c BGPCapabilityCode) String() string { - if n, y := CapNameMap[c]; y { - return n - } - return fmt.Sprintf("UnknownCapability(%d)", c) -} - -var ( - // Used parsing RouteDistinguisher - _regexpRouteDistinguisher = regexp.MustCompile(`^((\d+)\.(\d+)\.(\d+)\.(\d+)|((\d+)\.)?(\d+)|([\w]+:[\w:]*:[\w]+)):(\d+)$`) - - // Used for operator and value for the FlowSpec numeric type - // Example: - // re.FindStringSubmatch("&==80") - // >>> ["&==80" "&" "==" "80"] - _regexpFlowSpecNumericType = regexp.MustCompile(`(&?)(==|=|>|>=|<|<=|!|!=|=!)?(\d+|-\d|true|false)`) - - // - "=!" is used in the old style format of "tcp-flags" and "fragment". - // - The value field should be one of the followings: - // * Decimal value (e.g., 80) - // * Combination of the small letters, decimals, "-" and "+" - // (e.g., tcp, ipv4, is-fragment+first-fragment) - // * Capital letters (e.g., SA) - _regexpFlowSpecOperator = regexp.MustCompile(`&|=|>|<|!|[\w\-+]+`) - _regexpFlowSpecOperatorValue = regexp.MustCompile(`[\w\-+]+`) - - // Note: "(-*)" and "(.*)" catch the invalid flags - // Example: In this case, "Z" is unsupported flag type. - // re.FindStringSubmatch("&==-SZU") - // >>> ["&==-SZU" "&" "==" "-" "S" "ZU"] - _regexpFlowSpecTCPFlag = regexp.MustCompile("(&?)(==|=|!|!=|=!)?(-*)([FSRPAUCE]+)(.*)") - - // Note: "(.*)" catches the invalid flags - // re.FindStringSubmatch("&!=+first-fragment+last-fragment+invalid-fragment") - // >>> ["&!=+first-fragment+last-fragment+invalid-fragment" "&" "!=" "+first-fragment+last-fragment" "+last-fragment" "+" "last" "+invalid-fragment"] - _regexpFlowSpecFragment = regexp.MustCompile(`(&?)(==|=|!|!=|=!)?(((\+)?(dont|is|first|last|not-a)-fragment)+)(.*)`) - - // re.FindStringSubmatch("192.168.0.0/24") - // >>> ["192.168.0.0/24" "192.168.0.0" "/24" "24"] - // re.FindStringSubmatch("192.168.0.1") - // >>> ["192.168.0.1" "192.168.0.1" "" ""] - _regexpFindIPv4Prefix = regexp.MustCompile(`^([\d.]+)(/(\d{1,2}))?`) - - // re.FindStringSubmatch("2001:dB8::/64") - // >>> ["2001:dB8::/64" "2001:dB8::" "/64" "64" "" ""] - // re.FindStringSubmatch("2001:dB8::/64/8") - // >>> ["2001:dB8::/64/8" "2001:dB8::" "/64" "64" "/8" "8"] - // re.FindStringSubmatch("2001:dB8::1") - // >>> ["2001:dB8::1" "2001:dB8::1" "" "" "" ""] - _regexpFindIPv6Prefix = regexp.MustCompile(`^([a-fA-F\d:.]+)(/(\d{1,3}))?(/(\d{1,3}))?`) -) - -type ParameterCapabilityInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int - Code() BGPCapabilityCode -} - -type DefaultParameterCapability struct { - CapCode BGPCapabilityCode `json:"code"` - CapLen uint8 `json:"-"` - CapValue []byte `json:"value,omitempty"` -} - -func (c *DefaultParameterCapability) Code() BGPCapabilityCode { - return c.CapCode -} - -func (c *DefaultParameterCapability) DecodeFromBytes(data []byte) error { - c.CapCode = BGPCapabilityCode(data[0]) - c.CapLen = data[1] - if len(data) < 2+int(c.CapLen) { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all OptionParameterCapability bytes available") - } - if c.CapLen > 0 { - c.CapValue = data[2 : 2+c.CapLen] - } - return nil -} - -func (c *DefaultParameterCapability) Serialize() ([]byte, error) { - c.CapLen = uint8(len(c.CapValue)) - buf := make([]byte, 2+len(c.CapValue)) - buf[0] = uint8(c.CapCode) - buf[1] = c.CapLen - copy(buf[2:], c.CapValue) - return buf, nil -} - -func (c *DefaultParameterCapability) Len() int { - return int(c.CapLen + 2) -} - -type CapMultiProtocol struct { - DefaultParameterCapability - CapValue RouteFamily -} - -func (c *CapMultiProtocol) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 4 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityMultiProtocol bytes available") - } - c.CapValue = AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[0:2]), data[3]) - return nil -} - -func (c *CapMultiProtocol) Serialize() ([]byte, error) { - buf := make([]byte, 4) - afi, safi := RouteFamilyToAfiSafi(c.CapValue) - binary.BigEndian.PutUint16(buf[0:], afi) - buf[3] = safi - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapMultiProtocol) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Value RouteFamily `json:"value"` - }{ - Code: c.Code(), - Value: c.CapValue, - }) -} - -func NewCapMultiProtocol(rf RouteFamily) *CapMultiProtocol { - return &CapMultiProtocol{ - DefaultParameterCapability{ - CapCode: BGP_CAP_MULTIPROTOCOL, - }, - rf, - } -} - -type CapRouteRefresh struct { - DefaultParameterCapability -} - -func NewCapRouteRefresh() *CapRouteRefresh { - return &CapRouteRefresh{ - DefaultParameterCapability{ - CapCode: BGP_CAP_ROUTE_REFRESH, - }, - } -} - -type CapCarryingLabelInfo struct { - DefaultParameterCapability -} - -func NewCapCarryingLabelInfo() *CapCarryingLabelInfo { - return &CapCarryingLabelInfo{ - DefaultParameterCapability{ - CapCode: BGP_CAP_CARRYING_LABEL_INFO, - }, - } -} - -type CapExtendedNexthopTuple struct { - NLRIAFI uint16 - NLRISAFI uint16 - NexthopAFI uint16 -} - -func (c *CapExtendedNexthopTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - NLRIAddressFamily RouteFamily `json:"nlri_address_family"` - NexthopAddressFamily uint16 `json:"nexthop_address_family"` - }{ - NLRIAddressFamily: AfiSafiToRouteFamily(c.NLRIAFI, uint8(c.NLRISAFI)), - NexthopAddressFamily: c.NexthopAFI, - }) -} - -func NewCapExtendedNexthopTuple(af RouteFamily, nexthop uint16) *CapExtendedNexthopTuple { - afi, safi := RouteFamilyToAfiSafi(af) - return &CapExtendedNexthopTuple{ - NLRIAFI: afi, - NLRISAFI: uint16(safi), - NexthopAFI: nexthop, - } -} - -type CapExtendedNexthop struct { - DefaultParameterCapability - Tuples []*CapExtendedNexthopTuple -} - -func (c *CapExtendedNexthop) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - capLen := int(c.CapLen) - if capLen%6 != 0 || capLen < 6 || len(data) < capLen { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityExtendedNexthop bytes available") - } - - c.Tuples = []*CapExtendedNexthopTuple{} - for capLen >= 6 { - t := &CapExtendedNexthopTuple{ - binary.BigEndian.Uint16(data[0:2]), - binary.BigEndian.Uint16(data[2:4]), - binary.BigEndian.Uint16(data[4:6]), - } - c.Tuples = append(c.Tuples, t) - data = data[6:] - capLen -= 6 - } - return nil -} - -func (c *CapExtendedNexthop) Serialize() ([]byte, error) { - buf := make([]byte, len(c.Tuples)*6) - for i, t := range c.Tuples { - binary.BigEndian.PutUint16(buf[i*6:i*6+2], t.NLRIAFI) - binary.BigEndian.PutUint16(buf[i*6+2:i*6+4], t.NLRISAFI) - binary.BigEndian.PutUint16(buf[i*6+4:i*6+6], t.NexthopAFI) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapExtendedNexthop) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Tuples []*CapExtendedNexthopTuple `json:"tuples"` - }{ - Code: c.Code(), - Tuples: c.Tuples, - }) -} - -func NewCapExtendedNexthop(tuples []*CapExtendedNexthopTuple) *CapExtendedNexthop { - return &CapExtendedNexthop{ - DefaultParameterCapability{ - CapCode: BGP_CAP_EXTENDED_NEXTHOP, - }, - tuples, - } -} - -type CapGracefulRestartTuple struct { - AFI uint16 - SAFI uint8 - Flags uint8 -} - -func (c *CapGracefulRestartTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RouteFamily RouteFamily `json:"route_family"` - Flags uint8 `json:"flags"` - }{ - RouteFamily: AfiSafiToRouteFamily(c.AFI, c.SAFI), - Flags: c.Flags, - }) -} - -func NewCapGracefulRestartTuple(rf RouteFamily, forward bool) *CapGracefulRestartTuple { - afi, safi := RouteFamilyToAfiSafi(rf) - flags := 0 - if forward { - flags = 0x80 - } - return &CapGracefulRestartTuple{ - AFI: afi, - SAFI: safi, - Flags: uint8(flags), - } -} - -type CapGracefulRestart struct { - DefaultParameterCapability - Flags uint8 - Time uint16 - Tuples []*CapGracefulRestartTuple -} - -func (c *CapGracefulRestart) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 2 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityGracefulRestart bytes available") - } - restart := binary.BigEndian.Uint16(data[0:2]) - c.Flags = uint8(restart >> 12) - c.Time = restart & 0xfff - data = data[2:] - - valueLen := int(c.CapLen) - 2 - - if valueLen >= 4 && len(data) >= valueLen { - c.Tuples = make([]*CapGracefulRestartTuple, 0, valueLen/4) - - for i := valueLen; i >= 4; i -= 4 { - t := &CapGracefulRestartTuple{binary.BigEndian.Uint16(data[0:2]), - data[2], data[3]} - c.Tuples = append(c.Tuples, t) - data = data[4:] - } - } - return nil -} - -func (c *CapGracefulRestart) Serialize() ([]byte, error) { - buf := make([]byte, 2, 2+4*len(c.Tuples)) - binary.BigEndian.PutUint16(buf[0:], uint16(c.Flags)<<12|c.Time) - var tbuf [4]byte - for _, t := range c.Tuples { - binary.BigEndian.PutUint16(tbuf[0:2], t.AFI) - tbuf[2] = t.SAFI - tbuf[3] = t.Flags - buf = append(buf, tbuf[:]...) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapGracefulRestart) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Flags uint8 `json:"flags"` - Time uint16 `json:"time"` - Tuples []*CapGracefulRestartTuple `json:"tuples"` - }{ - Code: c.Code(), - Flags: c.Flags, - Time: c.Time, - Tuples: c.Tuples, - }) -} - -func NewCapGracefulRestart(restarting, notification bool, time uint16, tuples []*CapGracefulRestartTuple) *CapGracefulRestart { - flags := 0 - if restarting { - flags = 0x08 - } - if notification { - flags |= 0x04 - } - return &CapGracefulRestart{ - DefaultParameterCapability: DefaultParameterCapability{ - CapCode: BGP_CAP_GRACEFUL_RESTART, - }, - Flags: uint8(flags), - Time: time, - Tuples: tuples, - } -} - -type CapFourOctetASNumber struct { - DefaultParameterCapability - CapValue uint32 -} - -func (c *CapFourOctetASNumber) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 4 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFourOctetASNumber bytes available") - } - c.CapValue = binary.BigEndian.Uint32(data[0:4]) - return nil -} - -func (c *CapFourOctetASNumber) Serialize() ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, c.CapValue) - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapFourOctetASNumber) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Value uint32 `json:"value"` - }{ - Code: c.Code(), - Value: c.CapValue, - }) -} - -func NewCapFourOctetASNumber(asnum uint32) *CapFourOctetASNumber { - return &CapFourOctetASNumber{ - DefaultParameterCapability{ - CapCode: BGP_CAP_FOUR_OCTET_AS_NUMBER, - }, - asnum, - } -} - -type BGPAddPathMode uint8 - -const ( - BGP_ADD_PATH_NONE BGPAddPathMode = iota - BGP_ADD_PATH_RECEIVE - BGP_ADD_PATH_SEND - BGP_ADD_PATH_BOTH -) - -func (m BGPAddPathMode) String() string { - switch m { - case BGP_ADD_PATH_NONE: - return "none" - case BGP_ADD_PATH_RECEIVE: - return "receive" - case BGP_ADD_PATH_SEND: - return "send" - case BGP_ADD_PATH_BOTH: - return "receive/send" - default: - return fmt.Sprintf("unknown(%d)", m) - } -} - -type CapAddPathTuple struct { - RouteFamily RouteFamily - Mode BGPAddPathMode -} - -func (t *CapAddPathTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RouteFamily RouteFamily `json:"family"` - Mode uint8 `json:"mode"` - }{ - RouteFamily: t.RouteFamily, - Mode: uint8(t.Mode), - }) -} - -func NewCapAddPathTuple(family RouteFamily, mode BGPAddPathMode) *CapAddPathTuple { - return &CapAddPathTuple{ - RouteFamily: family, - Mode: mode, - } -} - -type CapAddPath struct { - DefaultParameterCapability - Tuples []*CapAddPathTuple -} - -func (c *CapAddPath) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - capLen := int(c.CapLen) - if capLen%4 != 0 || capLen < 4 || len(data) < capLen { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityAddPath bytes available") - } - - c.Tuples = []*CapAddPathTuple{} - for capLen >= 4 { - t := &CapAddPathTuple{ - RouteFamily: AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[:2]), data[2]), - Mode: BGPAddPathMode(data[3]), - } - c.Tuples = append(c.Tuples, t) - data = data[4:] - capLen -= 4 - } - return nil -} - -func (c *CapAddPath) Serialize() ([]byte, error) { - buf := make([]byte, len(c.Tuples)*4) - for i, t := range c.Tuples { - afi, safi := RouteFamilyToAfiSafi(t.RouteFamily) - binary.BigEndian.PutUint16(buf[i*4:i*4+2], afi) - buf[i*4+2] = safi - buf[i*4+3] = byte(t.Mode) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapAddPath) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Tuples []*CapAddPathTuple `json:"tuples"` - }{ - Code: c.Code(), - Tuples: c.Tuples, - }) -} - -func NewCapAddPath(tuples []*CapAddPathTuple) *CapAddPath { - return &CapAddPath{ - DefaultParameterCapability: DefaultParameterCapability{ - CapCode: BGP_CAP_ADD_PATH, - }, - Tuples: tuples, - } -} - -type CapEnhancedRouteRefresh struct { - DefaultParameterCapability -} - -func NewCapEnhancedRouteRefresh() *CapEnhancedRouteRefresh { - return &CapEnhancedRouteRefresh{ - DefaultParameterCapability{ - CapCode: BGP_CAP_ENHANCED_ROUTE_REFRESH, - }, - } -} - -type CapRouteRefreshCisco struct { - DefaultParameterCapability -} - -func NewCapRouteRefreshCisco() *CapRouteRefreshCisco { - return &CapRouteRefreshCisco{ - DefaultParameterCapability{ - CapCode: BGP_CAP_ROUTE_REFRESH_CISCO, - }, - } -} - -type CapLongLivedGracefulRestartTuple struct { - AFI uint16 - SAFI uint8 - Flags uint8 - RestartTime uint32 -} - -func (c *CapLongLivedGracefulRestartTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RouteFamily RouteFamily `json:"route_family"` - Flags uint8 `json:"flags"` - RestartTime uint32 `json:"restart_time"` - }{ - RouteFamily: AfiSafiToRouteFamily(c.AFI, c.SAFI), - Flags: c.Flags, - RestartTime: c.RestartTime, - }) -} - -func NewCapLongLivedGracefulRestartTuple(rf RouteFamily, forward bool, restartTime uint32) *CapLongLivedGracefulRestartTuple { - afi, safi := RouteFamilyToAfiSafi(rf) - flags := 0 - if forward { - flags = 0x80 - } - return &CapLongLivedGracefulRestartTuple{ - AFI: afi, - SAFI: safi, - Flags: uint8(flags), - RestartTime: restartTime, - } -} - -type CapLongLivedGracefulRestart struct { - DefaultParameterCapability - Tuples []*CapLongLivedGracefulRestartTuple -} - -func (c *CapLongLivedGracefulRestart) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - - valueLen := int(c.CapLen) - if valueLen%7 != 0 || len(data) < valueLen { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "invalid length of long lived graceful restart capablity") - } - for i := valueLen; i >= 7; i -= 7 { - t := &CapLongLivedGracefulRestartTuple{ - binary.BigEndian.Uint16(data), - data[2], - data[3], - uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]), - } - c.Tuples = append(c.Tuples, t) - data = data[7:] - } - return nil -} - -func (c *CapLongLivedGracefulRestart) Serialize() ([]byte, error) { - buf := make([]byte, 7*len(c.Tuples)) - for idx, t := range c.Tuples { - binary.BigEndian.PutUint16(buf[idx*7:], t.AFI) - buf[idx*7+2] = t.SAFI - buf[idx*7+3] = t.Flags - buf[idx*7+4] = uint8((t.RestartTime >> 16) & 0xff) - buf[idx*7+5] = uint8((t.RestartTime >> 8) & 0xff) - buf[idx*7+6] = uint8(t.RestartTime & 0xff) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapLongLivedGracefulRestart) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Tuples []*CapLongLivedGracefulRestartTuple `json:"tuples"` - }{ - Code: c.Code(), - Tuples: c.Tuples, - }) -} - -func NewCapLongLivedGracefulRestart(tuples []*CapLongLivedGracefulRestartTuple) *CapLongLivedGracefulRestart { - return &CapLongLivedGracefulRestart{ - DefaultParameterCapability: DefaultParameterCapability{ - CapCode: BGP_CAP_LONG_LIVED_GRACEFUL_RESTART, - }, - Tuples: tuples, - } -} - -type CapFQDN struct { - DefaultParameterCapability - HostNameLen uint8 - HostName string - DomainNameLen uint8 - DomainName string -} - -func (c *CapFQDN) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 2 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFQDN bytes allowed") - } - rest := len(data) - if rest < 1 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFQDN bytes allowed") - } - hostNameLen := uint8(data[0]) - rest -= 1 - c.HostNameLen = hostNameLen - if rest < int(hostNameLen) { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFQDN bytes allowed") - } - c.HostName = string(data[1 : c.HostNameLen+1]) - rest -= int(hostNameLen) - if rest < 1 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFQDN bytes allowed") - } - rest -= 1 - domainNameLen := uint8(data[c.HostNameLen+1]) - if rest < int(domainNameLen) { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFQDN bytes allowed") - } - c.DomainNameLen = domainNameLen - c.DomainName = string(data[c.HostNameLen+2:]) - return nil -} - -func (c *CapFQDN) Serialize() ([]byte, error) { - buf := make([]byte, c.HostNameLen+c.DomainNameLen+2) - buf[0] = c.HostNameLen - copy(buf[1:c.HostNameLen+1], c.HostName) - buf[c.HostNameLen+1] = c.DomainNameLen - copy(buf[c.HostNameLen+2:], c.DomainName) - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapFQDN) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - HostNameLen uint8 `json:"hostname_len"` - HostName string `json:"hostname"` - DomainNameLen uint8 `json:"domainname_len"` - DomainName string `json:"domainname"` - }{ - HostNameLen: c.HostNameLen, - HostName: c.HostName, - DomainNameLen: c.DomainNameLen, - DomainName: c.DomainName, - }) -} - -func NewCapFQDN(hostname string, domainname string) *CapFQDN { - if len(hostname) > 64 { - hostname = hostname[:64] - } - if len(domainname) > 64 { - domainname = domainname[:64] - } - return &CapFQDN{ - DefaultParameterCapability{ - CapCode: BGP_CAP_FQDN, - }, - uint8(len(hostname)), - hostname, - uint8(len(domainname)), - domainname, - } -} - -type CapSoftwareVersion struct { - DefaultParameterCapability - SoftwareVersionLen uint8 - SoftwareVersion string -} - -func (c *CapSoftwareVersion) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 2 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilitySoftwareVersion bytes allowed") - } - softwareVersionLen := uint8(data[0]) - if len(data[1:]) < int(softwareVersionLen) || softwareVersionLen > 64 || softwareVersionLen == 0 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "invalid length of software version capablity") - } - c.SoftwareVersionLen = softwareVersionLen - c.SoftwareVersion = string(data[1:c.SoftwareVersionLen]) - return nil -} - -func (c *CapSoftwareVersion) Serialize() ([]byte, error) { - buf := make([]byte, c.SoftwareVersionLen+1) - buf[0] = c.SoftwareVersionLen - copy(buf[1:], []byte(c.SoftwareVersion)) - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapSoftwareVersion) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - SoftwareVersionLen uint8 `json:"software_version_len"` - SoftwareVersion string `json:"software_version"` - }{ - SoftwareVersionLen: c.SoftwareVersionLen, - SoftwareVersion: c.SoftwareVersion, - }) -} - -func NewCapSoftwareVersion(version string) *CapSoftwareVersion { - if len(version) > 64 { - version = version[:64] - } - - return &CapSoftwareVersion{ - DefaultParameterCapability{ - CapCode: BGP_CAP_SOFT_VERSION, - }, - uint8(len(version)), - version, - } -} - -type CapUnknown struct { - DefaultParameterCapability -} - -func NewCapUnknown(code BGPCapabilityCode, value []byte) *CapUnknown { - return &CapUnknown{ - DefaultParameterCapability{ - CapCode: code, - CapValue: value, - }, - } -} - -func DecodeCapability(data []byte) (ParameterCapabilityInterface, error) { - if len(data) < 2 { - return nil, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all ParameterCapability bytes available") - } - var c ParameterCapabilityInterface - switch BGPCapabilityCode(data[0]) { - case BGP_CAP_MULTIPROTOCOL: - c = &CapMultiProtocol{} - case BGP_CAP_ROUTE_REFRESH: - c = &CapRouteRefresh{} - case BGP_CAP_CARRYING_LABEL_INFO: - c = &CapCarryingLabelInfo{} - case BGP_CAP_EXTENDED_NEXTHOP: - c = &CapExtendedNexthop{} - case BGP_CAP_GRACEFUL_RESTART: - c = &CapGracefulRestart{} - case BGP_CAP_FOUR_OCTET_AS_NUMBER: - c = &CapFourOctetASNumber{} - case BGP_CAP_ADD_PATH: - c = &CapAddPath{} - case BGP_CAP_ENHANCED_ROUTE_REFRESH: - c = &CapEnhancedRouteRefresh{} - case BGP_CAP_ROUTE_REFRESH_CISCO: - c = &CapRouteRefreshCisco{} - case BGP_CAP_LONG_LIVED_GRACEFUL_RESTART: - c = &CapLongLivedGracefulRestart{} - case BGP_CAP_FQDN: - c = &CapFQDN{} - case BGP_CAP_SOFT_VERSION: - c = &CapSoftwareVersion{} - default: - c = &CapUnknown{} - } - err := c.DecodeFromBytes(data) - return c, err -} - -type OptionParameterInterface interface { - Serialize() ([]byte, error) -} - -type OptionParameterCapability struct { - ParamType uint8 - ParamLen uint8 - Capability []ParameterCapabilityInterface -} - -func (o *OptionParameterCapability) DecodeFromBytes(data []byte) error { - if uint8(len(data)) < o.ParamLen { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_OPTIONAL_PARAMETER, nil, "Not all OptionParameterCapability bytes available") - } - for len(data) >= 2 { - c, err := DecodeCapability(data) - if err != nil { - return err - } - o.Capability = append(o.Capability, c) - if c.Len() == 0 || len(data) < c.Len() { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Bad capability length") - } - data = data[c.Len():] - } - return nil -} - -func (o *OptionParameterCapability) Serialize() ([]byte, error) { - buf := make([]byte, 2) - buf[0] = o.ParamType - for _, p := range o.Capability { - pbuf, err := p.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - o.ParamLen = uint8(len(buf) - 2) - buf[1] = o.ParamLen - return buf, nil -} - -func NewOptionParameterCapability(capability []ParameterCapabilityInterface) *OptionParameterCapability { - return &OptionParameterCapability{ - ParamType: BGP_OPT_CAPABILITY, - Capability: capability, - } -} - -type OptionParameterUnknown struct { - ParamType uint8 - ParamLen uint8 - Value []byte -} - -func (o *OptionParameterUnknown) Serialize() ([]byte, error) { - buf := make([]byte, 2+len(o.Value)) - buf[0] = o.ParamType - if o.ParamLen == 0 { - o.ParamLen = uint8(len(o.Value)) - } - buf[1] = o.ParamLen - copy(buf[2:], o.Value) - return buf, nil -} - -type BGPOpen struct { - Version uint8 - MyAS uint16 - HoldTime uint16 - ID net.IP - OptParamLen uint8 - OptParams []OptionParameterInterface -} - -func (msg *BGPOpen) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if len(data) < 10 { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP Open message bytes available") - } - msg.Version = data[0] - msg.MyAS = binary.BigEndian.Uint16(data[1:3]) - msg.HoldTime = binary.BigEndian.Uint16(data[3:5]) - msg.ID = net.IP(data[5:9]).To4() - msg.OptParamLen = data[9] - data = data[10:] - if len(data) < int(msg.OptParamLen) { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP Open message bytes available") - } - - msg.OptParams = []OptionParameterInterface{} - for rest := msg.OptParamLen; rest > 0; { - if rest < 2 { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Malformed BGP Open message") - } - paramtype := data[0] - paramlen := data[1] - if paramlen >= 254 || rest < paramlen+2 { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Malformed BGP Open message") - } - rest -= paramlen + 2 - - if paramtype == BGP_OPT_CAPABILITY { - p := &OptionParameterCapability{} - p.ParamType = paramtype - p.ParamLen = paramlen - p.DecodeFromBytes(data[2 : 2+paramlen]) - msg.OptParams = append(msg.OptParams, p) - } else { - p := &OptionParameterUnknown{} - p.ParamType = paramtype - p.ParamLen = paramlen - p.Value = data[2 : 2+paramlen] - msg.OptParams = append(msg.OptParams, p) - } - data = data[2+paramlen:] - } - return nil -} - -func (msg *BGPOpen) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 10) - buf[0] = msg.Version - binary.BigEndian.PutUint16(buf[1:3], msg.MyAS) - binary.BigEndian.PutUint16(buf[3:5], msg.HoldTime) - copy(buf[5:9], msg.ID.To4()) - pbuf := make([]byte, 0) - for _, p := range msg.OptParams { - onepbuf, err := p.Serialize() - if err != nil { - return nil, err - } - pbuf = append(pbuf, onepbuf...) - } - msg.OptParamLen = uint8(len(pbuf)) - buf[9] = msg.OptParamLen - return append(buf, pbuf...), nil -} - -func NewBGPOpenMessage(myas uint16, holdtime uint16, id string, optparams []OptionParameterInterface) *BGPMessage { - return &BGPMessage{ - Header: BGPHeader{Type: BGP_MSG_OPEN}, - Body: &BGPOpen{4, myas, holdtime, net.ParseIP(id).To4(), 0, optparams}, - } -} - -type AddrPrefixInterface interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) - AFI() uint16 - SAFI() uint8 - Len(...*MarshallingOption) int - String() string - MarshalJSON() ([]byte, error) - // Create a flat map to describe attributes and their - // values. This can be used to create structured outputs. - Flat() map[string]string - PathIdentifier() uint32 - SetPathIdentifier(uint32) - PathLocalIdentifier() uint32 - SetPathLocalIdentifier(uint32) -} - -func LabelString(nlri AddrPrefixInterface) string { - label := "" - switch n := nlri.(type) { - case *LabeledIPAddrPrefix: - label = n.Labels.String() - case *LabeledIPv6AddrPrefix: - label = n.Labels.String() - case *LabeledVPNIPAddrPrefix: - label = n.Labels.String() - case *LabeledVPNIPv6AddrPrefix: - label = n.Labels.String() - case *EVPNNLRI: - switch route := n.RouteTypeData.(type) { - case *EVPNEthernetAutoDiscoveryRoute: - label = fmt.Sprintf("[%d]", route.Label) - case *EVPNMacIPAdvertisementRoute: - ls := make([]string, len(route.Labels)) - for i, l := range route.Labels { - ls[i] = strconv.Itoa(int(l)) - } - label = fmt.Sprintf("[%s]", strings.Join(ls, ",")) - case *EVPNIPPrefixRoute: - label = fmt.Sprintf("[%d]", route.Label) - } - } - return label -} - -type PrefixDefault struct { - mu sync.Mutex - id uint32 - localId uint32 -} - -func (p *PrefixDefault) PathIdentifier() uint32 { - p.mu.Lock() - defer p.mu.Unlock() - - return p.id -} - -func (p *PrefixDefault) SetPathIdentifier(id uint32) { - p.mu.Lock() - defer p.mu.Unlock() - - p.id = id -} - -func (p *PrefixDefault) PathLocalIdentifier() uint32 { - p.mu.Lock() - defer p.mu.Unlock() - - return p.localId -} - -func (p *PrefixDefault) SetPathLocalIdentifier(id uint32) { - p.mu.Lock() - defer p.mu.Unlock() - - p.localId = id -} - -func (p *PrefixDefault) decodePathIdentifier(data []byte) ([]byte, error) { - if len(data) < 4 { - code := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - subcode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return nil, NewMessageError(code, subcode, nil, "prefix misses path identifier field") - } - p.SetPathIdentifier(binary.BigEndian.Uint32(data[:4])) - return data[4:], nil -} - -func (p *PrefixDefault) serializeIdentifier() ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, p.PathLocalIdentifier()) - return buf, nil -} - -type IPAddrPrefixDefault struct { - PrefixDefault - Length uint8 - Prefix net.IP -} - -func (r *IPAddrPrefixDefault) decodePrefix(data []byte, bitlen uint8, addrlen uint8) error { - bytelen := (int(bitlen) + 7) / 8 - if len(data) < bytelen { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "network bytes is short") - } - if bitlen > addrlen*8 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "network bit length is too long") - } - b := make([]byte, addrlen) - copy(b, data[:bytelen]) - // clear trailing bits in the last byte. rfc doesn't require - // this but some bgp implementations need this... - rem := bitlen % 8 - if rem != 0 { - mask := 0xff00 >> rem - lastByte := b[bytelen-1] & byte(mask) - b[bytelen-1] = lastByte - } - r.Prefix = b - return nil -} - -func (r *IPAddrPrefixDefault) serializePrefix(bitLen uint8) ([]byte, error) { - byteLen := (int(bitLen) + 7) / 8 - buf := make([]byte, byteLen) - copy(buf, r.Prefix) - return buf, nil -} - -func (r *IPAddrPrefixDefault) String() string { - return r.Prefix.String() + "/" + strconv.FormatUint(uint64(r.Length), 10) -} - -func (r *IPAddrPrefixDefault) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Prefix string `json:"prefix"` - }{ - Prefix: r.String(), - }) -} - -type IPAddrPrefix struct { - IPAddrPrefixDefault - addrlen uint8 -} - -func (r *IPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if r.addrlen == 0 { - r.addrlen = 4 - } - f := RF_IPv4_UC - if r.addrlen == 16 { - f = RF_IPv6_UC - } - if IsAddPathEnabled(true, f, options) { - var err error - data, err = r.decodePathIdentifier(data) - if err != nil { - return err - } - } - if len(data) < 1 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "prefix misses length field") - } - r.Length = data[0] - return r.decodePrefix(data[1:], r.Length, r.addrlen) -} - -func (r *IPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - f := RF_IPv4_UC - if r.addrlen == 16 { - f = RF_IPv6_UC - } - var buf []byte - if IsAddPathEnabled(false, f, options) { - var err error - buf, err = r.serializeIdentifier() - if err != nil { - return nil, err - } - } - buf = append(buf, r.Length) - pbuf, err := r.serializePrefix(r.Length) - if err != nil { - return nil, err - } - return append(buf, pbuf...), nil -} - -func (r *IPAddrPrefix) AFI() uint16 { - return AFI_IP -} - -func (r *IPAddrPrefix) SAFI() uint8 { - return SAFI_UNICAST -} - -func (r *IPAddrPrefix) Len(options ...*MarshallingOption) int { - return 1 + ((int(r.Length) + 7) / 8) -} - -func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix { - p := &IPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length, - }, - 4, - } - p.IPAddrPrefixDefault.decodePrefix(net.ParseIP(prefix).To4(), length, 4) - return p -} - -func isIPv4MappedIPv6(ip net.IP) bool { - return len(ip) == net.IPv6len && ip.To4() != nil -} - -type IPv6AddrPrefix struct { - IPAddrPrefix -} - -func (r *IPv6AddrPrefix) AFI() uint16 { - return AFI_IP6 -} - -func (r *IPv6AddrPrefix) String() string { - prefix := r.Prefix.String() - if isIPv4MappedIPv6(r.Prefix) { - prefix = "::ffff:" + prefix - } - return prefix + "/" + strconv.FormatUint(uint64(r.Length), 10) -} - -func NewIPv6AddrPrefix(length uint8, prefix string) *IPv6AddrPrefix { - p := &IPv6AddrPrefix{ - IPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length, - }, - 16, - }, - } - p.IPAddrPrefixDefault.decodePrefix(net.ParseIP(prefix), length, 16) - return p -} - -const ( - BGP_RD_TWO_OCTET_AS = iota - BGP_RD_IPV4_ADDRESS - BGP_RD_FOUR_OCTET_AS - BGP_RD_EOR -) - -type RouteDistinguisherInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int - String() string - MarshalJSON() ([]byte, error) -} - -type DefaultRouteDistinguisher struct { - Type uint16 -} - -func (rd *DefaultRouteDistinguisher) serialize(value []byte) ([]byte, error) { - buf := make([]byte, 8) - binary.BigEndian.PutUint16(buf, rd.Type) - copy(buf[2:], value) - return buf, nil -} - -func (rd *DefaultRouteDistinguisher) Len() int { - return 8 -} - -type RouteDistinguisherTwoOctetAS struct { - DefaultRouteDistinguisher - Admin uint16 - Assigned uint32 -} - -func (rd *RouteDistinguisherTwoOctetAS) DecodeFromBytes(data []byte) error { - rd.Admin = binary.BigEndian.Uint16(data[0:2]) - rd.Assigned = binary.BigEndian.Uint32(data[2:6]) - return nil -} - -func (rd *RouteDistinguisherTwoOctetAS) Serialize() ([]byte, error) { - buf := make([]byte, 6) - binary.BigEndian.PutUint16(buf[0:2], rd.Admin) - binary.BigEndian.PutUint32(buf[2:6], rd.Assigned) - return rd.serialize(buf) -} - -func (rd *RouteDistinguisherTwoOctetAS) String() string { - return fmt.Sprintf("%d:%d", rd.Admin, rd.Assigned) -} - -func (rd *RouteDistinguisherTwoOctetAS) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Admin uint16 `json:"admin"` - Assigned uint32 `json:"assigned"` - }{ - Type: rd.Type, - Admin: rd.Admin, - Assigned: rd.Assigned, - }) -} - -func NewRouteDistinguisherTwoOctetAS(admin uint16, assigned uint32) *RouteDistinguisherTwoOctetAS { - return &RouteDistinguisherTwoOctetAS{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: BGP_RD_TWO_OCTET_AS, - }, - Admin: admin, - Assigned: assigned, - } -} - -type RouteDistinguisherIPAddressAS struct { - DefaultRouteDistinguisher - Admin net.IP - Assigned uint16 -} - -func (rd *RouteDistinguisherIPAddressAS) DecodeFromBytes(data []byte) error { - rd.Admin = data[0:4] - rd.Assigned = binary.BigEndian.Uint16(data[4:6]) - return nil -} - -func (rd *RouteDistinguisherIPAddressAS) Serialize() ([]byte, error) { - buf := make([]byte, 6) - copy(buf[0:4], rd.Admin.To4()) - binary.BigEndian.PutUint16(buf[4:6], rd.Assigned) - return rd.serialize(buf) -} - -func (rd *RouteDistinguisherIPAddressAS) String() string { - return fmt.Sprintf("%s:%d", rd.Admin.String(), rd.Assigned) -} - -func (rd *RouteDistinguisherIPAddressAS) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Admin string `json:"admin"` - Assigned uint16 `json:"assigned"` - }{ - Type: rd.Type, - Admin: rd.Admin.String(), - Assigned: rd.Assigned, - }) -} - -func NewRouteDistinguisherIPAddressAS(admin string, assigned uint16) *RouteDistinguisherIPAddressAS { - return &RouteDistinguisherIPAddressAS{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: BGP_RD_IPV4_ADDRESS, - }, - Admin: net.ParseIP(admin).To4(), - Assigned: assigned, - } -} - -type RouteDistinguisherFourOctetAS struct { - DefaultRouteDistinguisher - Admin uint32 - Assigned uint16 -} - -func (rd *RouteDistinguisherFourOctetAS) DecodeFromBytes(data []byte) error { - rd.Admin = binary.BigEndian.Uint32(data[0:4]) - rd.Assigned = binary.BigEndian.Uint16(data[4:6]) - return nil -} - -func (rd *RouteDistinguisherFourOctetAS) Serialize() ([]byte, error) { - buf := make([]byte, 6) - binary.BigEndian.PutUint32(buf[0:4], rd.Admin) - binary.BigEndian.PutUint16(buf[4:6], rd.Assigned) - return rd.serialize(buf) -} - -func (rd *RouteDistinguisherFourOctetAS) String() string { - fst := rd.Admin >> 16 & 0xffff - snd := rd.Admin & 0xffff - return fmt.Sprintf("%d.%d:%d", fst, snd, rd.Assigned) -} - -func (rd *RouteDistinguisherFourOctetAS) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Admin uint32 `json:"admin"` - Assigned uint16 `json:"assigned"` - }{ - Type: rd.Type, - Admin: rd.Admin, - Assigned: rd.Assigned, - }) -} - -func NewRouteDistinguisherFourOctetAS(admin uint32, assigned uint16) *RouteDistinguisherFourOctetAS { - return &RouteDistinguisherFourOctetAS{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: BGP_RD_FOUR_OCTET_AS, - }, - Admin: admin, - Assigned: assigned, - } -} - -type RouteDistinguisherUnknown struct { - DefaultRouteDistinguisher - Value []byte -} - -func (rd *RouteDistinguisherUnknown) DecodeFromBytes(data []byte) error { - rd.Value = data[0:6] - return nil -} - -func (rd *RouteDistinguisherUnknown) Serialize() ([]byte, error) { - return rd.DefaultRouteDistinguisher.serialize(rd.Value) -} - -func (rd *RouteDistinguisherUnknown) String() string { - return fmt.Sprintf("%v", rd.Value) -} - -func (rd *RouteDistinguisherUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Value []byte `json:"value"` - }{ - Type: rd.Type, - Value: rd.Value, - }) -} - -func GetRouteDistinguisher(data []byte) RouteDistinguisherInterface { - typ := binary.BigEndian.Uint16(data[0:2]) - switch typ { - case BGP_RD_TWO_OCTET_AS: - return NewRouteDistinguisherTwoOctetAS(binary.BigEndian.Uint16(data[2:4]), binary.BigEndian.Uint32(data[4:8])) - case BGP_RD_IPV4_ADDRESS: - return NewRouteDistinguisherIPAddressAS(net.IP(data[2:6]).String(), binary.BigEndian.Uint16(data[6:8])) - case BGP_RD_FOUR_OCTET_AS: - return NewRouteDistinguisherFourOctetAS(binary.BigEndian.Uint32(data[2:6]), binary.BigEndian.Uint16(data[6:8])) - } - rd := &RouteDistinguisherUnknown{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: typ, - }, - } - return rd -} - -func parseRdAndRt(input string) ([]string, error) { - elems := _regexpRouteDistinguisher.FindStringSubmatch(input) - if len(elems) != 11 { - return nil, fmt.Errorf("failed to parse RD %q", input) - } - return elems, nil -} - -func ParseRouteDistinguisher(rd string) (RouteDistinguisherInterface, error) { - elems, err := parseRdAndRt(rd) - if err != nil { - return nil, err - } - assigned, _ := strconv.ParseUint(elems[10], 10, 32) - ip := net.ParseIP(elems[1]) - switch { - case ip.To4() != nil: - return NewRouteDistinguisherIPAddressAS(elems[1], uint16(assigned)), nil - case elems[6] == "" && elems[7] == "": - asn, _ := strconv.ParseUint(elems[8], 10, 16) - return NewRouteDistinguisherTwoOctetAS(uint16(asn), uint32(assigned)), nil - default: - fst, _ := strconv.ParseUint(elems[7], 10, 16) - snd, _ := strconv.ParseUint(elems[8], 10, 16) - asn := fst<<16 | snd - return NewRouteDistinguisherFourOctetAS(uint32(asn), uint16(assigned)), nil - } -} - -// ParseVPNPrefix parses VPNv4/VPNv6 prefix. -func ParseVPNPrefix(prefix string) (RouteDistinguisherInterface, net.IP, *net.IPNet, error) { - elems := strings.SplitN(prefix, ":", 3) - if len(elems) < 3 { - return nil, nil, nil, fmt.Errorf("invalid VPN prefix format: %q", prefix) - } - - rd, err := ParseRouteDistinguisher(elems[0] + ":" + elems[1]) - if err != nil { - return nil, nil, nil, err - } - - addr, network, err := net.ParseCIDR(elems[2]) - return rd, addr, network, err -} - -// ContainsCIDR checks if one IPNet is a subnet of another. -func ContainsCIDR(n1, n2 *net.IPNet) bool { - ones1, _ := n1.Mask.Size() - ones2, _ := n2.Mask.Size() - return ones1 <= ones2 && n1.Contains(n2.IP) -} - -// -// RFC3107 Carrying Label Information in BGP-4 -// -// 3. Carrying Label Mapping Information -// -// b) Label: -// -// The Label field carries one or more labels (that corresponds to -// the stack of labels [MPLS-ENCAPS(RFC3032)]). Each label is encoded as -// 4 octets, where the high-order 20 bits contain the label value, and -// the low order bit contains "Bottom of Stack" -// -// RFC3032 MPLS Label Stack Encoding -// -// 2.1. Encoding the Label Stack -// -// 0 1 2 3 -// 0 ... 9 0 ... 9 0 1 2 3 4 ... 9 0 1 -// +-----+-+-+---+-+-+-+-+-+-----+-+-+-+ -// | Label | Exp |S| TTL | -// +-----+-+-+---+-+-+-+-+-+-----+-+-+-+ -// - -// RFC3107 Carrying Label Information in BGP-4 -// -// 3. Carrying Label Mapping Information -// -// The label information carried (as part of NLRI) in the Withdrawn -// Routes field should be set to 0x800000. -const WITHDRAW_LABEL = uint32(0x800000) -const ZERO_LABEL = uint32(0) // some platform uses this as withdraw label - -type MPLSLabelStack struct { - Labels []uint32 -} - -func (l *MPLSLabelStack) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - labels := []uint32{} - foundBottom := false - bottomExpected := true - if IsAttributePresent(BGP_ATTR_TYPE_PREFIX_SID, options) { - // If Update carries Prefix SID attribute then one should not rely on BoS for the label stack processing, - // the first and only label carries transposed variable part of the SRv6 SID. - bottomExpected = false - } - for len(data) >= 3 { - label := uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]) - if label == WITHDRAW_LABEL || label == ZERO_LABEL { - l.Labels = []uint32{label} - return nil - } - data = data[3:] - labels = append(labels, label>>4) - if !bottomExpected { - // Faking found bottom. - foundBottom = true - break - } - if label&1 == 1 { - foundBottom = true - break - } - } - - if !foundBottom { - l.Labels = []uint32{} - return nil - } - l.Labels = labels - return nil -} - -func (l *MPLSLabelStack) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, len(l.Labels)*3) - for i, label := range l.Labels { - if label == WITHDRAW_LABEL { - return []byte{128, 0, 0}, nil - } - label = label << 4 - buf[i*3] = byte((label >> 16) & 0xff) - buf[i*3+1] = byte((label >> 8) & 0xff) - buf[i*3+2] = byte(label & 0xff) - } - buf[len(buf)-1] |= 1 - return buf, nil -} - -func (l *MPLSLabelStack) Len() int { return 3 * len(l.Labels) } - -func (l *MPLSLabelStack) String() string { - if len(l.Labels) == 0 { - return "" - } - s := bytes.NewBuffer(make([]byte, 0, 64)) - s.WriteString("[") - ss := make([]string, 0, len(l.Labels)) - for _, label := range l.Labels { - ss = append(ss, fmt.Sprintf("%d", label)) - } - s.WriteString(strings.Join(ss, ", ")) - s.WriteString("]") - return s.String() -} - -func NewMPLSLabelStack(labels ...uint32) *MPLSLabelStack { - if len(labels) == 0 { - labels = []uint32{0} - } - return &MPLSLabelStack{labels} -} - -func ParseMPLSLabelStack(buf string) (*MPLSLabelStack, error) { - elems := strings.Split(buf, "/") - labels := make([]uint32, 0, len(elems)) - if len(elems) == 0 { - goto ERR - } - for _, elem := range elems { - i, err := strconv.ParseUint(elem, 10, 32) - if err != nil { - goto ERR - } - if i > ((1 << 20) - 1) { - goto ERR - } - labels = append(labels, uint32(i)) - } - return NewMPLSLabelStack(labels...), nil -ERR: - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "invalid mpls label stack format") -} - -// -// RFC3107 Carrying Label Information in BGP-4 -// -// 3. Carrying Label Mapping Information -// -// +----------------------+ -// | Length (1 octet) | -// +----------------------+ -// | Label (3 octets) | -// +----------------------+ -// ....................... -// +----------------------+ -// | Prefix (variable) | -// +----------------------+ -// -// RFC4364 BGP/MPLS IP VPNs -// -// 4.3.4. How VPN-IPv4 NLRI Is Carried in BGP -// -// The labeled VPN-IPv4 NLRI itself is encoded as specified in -// [MPLS-BGP(RFC3107)], where the prefix consists of an 8-byte RD -// followed by an IPv4 prefix. -// - -type LabeledVPNIPAddrPrefix struct { - IPAddrPrefixDefault - Labels MPLSLabelStack - RD RouteDistinguisherInterface - addrlen uint8 -} - -func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - f := RF_IPv4_VPN - if l.addrlen == 16 { - f = RF_IPv6_VPN - } - if IsAddPathEnabled(true, f, options) { - var err error - data, err = l.decodePathIdentifier(data) - if err != nil { - return err - } - } - if len(data) < 1 { - return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field") - } - l.Length = uint8(data[0]) - data = data[1:] - l.Labels.DecodeFromBytes(data, options...) - if int(l.Length)-8*(l.Labels.Len()) < 0 { - l.Labels.Labels = []uint32{} - } - data = data[l.Labels.Len():] - l.RD = GetRouteDistinguisher(data) - rdLen := l.RD.Len() - if len(data) < rdLen { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "bad labeled VPN-IPv4 NLRI length") - } - data = data[l.RD.Len():] - restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len()) - return l.decodePrefix(data, uint8(restbits), l.addrlen) -} - -func (l *LabeledVPNIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - f := RF_IPv4_VPN - if l.addrlen == 16 { - f = RF_IPv6_VPN - } - var buf []byte - if IsAddPathEnabled(false, f, options) { - var err error - buf, err = l.serializeIdentifier() - if err != nil { - return nil, err - } - } - buf = append(buf, l.Length) - lbuf, err := l.Labels.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, lbuf...) - rbuf, err := l.RD.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, rbuf...) - restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len()) - pbuf, err := l.serializePrefix(uint8(restbits)) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - return buf, nil -} - -func (l *LabeledVPNIPAddrPrefix) AFI() uint16 { - return AFI_IP -} - -func (l *LabeledVPNIPAddrPrefix) SAFI() uint8 { - return SAFI_MPLS_VPN -} - -func (l *LabeledVPNIPAddrPrefix) IPPrefixLen() uint8 { - return l.Length - 8*uint8(l.Labels.Len()+l.RD.Len()) -} - -func (l *LabeledVPNIPAddrPrefix) Len(options ...*MarshallingOption) int { - return 1 + l.Labels.Len() + l.RD.Len() + int((l.IPPrefixLen()+7)/8) -} - -func (l *LabeledVPNIPAddrPrefix) String() string { - return l.RD.String() + ":" + l.IPPrefix() -} - -func (l *LabeledVPNIPAddrPrefix) IPPrefix() string { - masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len())) - return l.IPAddrPrefixDefault.Prefix.String() + "/" + strconv.FormatUint(uint64(masklen), 10) -} - -func (l *LabeledVPNIPAddrPrefix) MarshalJSON() ([]byte, error) { - masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len())) - return json.Marshal(struct { - Prefix string `json:"prefix"` - Labels []uint32 `json:"labels"` - RD RouteDistinguisherInterface `json:"rd"` - }{ - Prefix: fmt.Sprintf("%s/%d", l.IPAddrPrefixDefault.Prefix, masklen), - Labels: l.Labels.Labels, - RD: l.RD, - }) -} - -func NewLabeledVPNIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack, rd RouteDistinguisherInterface) *LabeledVPNIPAddrPrefix { - rdlen := 0 - if rd != nil { - rdlen = rd.Len() - } - return &LabeledVPNIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(8*(label.Len()+rdlen)), - Prefix: net.ParseIP(prefix).To4(), - }, - label, - rd, - 4, - } -} - -type LabeledVPNIPv6AddrPrefix struct { - LabeledVPNIPAddrPrefix -} - -func (l *LabeledVPNIPv6AddrPrefix) AFI() uint16 { - return AFI_IP6 -} - -func NewLabeledVPNIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack, rd RouteDistinguisherInterface) *LabeledVPNIPv6AddrPrefix { - rdlen := 0 - if rd != nil { - rdlen = rd.Len() - } - return &LabeledVPNIPv6AddrPrefix{ - LabeledVPNIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(8*(label.Len()+rdlen)), - Prefix: net.ParseIP(prefix), - }, - label, - rd, - 16, - }, - } -} - -type LabeledIPAddrPrefix struct { - IPAddrPrefixDefault - Labels MPLSLabelStack - addrlen uint8 -} - -func (r *LabeledIPAddrPrefix) AFI() uint16 { - return AFI_IP -} - -func (r *LabeledIPAddrPrefix) SAFI() uint8 { - return SAFI_MPLS_LABEL -} - -func (l *LabeledIPAddrPrefix) IPPrefixLen() uint8 { - return l.Length - 8*uint8(l.Labels.Len()) -} - -func (l *LabeledIPAddrPrefix) Len(options ...*MarshallingOption) int { - return 1 + l.Labels.Len() + int((l.IPPrefixLen()+7)/8) -} - -func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - f := RF_IPv4_MPLS - if l.addrlen == 16 { - f = RF_IPv6_MPLS - } - if IsAddPathEnabled(true, f, options) { - var err error - data, err = l.decodePathIdentifier(data) - if err != nil { - return err - } - } - l.Length = uint8(data[0]) - data = data[1:] - l.Labels.DecodeFromBytes(data) - - if int(l.Length)-8*(l.Labels.Len()) < 0 { - l.Labels.Labels = []uint32{} - } - restbits := int(l.Length) - 8*(l.Labels.Len()) - data = data[l.Labels.Len():] - return l.decodePrefix(data, uint8(restbits), l.addrlen) -} - -func (l *LabeledIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - f := RF_IPv4_MPLS - if l.addrlen == 16 { - f = RF_IPv6_MPLS - } - var buf []byte - if IsAddPathEnabled(false, f, options) { - var err error - buf, err = l.serializeIdentifier() - if err != nil { - return nil, err - } - } - buf = append(buf, l.Length) - restbits := int(l.Length) - 8*(l.Labels.Len()) - lbuf, err := l.Labels.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, lbuf...) - pbuf, err := l.serializePrefix(uint8(restbits)) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - return buf, nil -} - -func (l *LabeledIPAddrPrefix) String() string { - prefix := l.Prefix.String() - if isIPv4MappedIPv6(l.Prefix) { - prefix = "::ffff:" + prefix - } - masklen := int(l.Length) - l.Labels.Len()*8 - return prefix + "/" + strconv.FormatUint(uint64(masklen), 10) -} - -func (l *LabeledIPAddrPrefix) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Prefix string `json:"prefix"` - Labels []uint32 `json:"labels"` - }{ - Prefix: l.String(), - Labels: l.Labels.Labels, - }) -} - -func NewLabeledIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPAddrPrefix { - return &LabeledIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(label.Len()*8), - Prefix: net.ParseIP(prefix).To4(), - }, - label, - 4, - } -} - -type LabeledIPv6AddrPrefix struct { - LabeledIPAddrPrefix -} - -func (l *LabeledIPv6AddrPrefix) AFI() uint16 { - return AFI_IP6 -} - -func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPv6AddrPrefix { - return &LabeledIPv6AddrPrefix{ - LabeledIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(label.Len()*8), - Prefix: net.ParseIP(prefix), - }, - label, - 16, - }, - } -} - -type RouteTargetMembershipNLRI struct { - PrefixDefault - Length uint8 - AS uint32 - RouteTarget ExtendedCommunityInterface -} - -func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if IsAddPathEnabled(true, RF_RTC_UC, options) { - var err error - data, err = n.decodePathIdentifier(data) - if err != nil { - return err - } - } - if len(data) < 1 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "prefix misses length field") - } - n.Length = data[0] - if n.Length == 0 { - return nil - } - data = data[1:] - if n.Length < 32 || len(data)*8 < int(n.Length) { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "bad RouteTargetMembershipNLRI length") - } - n.AS = binary.BigEndian.Uint32(data[0:4]) - if n.Length < 96 { - return nil - } - rt, err := ParseExtended(data[4:]) - if err != nil { - return err - } - n.RouteTarget = rt - return nil -} - -func (n *RouteTargetMembershipNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - if IsAddPathEnabled(false, RF_RTC_UC, options) { - var err error - buf, err = n.serializeIdentifier() - if err != nil { - return nil, err - } - } - if n.Length == 0 { - return append(buf, 0), nil - } - offset := len(buf) - buf = append(buf, make([]byte, 5)...) - buf[offset] = n.Length - binary.BigEndian.PutUint32(buf[offset+1:], n.AS) - if n.RouteTarget == nil { - return buf, nil - } - ebuf, err := n.RouteTarget.Serialize() - if err != nil { - return nil, err - } - return append(buf, ebuf...), nil -} - -func (n *RouteTargetMembershipNLRI) AFI() uint16 { - return AFI_IP -} - -func (n *RouteTargetMembershipNLRI) SAFI() uint8 { - return SAFI_ROUTE_TARGET_CONSTRAINTS -} - -func (n *RouteTargetMembershipNLRI) Len(options ...*MarshallingOption) int { - return 1 + (int(n.Length)+7)/8 -} - -func (n *RouteTargetMembershipNLRI) String() string { - if n.Length == 0 { - return "default" - } - target := "0:0" - if n.RouteTarget != nil { - target = n.RouteTarget.String() - } - return strconv.FormatUint(uint64(n.AS), 10) + ":" + target -} - -func (n *RouteTargetMembershipNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Prefix string `json:"prefix"` - }{ - Prefix: n.String(), - }) -} - -func NewRouteTargetMembershipNLRI(as uint32, target ExtendedCommunityInterface) *RouteTargetMembershipNLRI { - l := 12 * 8 - if as == 0 && target == nil { - l = 0 - } else if target == nil { - l = 32 - } - return &RouteTargetMembershipNLRI{ - Length: uint8(l), - AS: as, - RouteTarget: target, - } -} - -//go:generate stringer -type=ESIType -type ESIType uint8 - -const ( - ESI_ARBITRARY ESIType = iota - ESI_LACP - ESI_MSTP - ESI_MAC - ESI_ROUTERID - ESI_AS -) - -type EthernetSegmentIdentifier struct { - Type ESIType - Value []byte -} - -func (esi *EthernetSegmentIdentifier) DecodeFromBytes(data []byte) error { - if len(data) < 10 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid %s length", esi.Type.String())) - } - esi.Type = ESIType(data[0]) - esi.Value = data[1:10] - switch esi.Type { - case ESI_LACP, ESI_MSTP, ESI_ROUTERID, ESI_AS: - if esi.Value[8] != 0x00 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid %s. last octet must be 0x00 (0x%02x)", esi.Type.String(), esi.Value[8])) - } - } - return nil -} - -func (esi *EthernetSegmentIdentifier) Serialize() ([]byte, error) { - buf := make([]byte, 10) - buf[0] = uint8(esi.Type) - copy(buf[1:], esi.Value) - return buf, nil -} - -func isZeroBuf(buf []byte) bool { - for _, b := range buf { - if b != 0 { - return false - } - } - return true -} - -func (esi *EthernetSegmentIdentifier) String() string { - toHexArray := func(data []byte) string { - // Converts byte slice into the colon separated hex values and the - // number of elements are 9 at most (excluding Type field). - values := make([]string, 0, 9) - for _, v := range data { - values = append(values, fmt.Sprintf("%02x", v)) - } - return strings.Join(values, ":") - } - - s := bytes.NewBuffer(make([]byte, 0, 64)) - s.WriteString(fmt.Sprintf("%s | ", esi.Type.String())) - switch esi.Type { - case ESI_LACP: - s.WriteString(fmt.Sprintf("system mac %s, ", net.HardwareAddr(esi.Value[:6]).String())) - s.WriteString(fmt.Sprintf("port key %d", binary.BigEndian.Uint16(esi.Value[6:8]))) - case ESI_MSTP: - s.WriteString(fmt.Sprintf("bridge mac %s, ", net.HardwareAddr(esi.Value[:6]).String())) - s.WriteString(fmt.Sprintf("priority %d", binary.BigEndian.Uint16(esi.Value[6:8]))) - case ESI_MAC: - s.WriteString(fmt.Sprintf("system mac %s, ", net.HardwareAddr(esi.Value[:6]).String())) - s.WriteString(fmt.Sprintf("local discriminator %d", uint32(esi.Value[6])<<16|uint32(esi.Value[7])<<8|uint32(esi.Value[8]))) - case ESI_ROUTERID: - s.WriteString(fmt.Sprintf("router id %s, ", net.IP(esi.Value[:4]))) - s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8]))) - case ESI_AS: - s.WriteString(fmt.Sprintf("as %d, ", binary.BigEndian.Uint32(esi.Value[:4]))) - s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8]))) - case ESI_ARBITRARY: - if isZeroBuf(esi.Value) { - return "single-homed" - } - fallthrough - default: - s.WriteString(toHexArray(esi.Value)) - } - return s.String() -} - -// Decode Ethernet Segment Identifier (ESI) from string slice. -// -// The first element of args should be the Type field (e.g., "ARBITRARY", -// "arbitrary", "ESI_ARBITRARY" or "esi_arbitrary") and "single-homed" is -// the special keyword for all zeroed ESI. -// For the "ARBITRARY" Value field (Type 0), it should be the colon separated -// hex values and the number of elements should be 9 at most. -// -// e.g.) args := []string{"ARBITRARY", "11:22:33:44:55:66:77:88:99"} -// -// For the other types, the Value field format is the similar to the string -// format of ESI. -// -// e.g.) args := []string{"lacp", "aa:bb:cc:dd:ee:ff", "100"} -func ParseEthernetSegmentIdentifier(args []string) (EthernetSegmentIdentifier, error) { - esi := EthernetSegmentIdentifier{} - argLen := len(args) - if argLen == 0 || args[0] == "single-homed" { - return esi, nil - } - - typeStr := strings.TrimPrefix(strings.ToUpper(args[0]), "ESI_") - switch typeStr { - case "ARBITRARY": - esi.Type = ESI_ARBITRARY - case "LACP": - esi.Type = ESI_LACP - case "MSTP": - esi.Type = ESI_MSTP - case "MAC": - esi.Type = ESI_MAC - case "ROUTERID": - esi.Type = ESI_ROUTERID - case "AS": - esi.Type = ESI_AS - default: - typ, err := strconv.ParseUint(args[0], 10, 8) - if err != nil { - return esi, fmt.Errorf("invalid esi type: %s", args[0]) - } - esi.Type = ESIType(typ) - } - - invalidEsiValuesError := fmt.Errorf("invalid esi values for type %s: %s", esi.Type.String(), args[1:]) - esi.Value = make([]byte, 9) - switch esi.Type { - case ESI_LACP: - fallthrough - case ESI_MSTP: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // MAC - mac, err := net.ParseMAC(args[1]) - if err != nil { - return esi, invalidEsiValuesError - } - copy(esi.Value[0:6], mac) - // Port Key or Bridge Priority - i, err := strconv.ParseUint(args[2], 10, 16) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint16(esi.Value[6:8], uint16(i)) - case ESI_MAC: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // MAC - mac, err := net.ParseMAC(args[1]) - if err != nil { - return esi, invalidEsiValuesError - } - copy(esi.Value[0:6], mac) - // Local Discriminator - i, err := strconv.ParseUint(args[2], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - iBuf := make([]byte, 4) - binary.BigEndian.PutUint32(iBuf, uint32(i)) - copy(esi.Value[6:9], iBuf[1:4]) - case ESI_ROUTERID: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // Router ID - ip := net.ParseIP(args[1]) - if ip == nil || ip.To4() == nil { - return esi, invalidEsiValuesError - } - copy(esi.Value[0:4], ip.To4()) - // Local Discriminator - i, err := strconv.ParseUint(args[2], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint32(esi.Value[4:8], uint32(i)) - case ESI_AS: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // AS - as, err := strconv.ParseUint(args[1], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint32(esi.Value[0:4], uint32(as)) - // Local Discriminator - i, err := strconv.ParseUint(args[2], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint32(esi.Value[4:8], uint32(i)) - case ESI_ARBITRARY: - fallthrough - default: - if argLen < 2 { - // Assumes the Value field is omitted - break - } - values := make([]byte, 0, 9) - for _, e := range strings.SplitN(args[1], ":", 9) { - v, err := strconv.ParseUint(e, 16, 16) - if err != nil { - return esi, invalidEsiValuesError - } - values = append(values, byte(v)) - } - copy(esi.Value, values) - } - - return esi, nil -} - -// -// I-D bess-evpn-overlay-01 -// -// 5.1.3 Constructing EVPN BGP Routes -// -// For the balance of this memo, the MPLS label field will be -// referred to as the VNI/VSID field. The VNI/VSID field is used for -// both local and global VNIs/VSIDs, and for either case the entire 24- -// bit field is used to encode the VNI/VSID value. -// -// We can't use type MPLSLabelStack for EVPN NLRI, because EVPN NLRI's MPLS -// field can be filled with VXLAN VNI. In that case, we must avoid modifying -// bottom of stack bit. -// - -func labelDecode(data []byte) (uint32, error) { - if len(data) < 3 { - return 0, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all Label bytes available") - } - return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]), nil -} - -func labelSerialize(label uint32) ([]byte, error) { - if label > 0xffffff { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Out of range Label: %d", label)) - } - buf := make([]byte, 3) - buf[0] = byte((label >> 16) & 0xff) - buf[1] = byte((label >> 8) & 0xff) - buf[2] = byte(label & 0xff) - return buf, nil -} - -type EVPNEthernetAutoDiscoveryRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - ETag uint32 - Label uint32 -} - -func (er *EVPNEthernetAutoDiscoveryRoute) Len() int { - // RD(8) + ESI(10) + ETag(4) + Label(3) - return 25 -} - -func (er *EVPNEthernetAutoDiscoveryRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - rdLen := er.RD.Len() - if len(data) < rdLen+14 { // 14 is 10 for - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "bad Ethernet Auto-discovery Route length") - } - data = data[er.RD.Len():] - err := er.ESI.DecodeFromBytes(data) - if err != nil { - return err - } - data = data[10:] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - data = data[4:] - if er.Label, err = labelDecode(data); err != nil { - return err - } - return nil -} - -func (er *EVPNEthernetAutoDiscoveryRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - - var tagBuf [4]byte - binary.BigEndian.PutUint32(tagBuf[:4], er.ETag) - buf = append(buf, tagBuf[:4]...) - - tbuf, err = labelSerialize(er.Label) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - - return buf, nil -} - -func (er *EVPNEthernetAutoDiscoveryRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.1. Ethernet Auto-discovery Route - // For the purpose of BGP route key processing, only the Ethernet - // Segment Identifier and the Ethernet Tag ID are considered to be part - // of the prefix in the NLRI. The MPLS Label field is to be treated as - // a route attribute as opposed to being part of the route. - return fmt.Sprintf("[type:A-D][rd:%s][esi:%s][etag:%d]", er.RD, er.ESI.String(), er.ETag) -} - -func (er *EVPNEthernetAutoDiscoveryRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - Etag uint32 `json:"etag"` - Label uint32 `json:"label"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - Etag: er.ETag, - Label: er.Label, - }) -} - -func (er *EVPNEthernetAutoDiscoveryRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNEthernetAutoDiscoveryRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, label uint32) *EVPNNLRI { - return NewEVPNNLRI(EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY, &EVPNEthernetAutoDiscoveryRoute{ - RD: rd, - ESI: esi, - ETag: etag, - Label: label, - }) -} - -type EVPNMacIPAdvertisementRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - ETag uint32 - MacAddressLength uint8 - MacAddress net.HardwareAddr - IPAddressLength uint8 - IPAddress net.IP - Labels []uint32 -} - -func (er *EVPNMacIPAdvertisementRoute) Len() int { - // RD(8) + ESI(10) + ETag(4) + MacAddressLength(1) + MacAddress(6) - // + IPAddressLength(1) + IPAddress(0, 4 or 16) + Labels(3 or 6) - return 30 + int(er.IPAddressLength)/8 + len(er.Labels)*3 -} - -func (er *EVPNMacIPAdvertisementRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - rdLen := er.RD.Len() - if len(data) < rdLen { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "bad length of MAC/IP Advertisement Route") - } - data = data[er.RD.Len():] - err := er.ESI.DecodeFromBytes(data) - if err != nil { - return err - } - data = data[10:] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - data = data[4:] - er.MacAddressLength = data[0] - er.MacAddress = net.HardwareAddr(data[1:7]) - er.IPAddressLength = data[7] - data = data[8:] - if er.IPAddressLength == 32 || er.IPAddressLength == 128 { - er.IPAddress = net.IP(data[0:((er.IPAddressLength) / 8)]) - } else if er.IPAddressLength != 0 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength)) - } - data = data[(er.IPAddressLength / 8):] - var label uint32 - if label, err = labelDecode(data); err != nil { - return err - } - er.Labels = append(er.Labels, label) - data = data[3:] - if len(data) == 3 { - if label, err = labelDecode(data); err != nil { - return err - } - er.Labels = append(er.Labels, label) - } - return nil -} - -func (er *EVPNMacIPAdvertisementRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - - esi, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - - buf = append(buf, esi...) - var tbuf [7]byte - binary.BigEndian.PutUint32(tbuf[:4], er.ETag) - buf = append(buf, tbuf[:4]...) - tbuf[0] = er.MacAddressLength - copy(tbuf[1:], er.MacAddress) - buf = append(buf, tbuf[:7]...) - - buf = append(buf, er.IPAddressLength) - switch er.IPAddressLength { - case 0: - // IP address omitted - case 32: - buf = append(buf, []byte(er.IPAddress.To4())...) - case 128: - buf = append(buf, []byte(er.IPAddress.To16())...) - default: - return nil, fmt.Errorf("invalid IP address length: %d", er.IPAddressLength) - } - - for _, l := range er.Labels { - label, err := labelSerialize(l) - if err != nil { - return nil, err - } - buf = append(buf, label...) - } - return buf, nil -} - -func (er *EVPNMacIPAdvertisementRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.2. MAC/IP Advertisement Route - // For the purpose of BGP route key processing, only the Ethernet Tag - // ID, MAC Address Length, MAC Address, IP Address Length, and IP - // Address fields are considered to be part of the prefix in the NLRI. - // The Ethernet Segment Identifier, MPLS Label1, and MPLS Label2 fields - // are to be treated as route attributes as opposed to being part of the - // "route". - return fmt.Sprintf("[type:macadv][rd:%s][etag:%d][mac:%s][ip:%s]", er.RD, er.ETag, er.MacAddress, er.IPAddress) -} - -func (er *EVPNMacIPAdvertisementRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - Etag uint32 `json:"etag"` - MacAddress string `json:"mac"` - IPAddress string `json:"ip"` - Labels []uint32 `json:"labels"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - Etag: er.ETag, - MacAddress: er.MacAddress.String(), - IPAddress: er.IPAddress.String(), - Labels: er.Labels, - }) -} - -func (er *EVPNMacIPAdvertisementRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNMacIPAdvertisementRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, macAddress string, ipAddress string, labels []uint32) *EVPNNLRI { - mac, _ := net.ParseMAC(macAddress) - var ipLen uint8 - ip := net.ParseIP(ipAddress) - if ip != nil { - if ipv4 := ip.To4(); ipv4 != nil { - ipLen = 32 - ip = ipv4 - } else { - ipLen = 128 - } - } - return NewEVPNNLRI(EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, &EVPNMacIPAdvertisementRoute{ - RD: rd, - ESI: esi, - ETag: etag, - MacAddressLength: 48, - MacAddress: mac, - IPAddressLength: ipLen, - IPAddress: ip, - Labels: labels, - }) -} - -type EVPNMulticastEthernetTagRoute struct { - RD RouteDistinguisherInterface - ETag uint32 - IPAddressLength uint8 - IPAddress net.IP -} - -func (er *EVPNMulticastEthernetTagRoute) Len() int { - // RD(8) + ETag(4) + IPAddressLength(1) + IPAddress(4 or 16) - return 13 + int(er.IPAddressLength)/8 -} - -func (er *EVPNMulticastEthernetTagRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - rdLen := er.RD.Len() - if len(data) < rdLen+4 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "invalid length of multicast ethernet tag route") - } - data = data[er.RD.Len():] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - er.IPAddressLength = data[4] - data = data[5:] - if er.IPAddressLength == 32 || er.IPAddressLength == 128 { - er.IPAddress = net.IP(data[:er.IPAddressLength/8]) - } else { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength)) - } - return nil -} - -func (er *EVPNMulticastEthernetTagRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - var tbuf [4]byte - binary.BigEndian.PutUint32(tbuf[:4], er.ETag) - buf = append(buf, tbuf[:4]...) - buf = append(buf, er.IPAddressLength) - switch er.IPAddressLength { - case 32: - buf = append(buf, []byte(er.IPAddress.To4())...) - case 128: - buf = append(buf, []byte(er.IPAddress.To16())...) - default: - return nil, fmt.Errorf("invalid IP address length: %d", er.IPAddressLength) - } - return buf, nil -} - -func (er *EVPNMulticastEthernetTagRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.3. Inclusive Multicast Ethernet Tag Route - // ...(snip)... For the purpose of BGP route key - // processing, only the Ethernet Tag ID, IP Address Length, and - // Originating Router's IP Address fields are considered to be part of - // the prefix in the NLRI. - return fmt.Sprintf("[type:multicast][rd:%s][etag:%d][ip:%s]", er.RD, er.ETag, er.IPAddress) -} - -func (er *EVPNMulticastEthernetTagRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - Etag uint32 `json:"etag"` - IPAddress string `json:"ip"` - }{ - RD: er.RD, - Etag: er.ETag, - IPAddress: er.IPAddress.String(), - }) -} - -func (er *EVPNMulticastEthernetTagRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNMulticastEthernetTagRoute(rd RouteDistinguisherInterface, etag uint32, ipAddress string) *EVPNNLRI { - ipLen := uint8(32) - ip := net.ParseIP(ipAddress) - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } else { - ipLen = 128 - } - return NewEVPNNLRI(EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, &EVPNMulticastEthernetTagRoute{ - RD: rd, - ETag: etag, - IPAddressLength: ipLen, - IPAddress: ip, - }) -} - -type EVPNEthernetSegmentRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - IPAddressLength uint8 - IPAddress net.IP -} - -func (er *EVPNEthernetSegmentRoute) Len() int { - // RD(8) + ESI(10) + IPAddressLength(1) + IPAddress(4 or 16) - return 19 + int(er.IPAddressLength)/8 -} - -func (er *EVPNEthernetSegmentRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - rdLen := er.RD.Len() - if len(data) < rdLen { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "invalid Ethernet Segment Route length") - } - data = data[er.RD.Len():] - er.ESI.DecodeFromBytes(data) - data = data[10:] - er.IPAddressLength = data[0] - data = data[1:] - if er.IPAddressLength == 32 || er.IPAddressLength == 128 { - er.IPAddress = net.IP(data[:er.IPAddressLength/8]) - } else { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength)) - } - return nil -} - -func (er *EVPNEthernetSegmentRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - buf = append(buf, er.IPAddressLength) - switch er.IPAddressLength { - case 32: - buf = append(buf, []byte(er.IPAddress.To4())...) - case 128: - buf = append(buf, []byte(er.IPAddress.To16())...) - default: - return nil, fmt.Errorf("invalid IP address length: %d", er.IPAddressLength) - } - return buf, nil -} - -func (er *EVPNEthernetSegmentRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.4. Ethernet Segment Route - // For the purpose of BGP route key processing, only the Ethernet - // Segment ID, IP Address Length, and Originating Router's IP Address - // fields are considered to be part of the prefix in the NLRI. - return fmt.Sprintf("[type:esi][rd:%s][esi:%s][ip:%s]", er.RD, er.ESI.String(), er.IPAddress) -} - -func (er *EVPNEthernetSegmentRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - IPAddress string `json:"ip"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - IPAddress: er.IPAddress.String(), - }) -} - -func (er *EVPNEthernetSegmentRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNEthernetSegmentRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, ipAddress string) *EVPNNLRI { - ipLen := uint8(32) - ip := net.ParseIP(ipAddress) - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } else { - ipLen = 128 - } - return NewEVPNNLRI(EVPN_ETHERNET_SEGMENT_ROUTE, &EVPNEthernetSegmentRoute{ - RD: rd, - ESI: esi, - IPAddressLength: ipLen, - IPAddress: ip, - }) -} - -type EVPNIPPrefixRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - ETag uint32 - IPPrefixLength uint8 - IPPrefix net.IP - GWIPAddress net.IP - Label uint32 -} - -func (er *EVPNIPPrefixRoute) Len() int { - if er.IPPrefix.To4() != nil { - return 34 - } - return 58 -} - -func (er *EVPNIPPrefixRoute) DecodeFromBytes(data []byte) error { - addrLen := net.IPv4len - switch len(data) { - case 34: - // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) + IPv4 Prefix(4) + GW IPv4(4) + Label(3) - case 58: - // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) + IPv6 Prefix(16) + GW IPv6(16) + Label(3) - addrLen = net.IPv6len - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPN IP Prefix Route bytes available") - } - - er.RD = GetRouteDistinguisher(data[0:8]) - - err := er.ESI.DecodeFromBytes(data[8:18]) - if err != nil { - return err - } - - er.ETag = binary.BigEndian.Uint32(data[18:22]) - - er.IPPrefixLength = data[22] - - offset := 23 // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) - er.IPPrefix = data[offset : offset+addrLen] - offset += addrLen - - er.GWIPAddress = data[offset : offset+addrLen] - offset += addrLen - - if er.Label, err = labelDecode(data[offset : offset+3]); err != nil { - return err - } - // offset += 3 - - return nil -} - -func (er *EVPNIPPrefixRoute) Serialize() ([]byte, error) { - buf := make([]byte, 23) // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) - - if er.RD != nil { - tbuf, err := er.RD.Serialize() - if err != nil { - return nil, err - } - copy(buf[0:8], tbuf) - } - - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - copy(buf[8:18], tbuf) - - binary.BigEndian.PutUint32(buf[18:22], er.ETag) - - buf[22] = er.IPPrefixLength - - if er.IPPrefix == nil { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "IP Prefix is nil") - } else if er.IPPrefix.To4() != nil { - buf = append(buf, er.IPPrefix.To4()...) - if er.GWIPAddress == nil { - // draft-ietf-bess-evpn-prefix-advertisement: IP Prefix Advertisement in EVPN - // The GW IP field SHOULD be zero if it is not used as an Overlay Index. - er.GWIPAddress = net.IPv4zero - } - buf = append(buf, er.GWIPAddress.To4()...) - } else { - buf = append(buf, er.IPPrefix.To16()...) - if er.GWIPAddress == nil { - er.GWIPAddress = net.IPv6zero - } - buf = append(buf, er.GWIPAddress.To16()...) - } - - tbuf, err = labelSerialize(er.Label) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - - return buf, nil -} - -func (er *EVPNIPPrefixRoute) String() string { - // draft-ietf-bess-evpn-prefix-advertisement: IP Prefix Advertisement in EVPN - // 3.1 IP Prefix Route Encoding - // The RD, Eth-Tag ID, IP Prefix Length and IP Prefix will be part of - // the route key used by BGP to compare routes. The rest of the fields - // will not be part of the route key. - return fmt.Sprintf("[type:Prefix][rd:%s][etag:%d][prefix:%s/%d]", er.RD, er.ETag, er.IPPrefix, er.IPPrefixLength) -} - -func (er *EVPNIPPrefixRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - Etag uint32 `json:"etag"` - Prefix string `json:"prefix"` - Gateway string `json:"gateway"` - Label uint32 `json:"label"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - Etag: er.ETag, - Prefix: fmt.Sprintf("%s/%d", er.IPPrefix, er.IPPrefixLength), - Gateway: er.GWIPAddress.String(), - Label: er.Label, - }) -} - -func (er *EVPNIPPrefixRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNIPPrefixRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, ipPrefixLength uint8, ipPrefix string, gateway string, label uint32) *EVPNNLRI { - ip := net.ParseIP(ipPrefix) - gw := net.ParseIP(gateway) - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - gw = gw.To4() - } - return NewEVPNNLRI(EVPN_IP_PREFIX, &EVPNIPPrefixRoute{ - RD: rd, - ESI: esi, - ETag: etag, - IPPrefixLength: ipPrefixLength, - IPPrefix: ip, - GWIPAddress: gw, - Label: label, - }) -} - -type EVPNIPMSIRoute struct { - RD RouteDistinguisherInterface - ETag uint32 - EC ExtendedCommunityInterface -} - -func (er *EVPNIPMSIRoute) Len() int { - // RD(8) + ETag(4) + EC(8) - return 20 -} - -func (er *EVPNIPMSIRoute) DecodeFromBytes(data []byte) error { - - er.RD = GetRouteDistinguisher(data[0:8]) - - data = data[er.RD.Len():] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - - data = data[4:] - ec, err := ParseExtended(data[0:8]) - if err != nil { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Parse extended community interface failed") - } - er.EC = ec - return nil -} - -func (er *EVPNIPMSIRoute) Serialize() ([]byte, error) { - buf := make([]byte, 20) - - if er.RD != nil { - tbuf, err := er.RD.Serialize() - if err != nil { - return nil, err - } - copy(buf[0:8], tbuf) - } - - binary.BigEndian.PutUint32(buf[8:12], er.ETag) - - ec, err := er.EC.Serialize() - if err != nil { - return nil, err - } - - return append(buf, ec...), nil -} - -func (er *EVPNIPMSIRoute) String() string { - ec := "default" - if er.EC != nil { - ec = er.EC.String() - } - return fmt.Sprintf("[type:I-PMSI][rd:%s][etag:%d][EC:%s]", er.RD, er.ETag, ec) -} - -func (er *EVPNIPMSIRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ETag uint32 `json:"etag"` - EC string `json:"ec"` - }{ - RD: er.RD, - ETag: er.ETag, - EC: er.EC.String(), - }) -} - -func (er *EVPNIPMSIRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNIPMSIRoute(rd RouteDistinguisherInterface, etag uint32, ec ExtendedCommunityInterface) *EVPNNLRI { - - return NewEVPNNLRI(EVPN_I_PMSI, &EVPNIPMSIRoute{ - RD: rd, - ETag: etag, - EC: ec, - }) -} - -type EVPNRouteTypeInterface interface { - Len() int - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - String() string - rd() RouteDistinguisherInterface - MarshalJSON() ([]byte, error) -} - -func getEVPNRouteType(t uint8) (EVPNRouteTypeInterface, error) { - switch t { - case EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY: - return &EVPNEthernetAutoDiscoveryRoute{}, nil - case EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT: - return &EVPNMacIPAdvertisementRoute{}, nil - case EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG: - return &EVPNMulticastEthernetTagRoute{}, nil - case EVPN_ETHERNET_SEGMENT_ROUTE: - return &EVPNEthernetSegmentRoute{}, nil - case EVPN_IP_PREFIX: - return &EVPNIPPrefixRoute{}, nil - } - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Unknown EVPN Route type: %d", t)) -} - -const ( - EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY = 1 - EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT = 2 - EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG = 3 - EVPN_ETHERNET_SEGMENT_ROUTE = 4 - EVPN_IP_PREFIX = 5 - EVPN_I_PMSI = 9 -) - -type EVPNNLRI struct { - PrefixDefault - RouteType uint8 - Length uint8 - RouteTypeData EVPNRouteTypeInterface -} - -func (n *EVPNNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if IsAddPathEnabled(true, RF_EVPN, options) { - var err error - data, err = n.decodePathIdentifier(data) - if err != nil { - return err - } - } - if len(data) < 2 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI bytes available") - } - n.RouteType = data[0] - n.Length = data[1] - data = data[2:] - if len(data) < int(n.Length) { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI Route type bytes available") - } - r, err := getEVPNRouteType(n.RouteType) - if err != nil { - return err - } - n.RouteTypeData = r - return n.RouteTypeData.DecodeFromBytes(data[:n.Length]) -} - -func (n *EVPNNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - if IsAddPathEnabled(false, RF_EVPN, options) { - var err error - buf, err = n.serializeIdentifier() - if err != nil { - return nil, err - } - } - offset := len(buf) - buf = append(buf, make([]byte, 2)...) - buf[offset] = n.RouteType - tbuf, err := n.RouteTypeData.Serialize() - buf[offset+1] = n.Length - if err != nil { - return nil, err - } - return append(buf, tbuf...), nil -} - -func (n *EVPNNLRI) AFI() uint16 { - return AFI_L2VPN -} - -func (n *EVPNNLRI) SAFI() uint8 { - return SAFI_EVPN -} - -func (n *EVPNNLRI) Len(options ...*MarshallingOption) int { - return int(n.Length) + 2 -} - -func (n *EVPNNLRI) String() string { - if n.RouteTypeData != nil { - return n.RouteTypeData.String() - } - return strconv.FormatUint(uint64(n.RouteType), 10) + ":" + strconv.FormatUint(uint64(n.Length), 10) -} - -func (n *EVPNNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint8 `json:"type"` - Value EVPNRouteTypeInterface `json:"value"` - }{ - Type: n.RouteType, - Value: n.RouteTypeData, - }) -} - -func (n *EVPNNLRI) RD() RouteDistinguisherInterface { - return n.RouteTypeData.rd() -} - -func NewEVPNNLRI(routeType uint8, routeTypeData EVPNRouteTypeInterface) *EVPNNLRI { - var l uint8 - if routeTypeData != nil { - l = uint8(routeTypeData.Len()) - } - return &EVPNNLRI{ - RouteType: routeType, - Length: l, - RouteTypeData: routeTypeData, - } -} - -type EncapNLRI struct { - IPAddrPrefixDefault - addrlen uint8 -} - -func (n *EncapNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if n.addrlen == 0 { - n.addrlen = 4 - } - f := RF_IPv4_ENCAP - if n.addrlen == 16 { - f = RF_IPv6_ENCAP - } - if IsAddPathEnabled(true, f, options) { - var err error - data, err = n.decodePathIdentifier(data) - if err != nil { - return err - } - } - if len(data) < 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "prefix misses length field") - } - n.Length = data[0] - if n.addrlen == 0 { - n.addrlen = 4 - } - return n.decodePrefix(data[1:], n.Length, n.addrlen) -} - -func (n *EncapNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - f := RF_IPv4_ENCAP - if n.addrlen == 16 { - f = RF_IPv6_ENCAP - } - if IsAddPathEnabled(false, f, options) { - var err error - buf, err = n.serializeIdentifier() - if err != nil { - return nil, err - } - } - if n.Prefix.To4() != nil { - buf = append(buf, net.IPv4len*8) - n.Prefix = n.Prefix.To4() - } else { - buf = append(buf, net.IPv6len*8) - } - n.Length = buf[len(buf)-1] - pbuf, err := n.serializePrefix(n.Length) - if err != nil { - return nil, err - } - return append(buf, pbuf...), nil -} - -func (n *EncapNLRI) String() string { - return n.Prefix.String() -} - -func (n *EncapNLRI) AFI() uint16 { - return AFI_IP -} - -func (n *EncapNLRI) SAFI() uint8 { - return SAFI_ENCAPSULATION -} - -func (n *EncapNLRI) Len(options ...*MarshallingOption) int { - return 1 + len(n.Prefix) -} - -func NewEncapNLRI(endpoint string) *EncapNLRI { - return &EncapNLRI{ - IPAddrPrefixDefault{Length: 32, Prefix: net.ParseIP(endpoint).To4()}, - 4, - } -} - -type Encapv6NLRI struct { - EncapNLRI -} - -func (n *Encapv6NLRI) AFI() uint16 { - return AFI_IP6 -} - -func NewEncapv6NLRI(endpoint string) *Encapv6NLRI { - return &Encapv6NLRI{ - EncapNLRI{ - IPAddrPrefixDefault{Length: 128, Prefix: net.ParseIP(endpoint)}, - 16, - }, - } -} - -type BGPFlowSpecType uint8 - -const ( - FLOW_SPEC_TYPE_UNKNOWN BGPFlowSpecType = iota - FLOW_SPEC_TYPE_DST_PREFIX - FLOW_SPEC_TYPE_SRC_PREFIX - FLOW_SPEC_TYPE_IP_PROTO - FLOW_SPEC_TYPE_PORT - FLOW_SPEC_TYPE_DST_PORT - FLOW_SPEC_TYPE_SRC_PORT - FLOW_SPEC_TYPE_ICMP_TYPE - FLOW_SPEC_TYPE_ICMP_CODE - FLOW_SPEC_TYPE_TCP_FLAG - FLOW_SPEC_TYPE_PKT_LEN - FLOW_SPEC_TYPE_DSCP - FLOW_SPEC_TYPE_FRAGMENT - FLOW_SPEC_TYPE_LABEL - FLOW_SPEC_TYPE_ETHERNET_TYPE // 14 - FLOW_SPEC_TYPE_SRC_MAC - FLOW_SPEC_TYPE_DST_MAC - FLOW_SPEC_TYPE_LLC_DSAP - FLOW_SPEC_TYPE_LLC_SSAP - FLOW_SPEC_TYPE_LLC_CONTROL - FLOW_SPEC_TYPE_SNAP - FLOW_SPEC_TYPE_VID - FLOW_SPEC_TYPE_COS - FLOW_SPEC_TYPE_INNER_VID - FLOW_SPEC_TYPE_INNER_COS -) - -var FlowSpecNameMap = map[BGPFlowSpecType]string{ - FLOW_SPEC_TYPE_UNKNOWN: "unknown", - FLOW_SPEC_TYPE_DST_PREFIX: "destination", - FLOW_SPEC_TYPE_SRC_PREFIX: "source", - FLOW_SPEC_TYPE_IP_PROTO: "protocol", - FLOW_SPEC_TYPE_PORT: "port", - FLOW_SPEC_TYPE_DST_PORT: "destination-port", - FLOW_SPEC_TYPE_SRC_PORT: "source-port", - FLOW_SPEC_TYPE_ICMP_TYPE: "icmp-type", - FLOW_SPEC_TYPE_ICMP_CODE: "icmp-code", - FLOW_SPEC_TYPE_TCP_FLAG: "tcp-flags", - FLOW_SPEC_TYPE_PKT_LEN: "packet-length", - FLOW_SPEC_TYPE_DSCP: "dscp", - FLOW_SPEC_TYPE_FRAGMENT: "fragment", - FLOW_SPEC_TYPE_LABEL: "label", - FLOW_SPEC_TYPE_ETHERNET_TYPE: "ether-type", - FLOW_SPEC_TYPE_SRC_MAC: "source-mac", - FLOW_SPEC_TYPE_DST_MAC: "destination-mac", - FLOW_SPEC_TYPE_LLC_DSAP: "llc-dsap", - FLOW_SPEC_TYPE_LLC_SSAP: "llc-ssap", - FLOW_SPEC_TYPE_LLC_CONTROL: "llc-control", - FLOW_SPEC_TYPE_SNAP: "snap", - FLOW_SPEC_TYPE_VID: "vid", - FLOW_SPEC_TYPE_COS: "cos", - FLOW_SPEC_TYPE_INNER_VID: "inner-vid", - FLOW_SPEC_TYPE_INNER_COS: "inner-cos", -} - -var FlowSpecValueMap = map[string]BGPFlowSpecType{ - FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]: FLOW_SPEC_TYPE_DST_PREFIX, - FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]: FLOW_SPEC_TYPE_SRC_PREFIX, - FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO]: FLOW_SPEC_TYPE_IP_PROTO, - FlowSpecNameMap[FLOW_SPEC_TYPE_PORT]: FLOW_SPEC_TYPE_PORT, - FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PORT]: FLOW_SPEC_TYPE_DST_PORT, - FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PORT]: FLOW_SPEC_TYPE_SRC_PORT, - FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_TYPE]: FLOW_SPEC_TYPE_ICMP_TYPE, - FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_CODE]: FLOW_SPEC_TYPE_ICMP_CODE, - FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG]: FLOW_SPEC_TYPE_TCP_FLAG, - FlowSpecNameMap[FLOW_SPEC_TYPE_PKT_LEN]: FLOW_SPEC_TYPE_PKT_LEN, - FlowSpecNameMap[FLOW_SPEC_TYPE_DSCP]: FLOW_SPEC_TYPE_DSCP, - FlowSpecNameMap[FLOW_SPEC_TYPE_FRAGMENT]: FLOW_SPEC_TYPE_FRAGMENT, - FlowSpecNameMap[FLOW_SPEC_TYPE_LABEL]: FLOW_SPEC_TYPE_LABEL, - FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE]: FLOW_SPEC_TYPE_ETHERNET_TYPE, - FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]: FLOW_SPEC_TYPE_SRC_MAC, - FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]: FLOW_SPEC_TYPE_DST_MAC, - FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_DSAP]: FLOW_SPEC_TYPE_LLC_DSAP, - FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_SSAP]: FLOW_SPEC_TYPE_LLC_SSAP, - FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_CONTROL]: FLOW_SPEC_TYPE_LLC_CONTROL, - FlowSpecNameMap[FLOW_SPEC_TYPE_SNAP]: FLOW_SPEC_TYPE_SNAP, - FlowSpecNameMap[FLOW_SPEC_TYPE_VID]: FLOW_SPEC_TYPE_VID, - FlowSpecNameMap[FLOW_SPEC_TYPE_COS]: FLOW_SPEC_TYPE_COS, - FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_VID]: FLOW_SPEC_TYPE_INNER_VID, - FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_COS]: FLOW_SPEC_TYPE_INNER_COS, -} - -// Joins the given and args into a single string and normalize it. -// Example: -// args := []string{" & <=80", " tcp != udp ", " =! SA & =U! F", " = is-fragment+last-fragment"} -// fmt.Printf("%q", normalizeFlowSpecOpValues(args)) -// >>> ["<=80" "tcp" "!=udp" "=!SA" "&=U" "!F" "=is-fragment+last-fragment"] -func normalizeFlowSpecOpValues(args []string) []string { - // Extracts keywords from the given args. - sub := "" - subs := make([]string, 0) - for _, s := range _regexpFlowSpecOperator.FindAllString(strings.Join(args, " "), -1) { - sub += s - if _regexpFlowSpecOperatorValue.MatchString(s) { - subs = append(subs, sub) - sub = "" - } - } - - // RFC5575 says "It should be unset in the first operator byte of a - // sequence". - if len(subs) > 0 { - subs[0] = strings.TrimPrefix(subs[0], "&") - } - - return subs -} - -// Parses the FlowSpec numeric operator using the given submatch which should be -// the return value of func (*Regexp) FindStringSubmatch. -func parseFlowSpecNumericOperator(submatch []string) (operator uint8, err error) { - if submatch[1] == "&" { - operator = DEC_NUM_OP_AND - } - value, ok := DECNumOpValueMap[submatch[2]] - if !ok { - return 0, fmt.Errorf("invalid numeric operator: %s%s", submatch[1], submatch[2]) - } - operator |= uint8(value) - return operator, nil -} - -// Parses the pairs of operator and value for the FlowSpec numeric type. The -// given validationFunc is applied to evaluate whether the parsed value is -// valid or not (e.g., if exceeds range or not). -// Note: Each of the args should be formatted in single pair of operator and -// value before calling this function. -// e.g.) "&==100", ">=200" or "&<300" -func parseFlowSpecNumericOpValues(typ BGPFlowSpecType, args []string, validationFunc func(uint64) error) (FlowSpecComponentInterface, error) { - argsLen := len(args) - items := make([]*FlowSpecComponentItem, 0, argsLen) - for idx, arg := range args { - m := _regexpFlowSpecNumericType.FindStringSubmatch(arg) - if len(m) < 4 { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } - operator, err := parseFlowSpecNumericOperator(m) - if err != nil { - return nil, err - } - // "true" and "false" is operator, but here handles them as value. - var value uint64 - switch m[3] { - case "true", "false": - if idx != argsLen-1 { - return nil, fmt.Errorf("%s should be the last of each rule", m[3]) - } - operator = uint8(DECNumOpValueMap[m[3]]) - default: - if value, err = strconv.ParseUint(m[3], 10, 64); err != nil { - return nil, fmt.Errorf("invalid numeric value: %s", m[3]) - } - if err = validationFunc(value); err != nil { - return nil, err - } - } - items = append(items, NewFlowSpecComponentItem(operator, value)) - } - - // Marks end-of-list bit - items[argsLen-1].Op |= uint8(DEC_NUM_OP_END) - - return NewFlowSpecComponent(typ, items), nil -} - -func flowSpecNumeric1ByteParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xff { // 1 byte - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecNumeric2BytesParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xffff { // 2 bytes - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -// Parses the FlowSpec bitmask operand using the given submatch which should be -// the return value of func (*Regexp) FindStringSubmatch. -func parseFlowSpecBitmaskOperand(submatch []string) (operand uint8, err error) { - if submatch[1] == "&" { - operand = BITMASK_FLAG_OP_AND - } - value, ok := BitmaskFlagOpValueMap[submatch[2]] - if !ok { - return 0, fmt.Errorf("invalid bitmask operand: %s%s", submatch[1], submatch[2]) - } - operand |= uint8(value) - return operand, nil -} - -func flowSpecPrefixParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args[0]: IP Prefix or IP Address (suppose prefix length is 32) - // args[1]: Offset in bit (IPv6 only) - // - // Example: - // - IPv4 Prefix - // args := []string{"192.168.0.0/24"} - // - IPv4 Address - // args := []string{"192.168.0.1"} - // - IPv6 Prefix - // args := []string{"2001:db8:1::/64"} - // - IPv6 Prefix with offset - // args := []string{"0:db8:1::/64/16"} - // args := []string{"0:db8:1::/64", "16"} - // - IPv6 Address - // args := []string{"2001:db8:1::1"} - // - IPv6 Address with offset - // args := []string{"0:db8:1::1", "16"} - afi, _ := RouteFamilyToAfiSafi(rf) - switch afi { - case AFI_IP: - if len(args) > 1 { - return nil, errors.New("cannot specify offset for ipv4 prefix") - } - invalidIPv4PrefixError := fmt.Errorf("invalid ipv4 prefix: %s", args[0]) - m := _regexpFindIPv4Prefix.FindStringSubmatch(args[0]) - if len(m) < 4 { - return nil, invalidIPv4PrefixError - } - prefix := net.ParseIP(m[1]) - if prefix.To4() == nil { - return nil, invalidIPv4PrefixError - } - var prefixLen uint64 = 32 - if m[3] != "" { - var err error - prefixLen, err = strconv.ParseUint(m[3], 10, 8) - if err != nil || prefixLen > 32 { - return nil, invalidIPv4PrefixError - } - } - switch typ { - case FLOW_SPEC_TYPE_DST_PREFIX: - return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil - case FLOW_SPEC_TYPE_SRC_PREFIX: - return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil - } - return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) - case AFI_IP6: - if len(args) > 2 { - return nil, fmt.Errorf("invalid arguments for ipv6 prefix: %q", args) - } - invalidIPv6PrefixError := fmt.Errorf("invalid ipv6 prefix: %s", args[0]) - m := _regexpFindIPv6Prefix.FindStringSubmatch(args[0]) - if len(m) < 4 { - return nil, invalidIPv6PrefixError - } - prefix := net.ParseIP(m[1]) - if prefix.To16() == nil { - return nil, invalidIPv6PrefixError - } - var prefixLen uint64 = 128 - if m[3] != "" { - var err error - prefixLen, err = strconv.ParseUint(m[3], 10, 8) - if err != nil || prefixLen > 128 { - return nil, invalidIPv6PrefixError - } - } - var offset uint64 - if len(args) == 1 && m[5] != "" { - var err error - offset, err = strconv.ParseUint(m[5], 10, 8) - if err != nil || offset > 128 { - return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", m[5]) - } - } else if len(args) == 2 { - if m[5] != "" { - return nil, fmt.Errorf("multiple ipv6 prefix offset arguments detected: %q", args) - } - var err error - offset, err = strconv.ParseUint(args[1], 10, 8) - if err != nil || offset > 128 { - return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", args[1]) - } - } - switch typ { - case FLOW_SPEC_TYPE_DST_PREFIX: - return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil - case FLOW_SPEC_TYPE_SRC_PREFIX: - return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil - } - return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) - } - return nil, fmt.Errorf("invalid address family: %s", rf.String()) -} - -func flowSpecIpProtoParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operator and IP protocol type - // - // Example: - // - TCP or UDP - // args := []string{"tcp", "==udp"} - // - Not TCP and not UDP - // args := []string{"!=tcp", "&!=udp"} - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range ProtocolNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 0xff { // 1 byte - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecTcpFlagParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operand and TCP Flags - // - // Example: - // - SYN or SYN/ACK - // args := []string{"==S", "==SA"} - // - Not FIN and not URG - // args := []string{"!=F", "&!=U"} - args = normalizeFlowSpecOpValues(args) - - argsLen := len(args) - items := make([]*FlowSpecComponentItem, 0, argsLen) - - for _, arg := range args { - m := _regexpFlowSpecTCPFlag.FindStringSubmatch(arg) - if len(m) < 6 { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } else if mLast := m[len(m)-1]; mLast != "" || m[3] != "" { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } - operand, err := parseFlowSpecBitmaskOperand(m) - if err != nil { - return nil, err - } - var value uint64 - for flag, name := range TCPFlagNameMap { - if strings.Contains(m[4], name) { - value |= uint64(flag) - } - } - items = append(items, NewFlowSpecComponentItem(operand, value)) - } - - // Marks end-of-list bit - items[argsLen-1].Op |= BITMASK_FLAG_OP_END - - return NewFlowSpecComponent(typ, items), nil -} - -func flowSpecDscpParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i < 64 { // 6 bits - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecFragmentParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operator and Fragment flags - // - // Example: - // - is-fragment or last-fragment - // args := []string{"==is-fragment", "==last-fragment"} - // - is-fragment and last-fragment (exact match) - // args := []string{"==is-fragment+last-fragment"} - args = normalizeFlowSpecOpValues(args) - - argsLen := len(args) - items := make([]*FlowSpecComponentItem, 0, argsLen) - - for _, arg := range args { - m := _regexpFlowSpecFragment.FindStringSubmatch(arg) - if len(m) < 4 { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } else if mLast := m[len(m)-1]; mLast != "" { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } - operand, err := parseFlowSpecBitmaskOperand(m) - if err != nil { - return nil, err - } - var value uint64 - // Example: - // m[3] = "first-fragment+last-fragment" - for flag, name := range FragmentFlagNameMap { - if strings.Contains(m[3], name) { - value |= uint64(flag) - } - } - items = append(items, NewFlowSpecComponentItem(operand, value)) - } - - // Marks end-of-list bit - items[argsLen-1].Op |= BITMASK_FLAG_OP_END - - return NewFlowSpecComponent(typ, items), nil -} - -func flowSpecLabelParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - afi, _ := RouteFamilyToAfiSafi(rf) - if afi == AFI_IP { - return nil, fmt.Errorf("%s is not supported for ipv4", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xfffff { // 20 bits - return nil - } - return errors.New("flow label range exceeded") - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecEtherTypeParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operator and Ether Types - // - // Example: - // - ARP or IPv4 - // args := []string{"==arp", "==ipv4"} - // - Not IPv4 and not IPv6 - // args := []string{"!=ipv4", "&!=ipv6"} - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range EthernetTypeNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 0xffff { // 2 bytes - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecMacParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args[0]: MAC address - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - mac, err := net.ParseMAC(args[0]) - if err != nil { - return nil, fmt.Errorf("invalid mac address: %s", args[0]) - } - - switch typ { - case FLOW_SPEC_TYPE_DST_MAC: - return NewFlowSpecDestinationMac(mac), nil - case FLOW_SPEC_TYPE_SRC_MAC: - return NewFlowSpecSourceMac(mac), nil - } - return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) -} - -func flowSpecLlcParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - return flowSpecNumeric1ByteParser(rf, typ, args) -} - -func flowSpecSnapParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xffffffffff { // 5 bytes - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecVlanIDParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range EthernetTypeNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 4095 { // 12 bits - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecVlanCosParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range EthernetTypeNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 7 { // 3 bits - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, BGPFlowSpecType, []string) (FlowSpecComponentInterface, error){ - FLOW_SPEC_TYPE_DST_PREFIX: flowSpecPrefixParser, - FLOW_SPEC_TYPE_SRC_PREFIX: flowSpecPrefixParser, - FLOW_SPEC_TYPE_IP_PROTO: flowSpecIpProtoParser, - FLOW_SPEC_TYPE_PORT: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_DST_PORT: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_SRC_PORT: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_ICMP_TYPE: flowSpecNumeric1ByteParser, - FLOW_SPEC_TYPE_ICMP_CODE: flowSpecNumeric1ByteParser, - FLOW_SPEC_TYPE_TCP_FLAG: flowSpecTcpFlagParser, - FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_DSCP: flowSpecDscpParser, - FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser, - FLOW_SPEC_TYPE_LABEL: flowSpecLabelParser, - FLOW_SPEC_TYPE_ETHERNET_TYPE: flowSpecEtherTypeParser, - FLOW_SPEC_TYPE_DST_MAC: flowSpecMacParser, - FLOW_SPEC_TYPE_SRC_MAC: flowSpecMacParser, - FLOW_SPEC_TYPE_LLC_DSAP: flowSpecLlcParser, - FLOW_SPEC_TYPE_LLC_SSAP: flowSpecLlcParser, - FLOW_SPEC_TYPE_LLC_CONTROL: flowSpecLlcParser, - FLOW_SPEC_TYPE_SNAP: flowSpecSnapParser, - FLOW_SPEC_TYPE_VID: flowSpecVlanIDParser, - FLOW_SPEC_TYPE_COS: flowSpecVlanCosParser, - FLOW_SPEC_TYPE_INNER_VID: flowSpecVlanIDParser, - FLOW_SPEC_TYPE_INNER_COS: flowSpecVlanCosParser, -} - -func extractFlowSpecArgs(args []string) map[BGPFlowSpecType][]string { - m := make(map[BGPFlowSpecType][]string, len(FlowSpecValueMap)) - var typ BGPFlowSpecType - for _, arg := range args { - if t, ok := FlowSpecValueMap[arg]; ok { - typ = t - m[typ] = make([]string, 0) - } else { - m[typ] = append(m[typ], arg) - } - } - return m -} - -func ParseFlowSpecComponents(rf RouteFamily, arg string) ([]FlowSpecComponentInterface, error) { - _, safi := RouteFamilyToAfiSafi(rf) - switch safi { - case SAFI_FLOW_SPEC_UNICAST, SAFI_FLOW_SPEC_VPN: - // Valid - default: - return nil, fmt.Errorf("invalid address family: %s", rf.String()) - } - - typeArgs := extractFlowSpecArgs(strings.Split(arg, " ")) - rules := make([]FlowSpecComponentInterface, 0, len(typeArgs)) - for typ, args := range typeArgs { - parser, ok := flowSpecParserMap[typ] - if !ok { - return nil, fmt.Errorf("unsupported traffic filtering rule type: %s", typ.String()) - } - if len(args) == 0 { - return nil, fmt.Errorf("specify traffic filtering rules for %s", typ.String()) - } - rule, err := parser(rf, typ, args) - if err != nil { - return nil, err - } - rules = append(rules, rule) - } - return rules, nil -} - -func (t BGPFlowSpecType) String() string { - name, ok := FlowSpecNameMap[t] - if !ok { - return fmt.Sprintf("%s(%d)", FlowSpecNameMap[FLOW_SPEC_TYPE_UNKNOWN], t) - } - return name -} - -type FlowSpecComponentInterface interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) - Len(...*MarshallingOption) int - Type() BGPFlowSpecType - String() string -} - -type flowSpecPrefix struct { - Prefix AddrPrefixInterface - typ BGPFlowSpecType -} - -func (p *flowSpecPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.typ = BGPFlowSpecType(data[0]) - return p.Prefix.DecodeFromBytes(data[1:], options...) -} - -func (p *flowSpecPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - bbuf, err := p.Prefix.Serialize(options...) - if err != nil { - return nil, err - } - buf := make([]byte, 1+len(bbuf)) - buf[0] = byte(p.Type()) - copy(buf[1:], bbuf) - return buf, nil -} - -func (p *flowSpecPrefix) Len(options ...*MarshallingOption) int { - buf, _ := p.Serialize(options...) - return len(buf) -} - -func (p *flowSpecPrefix) Type() BGPFlowSpecType { - return p.typ -} - -func (p *flowSpecPrefix) String() string { - return fmt.Sprintf("[%s: %s]", p.Type(), p.Prefix.String()) -} - -func (p *flowSpecPrefix) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value AddrPrefixInterface `json:"value"` - }{ - Type: p.Type(), - Value: p.Prefix, - }) -} - -type flowSpecPrefix6 struct { - Prefix AddrPrefixInterface - Offset uint8 - typ BGPFlowSpecType -} - -// draft-ietf-idr-flow-spec-v6-06 -// -func (p *flowSpecPrefix6) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.typ = BGPFlowSpecType(data[0]) - p.Offset = data[2] - prefix := append([]byte{data[1]}, data[3:]...) - return p.Prefix.DecodeFromBytes(prefix, options...) -} - -func (p *flowSpecPrefix6) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{byte(p.Type())} - bbuf, err := p.Prefix.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, bbuf[0]) - buf = append(buf, p.Offset) - return append(buf, bbuf[1:]...), nil -} - -func (p *flowSpecPrefix6) Len(options ...*MarshallingOption) int { - buf, _ := p.Serialize(options...) - return len(buf) -} - -func (p *flowSpecPrefix6) Type() BGPFlowSpecType { - return p.typ -} - -func (p *flowSpecPrefix6) String() string { - return fmt.Sprintf("[%s: %s/%d]", p.Type(), p.Prefix.String(), p.Offset) -} - -func (p *flowSpecPrefix6) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value AddrPrefixInterface `json:"value"` - Offset uint8 `json:"offset"` - }{ - Type: p.Type(), - Value: p.Prefix, - Offset: p.Offset, - }) -} - -type FlowSpecDestinationPrefix struct { - flowSpecPrefix -} - -func NewFlowSpecDestinationPrefix(prefix AddrPrefixInterface) *FlowSpecDestinationPrefix { - return &FlowSpecDestinationPrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_DST_PREFIX}} -} - -type FlowSpecSourcePrefix struct { - flowSpecPrefix -} - -func NewFlowSpecSourcePrefix(prefix AddrPrefixInterface) *FlowSpecSourcePrefix { - return &FlowSpecSourcePrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_SRC_PREFIX}} -} - -type FlowSpecDestinationPrefix6 struct { - flowSpecPrefix6 -} - -func NewFlowSpecDestinationPrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecDestinationPrefix6 { - return &FlowSpecDestinationPrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_DST_PREFIX}} -} - -type FlowSpecSourcePrefix6 struct { - flowSpecPrefix6 -} - -func NewFlowSpecSourcePrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecSourcePrefix6 { - return &FlowSpecSourcePrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_SRC_PREFIX}} -} - -type flowSpecMac struct { - Mac net.HardwareAddr - typ BGPFlowSpecType -} - -func (p *flowSpecMac) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if len(data) < 2 || len(data) < 2+int(data[1]) { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all mac bits available") - } - p.typ = BGPFlowSpecType(data[0]) - p.Mac = net.HardwareAddr(data[2 : 2+int(data[1])]) - return nil -} - -func (p *flowSpecMac) Serialize(options ...*MarshallingOption) ([]byte, error) { - if len(p.Mac) == 0 { - return nil, errors.New("mac unset") - } - buf := make([]byte, 2+len(p.Mac)) - buf[0] = byte(p.Type()) - buf[1] = byte(len(p.Mac)) - copy(buf[2:], p.Mac) - return buf, nil -} - -func (p *flowSpecMac) Len(options ...*MarshallingOption) int { - return 2 + len(p.Mac) -} - -func (p *flowSpecMac) Type() BGPFlowSpecType { - return p.typ -} - -func (p *flowSpecMac) String() string { - return fmt.Sprintf("[%s: %s]", p.Type(), p.Mac.String()) -} - -func (p *flowSpecMac) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value string `json:"value"` - }{ - Type: p.Type(), - Value: p.Mac.String(), - }) -} - -type FlowSpecSourceMac struct { - flowSpecMac -} - -func NewFlowSpecSourceMac(mac net.HardwareAddr) *FlowSpecSourceMac { - return &FlowSpecSourceMac{flowSpecMac{Mac: mac, typ: FLOW_SPEC_TYPE_SRC_MAC}} -} - -type FlowSpecDestinationMac struct { - flowSpecMac -} - -func NewFlowSpecDestinationMac(mac net.HardwareAddr) *FlowSpecDestinationMac { - return &FlowSpecDestinationMac{flowSpecMac{Mac: mac, typ: FLOW_SPEC_TYPE_DST_MAC}} -} - -type FlowSpecComponentItem struct { - Op uint8 `json:"op"` - Value uint64 `json:"value"` -} - -func (v *FlowSpecComponentItem) Len() int { - return 1 << ((uint32(v.Op) >> 4) & 0x3) -} - -func (v *FlowSpecComponentItem) Serialize() ([]byte, error) { - order := uint32(math.Log2(float64(v.Len()))) - buf := make([]byte, 1+(1<> 4) & 0x3) // (min, max) = (1, 8) - v := make([]byte, 8) - copy(v[8-l:], data[1:1+l]) - i := binary.BigEndian.Uint64(v) - item := &FlowSpecComponentItem{op, i} - p.Items = append(p.Items, item) - if end > 0 { - break - } - data = data[1+l:] - } - return nil -} - -func (p *FlowSpecComponent) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{byte(p.Type())} - for _, v := range p.Items { - bbuf, err := v.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return buf, nil -} - -func (p *FlowSpecComponent) Len(options ...*MarshallingOption) int { - l := 1 - for _, item := range p.Items { - l += item.Len() + 1 - } - return l -} - -func (p *FlowSpecComponent) Type() BGPFlowSpecType { - return p.typ -} - -func formatRaw(op uint8, value uint64) string { - return fmt.Sprintf("op:%b,value:%d", op, value) -} - -func formatNumeric(op uint8, value uint64) string { - cmpFlag := DECNumOp(op & 0x7) // lower 3 bits - if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE { - // Omit value field - return DECNumOp(op).String() - } - return DECNumOp(op).String() + strconv.FormatUint(value, 10) -} - -func formatProto(op uint8, value uint64) string { - cmpFlag := DECNumOp(op & 0x7) // lower 3 bits - if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE { - // Omit value field - return DECNumOp(op).String() - } - return DECNumOp(op).String() + Protocol(value).String() -} - -func formatTCPFlag(op uint8, value uint64) string { - return BitmaskFlagOp(op).String() + TCPFlag(value).String() -} - -func formatFragment(op uint8, value uint64) string { - return BitmaskFlagOp(op).String() + FragmentFlag(value).String() -} - -func formatEtherType(op uint8, value uint64) string { - cmpFlag := DECNumOp(op & 0x7) // lower 3 bits - if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE { - // Omit value field - return DECNumOp(op).String() - } - return DECNumOp(op).String() + EthernetType(value).String() -} - -var flowSpecFormatMap = map[BGPFlowSpecType]func(op uint8, value uint64) string{ - FLOW_SPEC_TYPE_UNKNOWN: formatRaw, - FLOW_SPEC_TYPE_IP_PROTO: formatProto, - FLOW_SPEC_TYPE_PORT: formatNumeric, - FLOW_SPEC_TYPE_DST_PORT: formatNumeric, - FLOW_SPEC_TYPE_SRC_PORT: formatNumeric, - FLOW_SPEC_TYPE_ICMP_TYPE: formatNumeric, - FLOW_SPEC_TYPE_ICMP_CODE: formatNumeric, - FLOW_SPEC_TYPE_TCP_FLAG: formatTCPFlag, - FLOW_SPEC_TYPE_PKT_LEN: formatNumeric, - FLOW_SPEC_TYPE_DSCP: formatNumeric, - FLOW_SPEC_TYPE_FRAGMENT: formatFragment, - FLOW_SPEC_TYPE_LABEL: formatNumeric, - FLOW_SPEC_TYPE_ETHERNET_TYPE: formatEtherType, - FLOW_SPEC_TYPE_LLC_DSAP: formatNumeric, - FLOW_SPEC_TYPE_LLC_SSAP: formatNumeric, - FLOW_SPEC_TYPE_LLC_CONTROL: formatNumeric, - FLOW_SPEC_TYPE_SNAP: formatNumeric, - FLOW_SPEC_TYPE_VID: formatNumeric, - FLOW_SPEC_TYPE_COS: formatNumeric, - FLOW_SPEC_TYPE_INNER_VID: formatNumeric, - FLOW_SPEC_TYPE_INNER_COS: formatNumeric, -} - -func (p *FlowSpecComponent) String() string { - f := flowSpecFormatMap[FLOW_SPEC_TYPE_UNKNOWN] - if _, ok := flowSpecFormatMap[p.typ]; ok { - f = flowSpecFormatMap[p.typ] - } - - items := make([]string, 0, len(p.Items)) - for _, i := range p.Items { - items = append(items, f(i.Op, i.Value)) - } - // Removes leading and tailing spaces - value := strings.TrimSpace(strings.Join(items, "")) - - return fmt.Sprintf("[%s: %s]", p.typ, value) -} - -func (p *FlowSpecComponent) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value []*FlowSpecComponentItem `json:"value"` - }{ - Type: p.Type(), - Value: p.Items, - }) -} - -func NewFlowSpecComponent(typ BGPFlowSpecType, items []*FlowSpecComponentItem) *FlowSpecComponent { - // Set end-of-list bit on the last item and unset them on the others. - for i, v := range items { - if i == len(items)-1 { - v.Op |= 0x80 - } else { - v.Op &^= 0x80 - } - - } - return &FlowSpecComponent{ - Items: items, - typ: typ, - } -} - -type FlowSpecUnknown struct { - Value []byte -} - -func (p *FlowSpecUnknown) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.Value = data - return nil -} - -func (p *FlowSpecUnknown) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.Value, nil -} - -func (p *FlowSpecUnknown) Len(options ...*MarshallingOption) int { - return len(p.Value) -} - -func (p *FlowSpecUnknown) Type() BGPFlowSpecType { - if len(p.Value) > 0 { - return BGPFlowSpecType(p.Value[0]) - } - return FLOW_SPEC_TYPE_UNKNOWN -} - -func (p *FlowSpecUnknown) String() string { - return fmt.Sprintf("[unknown:%v]", p.Value) -} - -func (p *FlowSpecUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value string `json:"value"` - }{ - Type: p.Type(), - Value: string(p.Value), - }) -} - -type FlowSpecNLRI struct { - PrefixDefault - Value []FlowSpecComponentInterface - rf RouteFamily - rd RouteDistinguisherInterface -} - -func (n *FlowSpecNLRI) AFI() uint16 { - afi, _ := RouteFamilyToAfiSafi(n.rf) - return afi -} - -func (n *FlowSpecNLRI) SAFI() uint8 { - _, safi := RouteFamilyToAfiSafi(n.rf) - return safi -} - -func (n *FlowSpecNLRI) RD() RouteDistinguisherInterface { - return n.rd -} - -func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...*MarshallingOption) error { - if IsAddPathEnabled(true, rf, options) { - var err error - data, err = n.decodePathIdentifier(data) - if err != nil { - return err - } - } - var length int - if (data[0]>>4) == 0xf && len(data) > 2 { - length = int(binary.BigEndian.Uint16(data[0:2])) - data = data[2:] - } else if len(data) > 1 { - length = int(data[0]) - data = data[1:] - } else { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - if len(data) < length { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - - n.rf = rf - - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - if length < 8 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - n.rd = GetRouteDistinguisher(data[:8]) - data = data[8:] - length -= 8 - } - - for l := length; l > 0; { - if len(data) == 0 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - t := BGPFlowSpecType(data[0]) - var i FlowSpecComponentInterface - switch t { - case FLOW_SPEC_TYPE_DST_PREFIX: - switch { - case rf>>16 == AFI_IP: - i = NewFlowSpecDestinationPrefix(NewIPAddrPrefix(0, "")) - case rf>>16 == AFI_IP6: - i = NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(0, ""), 0) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_SRC_PREFIX: - switch { - case rf>>16 == AFI_IP: - i = NewFlowSpecSourcePrefix(NewIPAddrPrefix(0, "")) - case rf>>16 == AFI_IP6: - i = NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(0, ""), 0) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_SRC_MAC: - switch rf { - case RF_FS_L2_VPN: - i = NewFlowSpecSourceMac(nil) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_DST_MAC: - switch rf { - case RF_FS_L2_VPN: - i = NewFlowSpecDestinationMac(nil) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_IP_PROTO, FLOW_SPEC_TYPE_PORT, FLOW_SPEC_TYPE_DST_PORT, FLOW_SPEC_TYPE_SRC_PORT, - FLOW_SPEC_TYPE_ICMP_TYPE, FLOW_SPEC_TYPE_ICMP_CODE, FLOW_SPEC_TYPE_TCP_FLAG, FLOW_SPEC_TYPE_PKT_LEN, - FLOW_SPEC_TYPE_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL, FLOW_SPEC_TYPE_ETHERNET_TYPE, - FLOW_SPEC_TYPE_LLC_DSAP, FLOW_SPEC_TYPE_LLC_SSAP, FLOW_SPEC_TYPE_LLC_CONTROL, FLOW_SPEC_TYPE_SNAP, - FLOW_SPEC_TYPE_VID, FLOW_SPEC_TYPE_COS, FLOW_SPEC_TYPE_INNER_VID, FLOW_SPEC_TYPE_INNER_COS: - i = NewFlowSpecComponent(t, nil) - default: - i = &FlowSpecUnknown{} - } - - err := i.DecodeFromBytes(data, options...) - if err != nil { - i = &FlowSpecUnknown{data} - } - l -= i.Len(options...) - data = data[i.Len(options...):] - n.Value = append(n.Value, i) - } - - // Sort Traffic Filtering Rules in types order to avoid the unordered rules - // are determined different. - sort.SliceStable(n.Value, func(i, j int) bool { return n.Value[i].Type() < n.Value[j].Type() }) - - return nil -} - -func (n *FlowSpecNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0, 32) - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - if n.rd == nil { - return nil, errors.New("RD is nil") - } - b, err := n.rd.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, b...) - } - for _, v := range n.Value { - b, err := v.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, b...) - } - length := n.Len(options...) - if length > 0xfff { - return nil, fmt.Errorf("too large: %d", length) - } else if length < 0xf0 { - length -= 1 - buf = append([]byte{byte(length)}, buf...) - } else { - length -= 2 - b := make([]byte, 2) - binary.BigEndian.PutUint16(buf, uint16(length)) - buf = append(b, buf...) - } - - if IsAddPathEnabled(false, n.rf, options) { - id, err := n.serializeIdentifier() - if err != nil { - return nil, err - } - return append(id, buf...), nil - } - return buf, nil -} - -func (n *FlowSpecNLRI) Len(options ...*MarshallingOption) int { - l := 0 - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - l += n.RD().Len() - } - for _, v := range n.Value { - l += v.Len(options...) - } - if l < 0xf0 { - return l + 1 - } else { - return l + 2 - } -} - -func (n *FlowSpecNLRI) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - buf.WriteString("[rd: ") - buf.WriteString(n.rd.String()) - buf.WriteString("]") - } - for _, v := range n.Value { - buf.WriteString(v.String()) - } - return buf.String() -} - -func (n *FlowSpecNLRI) MarshalJSON() ([]byte, error) { - if n.rd != nil { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - Value []FlowSpecComponentInterface `json:"value"` - }{ - RD: n.rd, - Value: n.Value, - }) - } - return json.Marshal(struct { - Value []FlowSpecComponentInterface `json:"value"` - }{ - Value: n.Value, - }) - -} - -// CompareFlowSpecNLRI(n, m) returns -// -1 when m has precedence -// -// 0 when n and m have same precedence -// 1 when n has precedence -func CompareFlowSpecNLRI(n, m *FlowSpecNLRI) (int, error) { - family := AfiSafiToRouteFamily(n.AFI(), n.SAFI()) - if family != AfiSafiToRouteFamily(m.AFI(), m.SAFI()) { - return 0, errors.New("address family mismatch") - } - longer := n.Value - shorter := m.Value - invert := 1 - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - k, _ := n.Serialize() - l, _ := m.Serialize() - if result := bytes.Compare(k, l); result != 0 { - return result, nil - } - } - if len(n.Value) < len(m.Value) { - longer = m.Value - shorter = n.Value - invert = -1 - } - for idx, v := range longer { - if len(shorter) < idx+1 { - return invert, nil - } - w := shorter[idx] - if v.Type() < w.Type() { - return invert, nil - } else if v.Type() > w.Type() { - return invert * -1, nil - } else if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX || v.Type() == FLOW_SPEC_TYPE_SRC_PREFIX { - // RFC5575 5.1 - // - // For IP prefix values (IP destination and source prefix) precedence is - // given to the lowest IP value of the common prefix length; if the - // common prefix is equal, then the most specific prefix has precedence. - var p, q *IPAddrPrefixDefault - var pCommon, qCommon uint64 - if n.AFI() == AFI_IP { - if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX { - p = &v.(*FlowSpecDestinationPrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecDestinationPrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - } else { - p = &v.(*FlowSpecSourcePrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecSourcePrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - } - min := p.Length - if q.Length < p.Length { - min = q.Length - } - pCommon = uint64(binary.BigEndian.Uint32([]byte(p.Prefix.To4())) >> (32 - min)) - qCommon = uint64(binary.BigEndian.Uint32([]byte(q.Prefix.To4())) >> (32 - min)) - } else if n.AFI() == AFI_IP6 { - if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX { - p = &v.(*FlowSpecDestinationPrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecDestinationPrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - } else { - p = &v.(*FlowSpecSourcePrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecSourcePrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - } - min := uint(p.Length) - if q.Length < p.Length { - min = uint(q.Length) - } - var mask uint - if min-64 > 0 { - mask = min - 64 - } - pCommon = binary.BigEndian.Uint64([]byte(p.Prefix.To16()[:8])) >> mask - qCommon = binary.BigEndian.Uint64([]byte(q.Prefix.To16()[:8])) >> mask - if pCommon == qCommon && mask == 0 { - mask = 64 - min - pCommon = binary.BigEndian.Uint64([]byte(p.Prefix.To16()[8:])) >> mask - qCommon = binary.BigEndian.Uint64([]byte(q.Prefix.To16()[8:])) >> mask - } - } - - if pCommon < qCommon { - return invert, nil - } else if pCommon > qCommon { - return invert * -1, nil - } else if p.Length > q.Length { - return invert, nil - } else if p.Length < q.Length { - return invert * -1, nil - } - - } else { - // RFC5575 5.1 - // - // For all other component types, unless otherwise specified, the - // comparison is performed by comparing the component data as a binary - // string using the memcmp() function as defined by the ISO C standard. - // For strings of different lengths, the common prefix is compared. If - // equal, the longest string is considered to have higher precedence - // than the shorter one. - p, _ := v.Serialize() - q, _ := w.Serialize() - min := len(p) - if len(q) < len(p) { - min = len(q) - } - if result := bytes.Compare(p[:min], q[:min]); result < 0 { - return invert, nil - } else if result > 0 { - return invert * -1, nil - } else if len(p) > len(q) { - return invert, nil - } else if len(q) > len(p) { - return invert * -1, nil - } - } - } - return 0, nil -} - -type FlowSpecIPv4Unicast struct { - FlowSpecNLRI -} - -func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) -} - -func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv4Unicast{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv4_UC, - }, - } -} - -type FlowSpecIPv4VPN struct { - FlowSpecNLRI -} - -func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) -} - -func NewFlowSpecIPv4VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv4VPN { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv4VPN{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv4_VPN, - rd: rd, - }, - } -} - -type FlowSpecIPv6Unicast struct { - FlowSpecNLRI -} - -func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) -} - -func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv6Unicast{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv6_UC, - }, - } -} - -type FlowSpecIPv6VPN struct { - FlowSpecNLRI -} - -func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) -} - -func NewFlowSpecIPv6VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv6VPN { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv6VPN{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv6_VPN, - rd: rd, - }, - } -} - -type FlowSpecL2VPN struct { - FlowSpecNLRI -} - -func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) -} - -func NewFlowSpecL2VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecL2VPN { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecL2VPN{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_L2_VPN, - rd: rd, - }, - } -} - -type OpaqueNLRI struct { - PrefixDefault - Length uint16 - Key []byte - Value []byte -} - -func (n *OpaqueNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if len(data) < 2 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available") - } - if IsAddPathEnabled(true, RF_OPAQUE, options) { - var err error - data, err = n.decodePathIdentifier(data) - if err != nil { - return err - } - } - n.Length = binary.BigEndian.Uint16(data[0:2]) - if len(data)-2 < int(n.Length) { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available") - } - n.Key = data[2 : 2+n.Length] - n.Value = data[2+n.Length:] - return nil -} - -func (n *OpaqueNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - keyLen := len(n.Key) - if keyLen > math.MaxUint16 { - return nil, errors.New("key length too big") - } - buf := make([]byte, 2, 2+keyLen+len(n.Value)) - binary.BigEndian.PutUint16(buf[:2], uint16(keyLen)) - buf = append(buf, n.Key...) - buf = append(buf, n.Value...) - if IsAddPathEnabled(false, RF_OPAQUE, options) { - id, err := n.serializeIdentifier() - if err != nil { - return nil, err - } - return append(id, buf...), nil - } - return buf, nil -} - -func (n *OpaqueNLRI) AFI() uint16 { - return AFI_OPAQUE -} - -func (n *OpaqueNLRI) SAFI() uint8 { - return SAFI_KEY_VALUE -} - -func (n *OpaqueNLRI) Len(options ...*MarshallingOption) int { - return 2 + len(n.Key) + len(n.Value) -} - -func (n *OpaqueNLRI) String() string { - return string(n.Key) -} - -func (n *OpaqueNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Key string `json:"key"` - Value string `json:"value"` - }{ - Key: string(n.Key), - Value: string(n.Value), - }) -} - -func NewOpaqueNLRI(key, value []byte) *OpaqueNLRI { - return &OpaqueNLRI{ - Key: key, - Value: value, - } -} - -type LsNLRIType uint16 - -const ( - LS_NLRI_TYPE_UNKNOWN LsNLRIType = iota - LS_NLRI_TYPE_NODE - LS_NLRI_TYPE_LINK - LS_NLRI_TYPE_PREFIX_IPV4 - LS_NLRI_TYPE_PREFIX_IPV6 - LS_NLRI_TYPE_SR_POLICY_CANDIDATE_PATH - LS_NLRI_TYPE_SRV6_SID -) - -type LsNLRIInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int - Type() LsNLRIType - String() string -} - -type LsProtocolID uint8 - -const ( - LS_PROTOCOL_UNKNOWN = iota - LS_PROTOCOL_ISIS_L1 - LS_PROTOCOL_ISIS_L2 - LS_PROTOCOL_OSPF_V2 - LS_PROTOCOL_DIRECT - LS_PROTOCOL_STATIC - LS_PROTOCOL_OSPF_V3 - LS_PROTOCOL_BGP -) - -func (l LsProtocolID) String() string { - switch l { - case LS_PROTOCOL_ISIS_L1: - return "ISIS-L1" - case LS_PROTOCOL_ISIS_L2: - return "ISIS-L2" - case LS_PROTOCOL_OSPF_V2: - return "OSPFv2" - case LS_PROTOCOL_DIRECT: - return "DIRECT" - case LS_PROTOCOL_STATIC: - return "STATIC" - case LS_PROTOCOL_OSPF_V3: - return "OSPFv3" - case LS_PROTOCOL_BGP: - return "BGP" - default: - return fmt.Sprintf("LsProtocolID(%d)", uint8(l)) - } -} - -type LsNLRI struct { - NLRIType LsNLRIType - Length uint16 - ProtocolID LsProtocolID - Identifier uint64 -} - -const lsNLRIHdrLen = 9 - -func (l *LsNLRI) DecodeFromBytes(data []byte) error { - if len(data) < lsNLRIHdrLen { - return malformedAttrListErr("Malformed NLRI") - } - - l.ProtocolID = LsProtocolID(data[0]) - l.Identifier = binary.BigEndian.Uint64(data[1:lsNLRIHdrLen]) - - return nil -} - -func (l *LsNLRI) Serialize(value []byte) ([]byte, error) { - buf := make([]byte, lsNLRIHdrLen) - buf[0] = uint8(l.ProtocolID) - binary.BigEndian.PutUint64(buf[1:], l.Identifier) - buf = append(buf, value...) - - return buf, nil -} - -func (l *LsNLRI) Len() int { - return int(l.Length) -} - -func (l *LsNLRI) Type() LsNLRIType { - return l.NLRIType -} - -type LsNodeNLRI struct { - LsNLRI - LocalNodeDesc LsTLVInterface -} - -func (l *LsNodeNLRI) DecodeFromBytes(data []byte) error { - if err := l.LsNLRI.DecodeFromBytes(data); err != nil { - return nil - } - - tlv := data[lsNLRIHdrLen:] - if len(tlv) < tlvHdrLen { - return malformedAttrListErr("Malformed Node NLRI") - } - - tlvType := LsTLVType(binary.BigEndian.Uint16(tlv[:2])) - if tlvType != LS_TLV_LOCAL_NODE_DESC { - return malformedAttrListErr("Mandatory TLV missing") - } - - l.LocalNodeDesc = &LsTLVNodeDescriptor{} - if err := l.LocalNodeDesc.DecodeFromBytes(tlv); err != nil { - return malformedAttrListErr(fmt.Sprintf("Malformed Node NLRI: %v", err)) - } - - return nil -} - -func (l *LsNodeNLRI) String() string { - if l.LocalNodeDesc == nil { - return "NODE { EMPTY }" - } - - local := l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract() - return fmt.Sprintf("NODE { AS:%v BGP-LS ID:%v %v %v:%v }", local.Asn, local.BGPLsID, local.IGPRouterID, l.ProtocolID.String(), l.Identifier) -} - -func (l *LsNodeNLRI) Serialize() ([]byte, error) { - if l.LocalNodeDesc == nil { - return nil, errors.New("local node descriptor missing") - } - ser, err := l.LocalNodeDesc.Serialize() - if err != nil { - return nil, err - } - - return l.LsNLRI.Serialize(ser) -} - -func (l *LsNodeNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsNLRIType `json:"type"` - LocalNode LsNodeDescriptor `json:"local_node_desc"` - }{ - Type: l.Type(), - LocalNode: *l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract(), - }) -} - -type LsLinkDescriptor struct { - LinkLocalID *uint32 - LinkRemoteID *uint32 - InterfaceAddrIPv4 *net.IP - NeighborAddrIPv4 *net.IP - InterfaceAddrIPv6 *net.IP - NeighborAddrIPv6 *net.IP -} - -func (l *LsLinkDescriptor) ParseTLVs(tlvs []LsTLVInterface) { - for _, tlv := range tlvs { - switch v := tlv.(type) { - case *LsTLVLinkID: - l.LinkLocalID = &v.Local - l.LinkRemoteID = &v.Remote - - case *LsTLVIPv4InterfaceAddr: - l.InterfaceAddrIPv4 = &v.IP - - case *LsTLVIPv4NeighborAddr: - l.NeighborAddrIPv4 = &v.IP - - case *LsTLVIPv6InterfaceAddr: - l.InterfaceAddrIPv6 = &v.IP - - case *LsTLVIPv6NeighborAddr: - l.NeighborAddrIPv6 = &v.IP - } - } -} - -func (l *LsLinkDescriptor) String() string { - switch { - case l.InterfaceAddrIPv4 != nil && l.NeighborAddrIPv4 != nil: - return fmt.Sprintf("%v->%v", l.InterfaceAddrIPv4, l.NeighborAddrIPv4) - - case l.InterfaceAddrIPv6 != nil && l.NeighborAddrIPv6 != nil: - return fmt.Sprintf("%v->%v", l.InterfaceAddrIPv6, l.NeighborAddrIPv6) - - case l.LinkLocalID != nil && l.LinkRemoteID != nil: - return fmt.Sprintf("%v->%v", *l.LinkLocalID, *l.LinkRemoteID) - - case l.InterfaceAddrIPv4 != nil: - return fmt.Sprintf("%v->UNKNOWN", l.InterfaceAddrIPv4) - case l.NeighborAddrIPv4 != nil: - return fmt.Sprintf("UNKNOWN->%v", l.NeighborAddrIPv4) - - case l.InterfaceAddrIPv6 != nil: - return fmt.Sprintf("%v->UNKNOWN", l.InterfaceAddrIPv6) - case l.NeighborAddrIPv6 != nil: - return fmt.Sprintf("UNKNOWN->%v", l.NeighborAddrIPv6) - - case l.LinkLocalID != nil: - return fmt.Sprintf("%v->UNKNOWN", *l.LinkLocalID) - case l.LinkRemoteID != nil: - return fmt.Sprintf("UNKNOWN->%v", *l.LinkRemoteID) - - default: - return "UNKNOWN" - } -} - -func NewLsLinkTLVs(ld *LsLinkDescriptor) []LsTLVInterface { - tlvs := []LsTLVInterface{} - - if ld.LinkLocalID != nil && ld.LinkRemoteID != nil { - tlvs = append(tlvs, &LsTLVLinkID{ - // https://tools.ietf.org/html/rfc5307#section-1.1 - LsTLV: LsTLV{ - Type: LS_TLV_LINK_ID, - Length: 8, - }, - Local: *ld.LinkLocalID, - Remote: *ld.LinkRemoteID, - }) - } - - if ld.InterfaceAddrIPv4 != nil { - tlvs = append(tlvs, &LsTLVIPv4InterfaceAddr{ - LsTLV: LsTLV{ - Type: LS_TLV_IPV4_INTERFACE_ADDR, - Length: net.IPv4len, - }, - IP: *ld.InterfaceAddrIPv4, - }) - } - if ld.NeighborAddrIPv4 != nil { - tlvs = append(tlvs, &LsTLVIPv4NeighborAddr{ - LsTLV: LsTLV{ - Type: LS_TLV_IPV4_NEIGHBOR_ADDR, - Length: net.IPv4len, - }, - IP: *ld.NeighborAddrIPv4, - }) - } - if ld.InterfaceAddrIPv6 != nil { - tlvs = append(tlvs, &LsTLVIPv6InterfaceAddr{ - LsTLV: LsTLV{ - Type: LS_TLV_IPV6_INTERFACE_ADDR, - Length: net.IPv6len, - }, - IP: *ld.InterfaceAddrIPv6, - }) - } - if ld.NeighborAddrIPv6 != nil { - tlvs = append(tlvs, &LsTLVIPv6NeighborAddr{ - LsTLV: LsTLV{ - Type: LS_TLV_IPV6_NEIGHBOR_ADDR, - Length: net.IPv6len, - }, - IP: *ld.NeighborAddrIPv6, - }) - } - - return tlvs -} - -type LsLinkNLRI struct { - LsNLRI - LocalNodeDesc LsTLVInterface - RemoteNodeDesc LsTLVInterface - LinkDesc []LsTLVInterface -} - -func (l *LsLinkNLRI) String() string { - if l.LocalNodeDesc == nil || l.RemoteNodeDesc == nil { - return "LINK { EMPTY }" - } - var local string - var remote string - if l.LsNLRI.ProtocolID == LS_PROTOCOL_BGP { - local = l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract().BGPRouterID.String() - remote = l.RemoteNodeDesc.(*LsTLVNodeDescriptor).Extract().BGPRouterID.String() - } else { - local = l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract().IGPRouterID - remote = l.RemoteNodeDesc.(*LsTLVNodeDescriptor).Extract().IGPRouterID - } - - link := &LsLinkDescriptor{} - link.ParseTLVs(l.LinkDesc) - - return fmt.Sprintf("LINK { LOCAL_NODE: %v REMOTE_NODE: %v LINK: %v}", local, remote, link) -} - -func (l *LsLinkNLRI) DecodeFromBytes(data []byte) error { - if err := l.LsNLRI.DecodeFromBytes(data); err != nil { - return nil - } - - tlv := data[lsNLRIHdrLen:] - m := make(map[LsTLVType]bool) - - for len(tlv) >= tlvHdrLen { - sub := &LsTLV{} - _, err := sub.DecodeFromBytes(tlv) - if err != nil { - return err - } - m[sub.Type] = true - - var subTLV LsTLVInterface - switch sub.Type { - case LS_TLV_LOCAL_NODE_DESC, LS_TLV_REMOTE_NODE_DESC: - subTLV = &LsTLVNodeDescriptor{} - case LS_TLV_LINK_ID: - subTLV = &LsTLVLinkID{} - case LS_TLV_IPV4_INTERFACE_ADDR: - subTLV = &LsTLVIPv4InterfaceAddr{} - case LS_TLV_IPV4_NEIGHBOR_ADDR: - subTLV = &LsTLVIPv4NeighborAddr{} - case LS_TLV_IPV6_INTERFACE_ADDR: - subTLV = &LsTLVIPv6InterfaceAddr{} - case LS_TLV_IPV6_NEIGHBOR_ADDR: - subTLV = &LsTLVIPv6NeighborAddr{} - - default: - tlv = tlv[sub.Len():] - l.Length -= uint16(sub.Len()) - continue - } - - if err := subTLV.DecodeFromBytes(tlv); err != nil { - return err - } - tlv = tlv[subTLV.Len():] - - switch sub.Type { - case LS_TLV_LOCAL_NODE_DESC: - l.LocalNodeDesc = subTLV - case LS_TLV_REMOTE_NODE_DESC: - l.RemoteNodeDesc = subTLV - default: - l.LinkDesc = append(l.LinkDesc, subTLV) - } - } - - required := []LsTLVType{LS_TLV_LOCAL_NODE_DESC, LS_TLV_REMOTE_NODE_DESC} - for _, tlv := range required { - if _, ok := m[tlv]; !ok { - return malformedAttrListErr("Required TLV missing") - } - } - - return nil -} - -func (l *LsLinkNLRI) Serialize() ([]byte, error) { - if l.LocalNodeDesc == nil || l.RemoteNodeDesc == nil { - return nil, errors.New("required TLV missing") - } - - buf := make([]byte, 0) - s, err := l.LocalNodeDesc.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - s, err = l.RemoteNodeDesc.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - for _, tlv := range l.LinkDesc { - s, err := tlv.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - } - - return l.LsNLRI.Serialize(buf) -} - -func (l *LsLinkNLRI) MarshalJSON() ([]byte, error) { - linkDesc := &LsLinkDescriptor{} - linkDesc.ParseTLVs(l.LinkDesc) - - return json.Marshal(struct { - Type LsNLRIType `json:"type"` - LocalNode LsNodeDescriptor `json:"local_node_desc"` - RemoteNode LsNodeDescriptor `json:"remote_node_desc"` - LinkDesc LsLinkDescriptor `json:"link_desc"` - }{ - Type: l.Type(), - LocalNode: *l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract(), - RemoteNode: *l.RemoteNodeDesc.(*LsTLVNodeDescriptor).Extract(), - LinkDesc: *linkDesc, - }) -} - -type LsPrefixDescriptor struct { - IPReachability []net.IPNet - OSPFRouteType LsOspfRouteType -} - -func (l *LsPrefixDescriptor) ParseTLVs(tlvs []LsTLVInterface, ipv6 bool) { - for _, tlv := range tlvs { - switch v := tlv.(type) { - case *LsTLVIPReachability: - l.IPReachability = append(l.IPReachability, v.ToIPNet(ipv6)) - - case *LsTLVOspfRouteType: - l.OSPFRouteType = v.RouteType - } - } -} - -type LsPrefixV4NLRI struct { - LsNLRI - LocalNodeDesc LsTLVInterface - PrefixDesc []LsTLVInterface -} - -func (l *LsPrefixV4NLRI) String() string { - if l.LocalNodeDesc == nil { - return "PREFIXv4 { EMPTY }" - } - - local := l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract() - prefix := &LsPrefixDescriptor{} - prefix.ParseTLVs(l.PrefixDesc, false) - ips := make([]string, len(prefix.IPReachability)) - for i, ip := range prefix.IPReachability { - ips[i] = ip.String() - } - - ospf := "" - if prefix.OSPFRouteType != LS_OSPF_ROUTE_TYPE_UNKNOWN { - ospf = fmt.Sprintf("OSPF_ROUTE_TYPE:%v ", prefix.OSPFRouteType) - } - - return fmt.Sprintf("PREFIXv4 { LOCAL_NODE: %s PREFIX: %v %s}", local.IGPRouterID, ips, ospf) -} - -func (l *LsPrefixV4NLRI) DecodeFromBytes(data []byte) error { - if err := l.LsNLRI.DecodeFromBytes(data); err != nil { - return nil - } - - tlv := data[lsNLRIHdrLen:] - m := make(map[LsTLVType]bool) - - for len(tlv) >= tlvHdrLen { - sub := &LsTLV{} - _, err := sub.DecodeFromBytes(tlv) - if err != nil { - return err - } - m[sub.Type] = true - - var subTLV LsTLVInterface - switch sub.Type { - case LS_TLV_LOCAL_NODE_DESC: - subTLV = &LsTLVNodeDescriptor{} - case LS_TLV_OSPF_ROUTE_TYPE: - subTLV = &LsTLVOspfRouteType{} - case LS_TLV_IP_REACH_INFO: - subTLV = &LsTLVIPReachability{} - - default: - tlv = tlv[sub.Len():] - l.Length -= uint16(sub.Len()) - continue - } - - if err := subTLV.DecodeFromBytes(tlv); err != nil { - return err - } - tlv = tlv[subTLV.Len():] - - switch sub.Type { - case LS_TLV_LOCAL_NODE_DESC: - l.LocalNodeDesc = subTLV - default: - l.PrefixDesc = append(l.PrefixDesc, subTLV) - } - } - - required := []LsTLVType{LS_TLV_IP_REACH_INFO, LS_TLV_LOCAL_NODE_DESC} - for _, tlv := range required { - if _, ok := m[tlv]; !ok { - return malformedAttrListErr("Required TLV missing") - } - } - - for _, tlv := range l.PrefixDesc { - switch v := tlv.(type) { - case *LsTLVIPReachability: - if v.PrefixLength > 8*net.IPv4len { - return malformedAttrListErr("Unexpected IP Reachability info") - } - } - } - - return nil -} - -func (l *LsPrefixV4NLRI) Serialize() ([]byte, error) { - if l.LocalNodeDesc == nil { - return nil, errors.New("required TLV missing") - } - - buf := make([]byte, 0) - s, err := l.LocalNodeDesc.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - for _, tlv := range l.PrefixDesc { - s, err := tlv.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - } - - return l.LsNLRI.Serialize(buf) -} - -func (l *LsPrefixV4NLRI) MarshalJSON() ([]byte, error) { - prefixDesc := &LsPrefixDescriptor{} - prefixDesc.ParseTLVs(l.PrefixDesc, false) - - return json.Marshal(struct { - Type LsNLRIType `json:"type"` - LocalNode LsNodeDescriptor `json:"local_node_desc"` - PrefixDesc LsPrefixDescriptor `json:"prefix_desc"` - }{ - Type: l.Type(), - LocalNode: *l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract(), - PrefixDesc: *prefixDesc, - }) -} - -func NewLsPrefixTLVs(pd *LsPrefixDescriptor) []LsTLVInterface { - lsTLVs := []LsTLVInterface{} - for _, ipReach := range pd.IPReachability { - prefixSize, _ := ipReach.Mask.Size() - lenIpPrefix := (prefixSize-1)/8 + 1 - lenIpReach := uint16(lenIpPrefix + 1) - var tlv *LsTLVIPReachability - - if ipReach.IP.To4() != nil { - ip := ipReach.IP.To4() - tlv = &LsTLVIPReachability{ - LsTLV: LsTLV{ - Type: LS_TLV_IP_REACH_INFO, - Length: lenIpReach, - }, - PrefixLength: uint8(prefixSize), - Prefix: []byte(ip)[:((lenIpPrefix-1)/8 + 1)], - } - } else if ipReach.IP.To16() != nil { - ip := ipReach.IP.To16() - tlv = &LsTLVIPReachability{ - LsTLV: LsTLV{ - Type: LS_TLV_IP_REACH_INFO, - Length: lenIpReach, - }, - PrefixLength: uint8(prefixSize), - Prefix: []byte(ip)[:((lenIpPrefix-1)/8 + 1)], - } - } - lsTLVs = append(lsTLVs, tlv) - } - - lsTLVs = append(lsTLVs, - &LsTLVOspfRouteType{ - LsTLV: LsTLV{ - Type: LS_TLV_OSPF_ROUTE_TYPE, - Length: 1, - }, - RouteType: pd.OSPFRouteType, - }) - return lsTLVs -} - -type LsPrefixV6NLRI struct { - LsNLRI - LocalNodeDesc LsTLVInterface - PrefixDesc []LsTLVInterface -} - -func (l *LsPrefixV6NLRI) String() string { - if l.LocalNodeDesc == nil { - return "PREFIXv6 { EMPTY }" - } - - local := l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract() - prefix := &LsPrefixDescriptor{} - prefix.ParseTLVs(l.PrefixDesc, true) - ips := []string{} - for _, ip := range prefix.IPReachability { - ips = append(ips, ip.String()) - } - - ospf := "" - if prefix.OSPFRouteType != LS_OSPF_ROUTE_TYPE_UNKNOWN { - ospf = fmt.Sprintf("OSPF_ROUTE_TYPE:%v ", prefix.OSPFRouteType) - } - - return fmt.Sprintf("PREFIXv6 { LOCAL_NODE: %v PREFIX: %v %v}", local.IGPRouterID, ips, ospf) -} - -func (l *LsPrefixV6NLRI) DecodeFromBytes(data []byte) error { - if err := l.LsNLRI.DecodeFromBytes(data); err != nil { - return nil - } - - tlv := data[lsNLRIHdrLen:] - m := make(map[LsTLVType]bool) - - for len(tlv) >= tlvHdrLen { - sub := &LsTLV{} - _, err := sub.DecodeFromBytes(tlv) - if err != nil { - return err - } - m[sub.Type] = true - - var subTLV LsTLVInterface - switch sub.Type { - case LS_TLV_LOCAL_NODE_DESC: - subTLV = &LsTLVNodeDescriptor{} - case LS_TLV_OSPF_ROUTE_TYPE: - subTLV = &LsTLVOspfRouteType{} - case LS_TLV_IP_REACH_INFO: - subTLV = &LsTLVIPReachability{} - - default: - tlv = tlv[sub.Len():] - l.Length -= uint16(sub.Len()) - continue - } - - if err := subTLV.DecodeFromBytes(tlv); err != nil { - return err - } - tlv = tlv[subTLV.Len():] - - switch sub.Type { - case LS_TLV_LOCAL_NODE_DESC: - l.LocalNodeDesc = subTLV - default: - l.PrefixDesc = append(l.PrefixDesc, subTLV) - } - } - - required := []LsTLVType{LS_TLV_IP_REACH_INFO, LS_TLV_LOCAL_NODE_DESC} - for _, tlv := range required { - if _, ok := m[tlv]; !ok { - return malformedAttrListErr("Required TLV missing") - } - } - - return nil -} - -func (l *LsPrefixV6NLRI) Serialize() ([]byte, error) { - if l.LocalNodeDesc == nil { - return nil, errors.New("required TLV missing") - } - - buf := make([]byte, 0) - s, err := l.LocalNodeDesc.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - for _, tlv := range l.PrefixDesc { - s, err := tlv.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - } - - return l.LsNLRI.Serialize(buf) -} - -func (l *LsPrefixV6NLRI) MarshalJSON() ([]byte, error) { - prefixDesc := &LsPrefixDescriptor{} - prefixDesc.ParseTLVs(l.PrefixDesc, true) - - return json.Marshal(struct { - Type LsNLRIType `json:"type"` - LocalNode LsNodeDescriptor `json:"local_node_desc"` - PrefixDesc LsPrefixDescriptor `json:"prefix_desc"` - }{ - Type: l.Type(), - LocalNode: *l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract(), - PrefixDesc: *prefixDesc, - }) -} - -// TODO: LsSrPolicyiCandidatePathNLRI - -type LsTLVSrv6SIDInfo struct { - LsTLV - SIDs []net.IP -} - -func (l *LsTLVSrv6SIDInfo) DecodeFromBytes(data []byte) error { - sid, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - for i := 0; i < len(sid)/16; i++ { - l.SIDs = append(l.SIDs, net.IP(sid[i*16:i*16+16])) - } - - return nil -} - -func (l *LsTLVSrv6SIDInfo) Serialize() ([]byte, error) { - buf := []byte{} - - for _, sid := range l.SIDs { - buf = append(buf, sid...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVSrv6SIDInfo) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SIDs []string `json:"sids"` - }{ - l.Type, - l.Strings(), - }) -} - -func (l *LsTLVSrv6SIDInfo) Strings() []string { - sidStrings := []string{} - for _, sid := range l.SIDs { - sidStrings = append(sidStrings, sid.String()) - } - - return sidStrings -} - -func (l *LsTLVSrv6SIDInfo) String() string { - return fmt.Sprintf("{SIDs: %s}", strings.Join(l.Strings(), ", ")) -} - -func (l *LsTLVSrv6SIDInfo) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVMultiTopoID struct { - LsTLV - MultiTopoIDs []uint16 -} - -func (l *LsTLVMultiTopoID) DecodeFromBytes(data []byte) error { - tlv, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - for i := 0; i < len(tlv); i += 2 { - if i+2 > len(tlv) { - return errors.New("TLV length mismatch") - } - - multiTopoID := binary.BigEndian.Uint16(tlv[i:i+2]) & 0x0FFF - l.MultiTopoIDs = append(l.MultiTopoIDs, multiTopoID) - } - return nil -} - -func (l *LsTLVMultiTopoID) Serialize() ([]byte, error) { - buf := []byte{} - - for _, multiTopoID := range l.MultiTopoIDs { - bytes := make([]byte, 2) - binary.BigEndian.PutUint16(bytes, multiTopoID) - buf = append(buf, bytes...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVMultiTopoID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - MultiTopoIDs []uint16 `json:"multi_topo_ids"` - }{ - l.Type, - l.MultiTopoIDs, - }) -} - -func (l *LsTLVMultiTopoID) Strings() []string { - multiTopoIDs := []string{} - for _, multiTopoID := range l.MultiTopoIDs { - multiTopoIDs = append(multiTopoIDs, fmt.Sprintf("%d", multiTopoID)) - } - - return multiTopoIDs -} - -func (l *LsTLVMultiTopoID) String() string { - return fmt.Sprintf("{MultiTopoIDs: %s}", strings.Join(l.Strings(), ", ")) -} - -func (l *LsTLVMultiTopoID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsSrv6SIDNLRI struct { - LsNLRI - LocalNodeDesc LsTLVInterface - MultiTopoID LsTLVInterface - Srv6SIDInfo LsTLVInterface -} - -func (l *LsSrv6SIDNLRI) String() string { - local := l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract() - srv6SID := l.Srv6SIDInfo.(*LsTLVSrv6SIDInfo) - multiTopo := l.MultiTopoID.(*LsTLVMultiTopoID) - - return fmt.Sprintf("SRv6SID { LOCAL_NODE: %s SRv6_SID: %v MULTI_TOPO_IDs: %v}", local, srv6SID.String(), multiTopo.String()) -} - -func (l *LsSrv6SIDNLRI) DecodeFromBytes(data []byte) error { - if err := l.LsNLRI.DecodeFromBytes(data); err != nil { - return nil - } - - tlvs := data[lsNLRIHdrLen:] - m := make(map[LsTLVType]bool) - - for len(tlvs) >= tlvHdrLen { - tlv := &LsTLV{} - _, err := tlv.DecodeFromBytes(tlvs) - if err != nil { - return err - } - m[tlv.Type] = true - - var tLVInterface LsTLVInterface - switch tlv.Type { - case LS_TLV_LOCAL_NODE_DESC: - tLVInterface = &LsTLVNodeDescriptor{} - case LS_TLV_SRV6_SID_INFO: - tLVInterface = &LsTLVSrv6SIDInfo{} - case LS_TLV_MULTI_TOPO_ID: - tLVInterface = &LsTLVMultiTopoID{} - default: - tlvs = tlvs[tlv.Len():] - l.Length -= uint16(tlv.Len()) - continue - } - - if err := tLVInterface.DecodeFromBytes(tlvs); err != nil { - return err - } - tlvs = tlvs[tLVInterface.Len():] - - switch tlv.Type { - case LS_TLV_LOCAL_NODE_DESC: - l.LocalNodeDesc = tLVInterface - case LS_TLV_SRV6_SID_INFO: - l.Srv6SIDInfo = tLVInterface - case LS_TLV_MULTI_TOPO_ID: - l.MultiTopoID = tLVInterface - } - } - - required := []LsTLVType{LS_TLV_LOCAL_NODE_DESC, LS_TLV_SRV6_SID_INFO} - for _, tlv := range required { - if _, ok := m[tlv]; !ok { - return malformedAttrListErr("Required TLV missing") - } - } - - return nil -} - -func (l *LsSrv6SIDNLRI) Serialize() ([]byte, error) { - if l.LocalNodeDesc == nil || l.Srv6SIDInfo == nil { - return nil, errors.New("required TLV missing") - } - buf := make([]byte, 0) - - s, err := l.LocalNodeDesc.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - s, err = l.Srv6SIDInfo.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - s, err = l.MultiTopoID.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - - return l.LsNLRI.Serialize(buf) -} - -func (l *LsSrv6SIDNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsNLRIType `json:"type"` - LocalNode LsNodeDescriptor `json:"local_node_desc"` - Srv6SID LsTLVSrv6SIDInfo `json:"srv6_sid_info"` - MultiTopoID LsTLVMultiTopoID `json:"multi_topo"` - }{ - - Type: l.Type(), - LocalNode: *l.LocalNodeDesc.(*LsTLVNodeDescriptor).Extract(), - Srv6SID: *l.Srv6SIDInfo.(*LsTLVSrv6SIDInfo), - MultiTopoID: *l.MultiTopoID.(*LsTLVMultiTopoID), - }) -} - -type LsTLVType uint16 - -// Based on https://www.iana.org/assignments/bgp-ls-parameters/bgp-ls-parameters.xhtml -const ( - LS_TLV_UNKNOWN LsTLVType = iota - - LS_TLV_LOCAL_NODE_DESC = 256 - LS_TLV_REMOTE_NODE_DESC = 257 - LS_TLV_LINK_ID = 258 - LS_TLV_IPV4_INTERFACE_ADDR = 259 - LS_TLV_IPV4_NEIGHBOR_ADDR = 260 - LS_TLV_IPV6_INTERFACE_ADDR = 261 - LS_TLV_IPV6_NEIGHBOR_ADDR = 262 - LS_TLV_MULTI_TOPO_ID = 263 - LS_TLV_OSPF_ROUTE_TYPE = 264 - LS_TLV_IP_REACH_INFO = 265 - - LS_TLV_AS = 512 - LS_TLV_BGP_LS_ID = 513 - LS_TLV_OSPF_AREA = 514 - LS_TLV_IGP_ROUTER_ID = 515 - LS_TLV_BGP_ROUTER_ID = 516 // RFC9086 - LS_TLV_BGP_CONFEDERATION_MEMBER = 517 // RFC9086 - LS_TLV_SRV6_SID_INFO = 518 // RFC9514 - - LS_TLV_NODE_FLAG_BITS = 1024 - LS_TLV_OPAQUE_NODE_ATTR = 1025 - LS_TLV_NODE_NAME = 1026 - LS_TLV_ISIS_AREA = 1027 - LS_TLV_IPV4_LOCAL_ROUTER_ID = 1028 - LS_TLV_IPV6_LOCAL_ROUTER_ID = 1029 - LS_TLV_IPV4_REMOTE_ROUTER_ID = 1030 - LS_TLV_IPV6_REMOTE_ROUTER_ID = 1031 - - LS_TLV_SR_CAPABILITIES = 1034 // draft-ietf-idr-bgp-ls-segment-routing-ext - LS_TLV_SR_ALGORITHM = 1035 // draft-ietf-idr-bgp-ls-segment-routing-ext - LS_TLV_SR_LOCAL_BLOCK = 1036 // draft-ietf-idr-bgp-ls-segment-routing-ext - LS_TLV_SRMS_PREFERENCE = 1037 // draft-ietf-idr-bgp-ls-segment-routing-ext, TODO - - LS_TLV_ADMIN_GROUP = 1088 - LS_TLV_MAX_LINK_BANDWIDTH = 1089 - LS_TLV_MAX_RESERVABLE_BANDWIDTH = 1090 - LS_TLV_UNRESERVED_BANDWIDTH = 1091 - LS_TLV_TE_DEFAULT_METRIC = 1092 - LS_TLV_LINK_PROTECTION_TYPE = 1093 // TODO - LS_TLV_MPLS_PROTOCOL_MASK = 1094 // TODO - LS_TLV_IGP_METRIC = 1095 - LS_TLV_SRLG = 1096 - LS_TLV_OPAQUE_LINK_ATTR = 1097 - LS_TLV_LINK_NAME = 1098 - LS_TLV_ADJACENCY_SID = 1099 // draft-ietf-idr-bgp-ls-segment-routing-ext - LS_TLV_LAN_ADJACENCY_SID = 1100 // draft-ietf-idr-bgp-ls-segment-routing-ext, TODO - LS_TLV_PEER_NODE_SID = 1101 // RFC9086 - LS_TLV_PEER_ADJACENCY_SID = 1102 // RFC9086 - LS_TLV_PEER_SET_SID = 1103 // RFC9086 - - LS_TLV_RTM_CAPABILITY = 1105 // RFC8169, TODO - - LS_TLV_IGP_FLAGS = 1152 - LS_TLV_IGP_ROUTE_TAG = 1153 // TODO - LS_TLV_EXTENDED_ROUTE_TAG = 1154 // TODO - LS_TLV_PREFIX_METRIC = 1155 // TODO - LS_TLV_OSPF_FORWARDING_ADDR = 1156 // TODO - LS_TLV_OPAQUE_PREFIX_ATTR = 1157 - LS_TLV_PREFIX_SID = 1158 // draft-ietf-idr-bgp-ls-segment-routing-ext - LS_TLV_RANGE = 1159 // draft-ietf-idr-bgp-ls-segment-routing-ext, TODO - LS_TLV_SID_LABEL_TLV = 1161 // draft-ietf-idr-bgp-ls-segment-routing-ext - LS_TLV_PREFIX_ATTRIBUTE_FLAGS = 1170 // draft-ietf-idr-bgp-ls-segment-routing-ext, TODO - LS_TLV_SOURCE_ROUTER_ID = 1171 // draft-ietf-idr-bgp-ls-segment-routing-ext, TODO - LS_TLV_L2_BUNDLE_MEMBER_TLV = 1172 // draft-ietf-idr-bgp-ls-segment-routing-ext, TODO -) - -type LsTLVInterface interface { - Len() int - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - String() string - MarshalJSON() ([]byte, error) - GetLsTLV() LsTLV -} - -func NewLsAttributeTLVs(lsAttr *LsAttribute) []LsTLVInterface { - tlvs := []LsTLVInterface{} - - if lsAttr.Node.Flags != nil { - tlvs = append(tlvs, NewLsTLVNodeFlagbits(lsAttr.Node.Flags)) - } - if lsAttr.Node.Opaque != nil { - tlvs = append(tlvs, NewLsTLVOpaqueNodeAttr(lsAttr.Node.Opaque)) - } - if lsAttr.Node.Name != nil { - tlvs = append(tlvs, NewLsTLVNodeName(lsAttr.Node.Name)) - } - if lsAttr.Node.IsisArea != nil { - tlvs = append(tlvs, NewLsTLVIsisArea(lsAttr.Node.IsisArea)) - } - if lsAttr.Node.LocalRouterID != (*net.IP)(nil) { - tlvs = append(tlvs, NewLsTLVLocalIPv4RouterID(lsAttr.Node.LocalRouterID)) - } - if lsAttr.Node.LocalRouterIDv6 != (*net.IP)(nil) { - tlvs = append(tlvs, NewLsTLVLocalIPv6RouterID(lsAttr.Node.LocalRouterIDv6)) - } - if lsAttr.Node.SrCapabilties != nil { - tlvs = append(tlvs, NewLsTLVSrCapabilities(lsAttr.Node.SrCapabilties)) - } - if lsAttr.Node.SrAlgorithms != nil { - tlvs = append(tlvs, NewLsTLVSrAlgorithm(lsAttr.Node.SrAlgorithms)) - } - if lsAttr.Node.SrLocalBlock != nil { - tlvs = append(tlvs, NewLsTLVSrLocalBlock(lsAttr.Node.SrLocalBlock)) - } - - if lsAttr.Link.Name != nil { - tlvs = append(tlvs, NewLsTLVLinkName(lsAttr.Link.Name)) - } - if lsAttr.Link.LocalRouterID != (*net.IP)(nil) { - tlvs = append(tlvs, NewLsTLVLocalIPv4RouterID(lsAttr.Link.LocalRouterID)) - } - if lsAttr.Link.LocalRouterIDv6 != (*net.IP)(nil) { - tlvs = append(tlvs, NewLsTLVLocalIPv6RouterID(lsAttr.Link.LocalRouterIDv6)) - } - if lsAttr.Link.RemoteRouterID != (*net.IP)(nil) { - tlvs = append(tlvs, NewLsTLVRemoteIPv4RouterID(lsAttr.Link.RemoteRouterID)) - } - if lsAttr.Link.RemoteRouterIDv6 != (*net.IP)(nil) { - tlvs = append(tlvs, NewLsTLVRemoteIPv6RouterID(lsAttr.Link.RemoteRouterIDv6)) - } - if lsAttr.Link.AdminGroup != nil { - tlvs = append(tlvs, NewLsTLVAdminGroup(lsAttr.Link.AdminGroup)) - } - if lsAttr.Link.DefaultTEMetric != nil { - tlvs = append(tlvs, NewLsTLVTEDefaultMetric(lsAttr.Link.DefaultTEMetric)) - } - if lsAttr.Link.IGPMetric != nil { - tlvs = append(tlvs, NewLsTLVIGPMetric(lsAttr.Link.IGPMetric)) - } - if lsAttr.Link.Opaque != nil { - tlvs = append(tlvs, NewLsTLVOpaqueLinkAttr(lsAttr.Link.Opaque)) - } - if lsAttr.Link.Bandwidth != nil { - tlvs = append(tlvs, NewLsTLVMaxLinkBw(lsAttr.Link.Bandwidth)) - } - if lsAttr.Link.ReservableBandwidth != nil { - tlvs = append(tlvs, NewLsTLVMaxReservableLinkBw(lsAttr.Link.ReservableBandwidth)) - } - if lsAttr.Link.UnreservedBandwidth != nil && *lsAttr.Link.UnreservedBandwidth != [8]float32{0, 0, 0, 0, 0, 0, 0, 0} { - tlvs = append(tlvs, NewLsTLVUnreservedBw(lsAttr.Link.UnreservedBandwidth)) - } - if lsAttr.Link.Srlgs != nil { - tlvs = append(tlvs, NewLsTLVSrlg(lsAttr.Link.Srlgs)) - } - if lsAttr.Link.SrAdjacencySID != nil { - tlvs = append(tlvs, NewLsTLVAdjacencySID(lsAttr.Link.SrAdjacencySID)) - } - - if lsAttr.Prefix.IGPFlags != nil { - tlvs = append(tlvs, NewLsTLVIGPFlags(lsAttr.Prefix.IGPFlags)) - } - if lsAttr.Prefix.Opaque != nil { - tlvs = append(tlvs, NewLsTLVOpaquePrefixAttr(lsAttr.Prefix.Opaque)) - } - if lsAttr.Prefix.SrPrefixSID != nil { - tlvs = append(tlvs, NewLsTLVPrefixSID(lsAttr.Prefix.SrPrefixSID)) - } - - if lsAttr.BgpPeerSegment.BgpPeerNodeSid != nil { - tlvs = append(tlvs, NewLsTLVPeerNodeSID(lsAttr.BgpPeerSegment.BgpPeerNodeSid)) - } - if lsAttr.BgpPeerSegment.BgpPeerAdjacencySid != nil { - tlvs = append(tlvs, NewLsTLVPeerAdjacencySID(lsAttr.BgpPeerSegment.BgpPeerAdjacencySid)) - } - if lsAttr.BgpPeerSegment.BgpPeerSetSid != nil { - tlvs = append(tlvs, NewLsTLVPeerSetSID(lsAttr.BgpPeerSegment.BgpPeerSetSid)) - } - - return tlvs -} - -type LsTLV struct { - Type LsTLVType - Length uint16 -} - -func malformedAttrListErr(s string) error { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, s) -} - -const tlvHdrLen = 4 - -func (l *LsTLV) Len() int { - return int(l.Length) + tlvHdrLen -} - -func (l *LsTLV) Serialize(value []byte) ([]byte, error) { - if len(value) != int(l.Length) { - return nil, malformedAttrListErr("serialization failed: LS TLV malformed") - } - - buf := make([]byte, tlvHdrLen+len(value)) - binary.BigEndian.PutUint16(buf[:2], uint16(l.Type)) - binary.BigEndian.PutUint16(buf[2:4], uint16(l.Length)) - copy(buf[4:], value) - - return buf, nil -} - -func (l *LsTLV) DecodeFromBytes(data []byte) ([]byte, error) { - if len(data) < tlvHdrLen { - return nil, malformedAttrListErr("decoding failed: LS TLV malformed") - } - l.Type = LsTLVType(binary.BigEndian.Uint16(data[:2])) - l.Length = binary.BigEndian.Uint16(data[2:4]) - - if len(data) < l.Len() { - return nil, malformedAttrListErr("decoding failed: LS TLV malformed") - } - - return data[tlvHdrLen:l.Len()], nil -} - -type LsTLVLinkID struct { - LsTLV - Local uint32 - Remote uint32 -} - -func (l *LsTLVLinkID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_LINK_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5307#section-1.1 - if len(value) != 8 { - return malformedAttrListErr("Incorrect Link ID length") - } - - l.Local = binary.BigEndian.Uint32(value[:4]) - l.Remote = binary.BigEndian.Uint32(value[4:]) - - return nil -} - -func (l *LsTLVLinkID) Serialize() ([]byte, error) { - buf := make([]byte, 8) - binary.BigEndian.PutUint32(buf[:4], l.Local) - binary.BigEndian.PutUint32(buf[4:], l.Remote) - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVLinkID) String() string { - return fmt.Sprintf("{Link ID Remote: %v Local: %v}", l.Local, l.Remote) -} - -func (l *LsTLVLinkID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Local uint32 `json:"local_link_id"` - Remote uint32 `json:"remote_link_id"` - }{ - Type: l.Type, - Local: l.Local, - Remote: l.Remote, - }) -} - -func (l *LsTLVLinkID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIPv4InterfaceAddr struct { - LsTLV - IP net.IP -} - -func (l *LsTLVIPv4InterfaceAddr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV4_INTERFACE_ADDR { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-3.2 - if len(value) != 4 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - return nil -} - -func (l *LsTLVIPv4InterfaceAddr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVIPv4InterfaceAddr) String() string { - return fmt.Sprintf("{IPv4 Interface Address: %v}", l.IP) -} - -func (l *LsTLVIPv4InterfaceAddr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"ipv4_interface_address"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVIPv4InterfaceAddr) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIPv4NeighborAddr struct { - LsTLV - IP net.IP -} - -func (l *LsTLVIPv4NeighborAddr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV4_NEIGHBOR_ADDR { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-3.3 - if len(value) != 4 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - return nil -} - -func (l *LsTLVIPv4NeighborAddr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVIPv4NeighborAddr) String() string { - return fmt.Sprintf("{IPv4 Neighbor Address: %v}", l.IP) -} - -func (l *LsTLVIPv4NeighborAddr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"ipv4_neighbor_address"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVIPv4NeighborAddr) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIPv6InterfaceAddr struct { - LsTLV - IP net.IP -} - -func (l *LsTLVIPv6InterfaceAddr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV6_INTERFACE_ADDR { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc6119#section-4.2 - if len(value) != 16 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - if l.IP.IsLinkLocalUnicast() { - return malformedAttrListErr("Unexpected link local address") - } - - return nil -} - -func (l *LsTLVIPv6InterfaceAddr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVIPv6InterfaceAddr) String() string { - return fmt.Sprintf("{IPv6 Interface Address: %v}", l.IP) -} - -func (l *LsTLVIPv6InterfaceAddr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"ipv6_interface_address"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVIPv6InterfaceAddr) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIPv6NeighborAddr struct { - LsTLV - IP net.IP -} - -func (l *LsTLVIPv6NeighborAddr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV6_NEIGHBOR_ADDR { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc6119#section-4.3 - if len(value) != 16 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - if l.IP.IsLinkLocalUnicast() { - return malformedAttrListErr("Unexpected link local address") - } - - return nil -} - -func (l *LsTLVIPv6NeighborAddr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVIPv6NeighborAddr) String() string { - return fmt.Sprintf("{IPv6 Neighbor Address: %v}", l.IP) -} - -func (l *LsTLVIPv6NeighborAddr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"ipv6_neighbor_address"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVIPv6NeighborAddr) GetLsTLV() LsTLV { - return l.LsTLV -} - -// https://tools.ietf.org/html/rfc7752#section-3.3.1.1 -type LsNodeFlags struct { - Overload bool `json:"overload"` - Attached bool `json:"attached"` - External bool `json:"external"` - ABR bool `json:"abr"` - Router bool `json:"router"` - V6 bool `json:"v6"` -} - -type LsTLVNodeFlagBits struct { - LsTLV - Flags uint8 -} - -func NewLsTLVNodeFlagbits(l *LsNodeFlags) *LsTLVNodeFlagBits { - var flags uint8 - if l.Overload { - flags = flags & (1 >> 7) - } - if l.Attached { - flags = flags & (1 >> 6) - } - if l.External { - flags = flags & (1 >> 5) - } - if l.ABR { - flags = flags & (1 >> 4) - } - if l.Router { - flags = flags & (1 >> 3) - } - if l.V6 { - flags = flags & (1 >> 2) - } - return &LsTLVNodeFlagBits{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 2, - }, - Flags: flags, - } -} - -func (l *LsTLVNodeFlagBits) Extract() *LsNodeFlags { - return &LsNodeFlags{ - Overload: (l.Flags & (1 << 7)) > 0, - Attached: (l.Flags & (1 << 6)) > 0, - External: (l.Flags & (1 << 5)) > 0, - ABR: (l.Flags & (1 << 4)) > 0, - Router: (l.Flags & (1 << 3)) > 0, - V6: (l.Flags & (1 << 2)) > 0, - } -} - -func (l *LsTLVNodeFlagBits) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_NODE_FLAG_BITS { - return malformedAttrListErr("Unexpected TLV type") - } - - if l.Length != 1 { - return malformedAttrListErr("Node Flag Bits TLV malformed") - } - - l.Flags = value[0] - - return nil -} - -func (l *LsTLVNodeFlagBits) Serialize() ([]byte, error) { - return l.LsTLV.Serialize([]byte{l.Flags}) -} - -func (l *LsTLVNodeFlagBits) String() string { - flags := "XXVRBETO" - - var buf bytes.Buffer - - for i := 0; i < len(flags); i++ { - if l.Flags&(1< 0 { - buf.WriteString(flags[i : i+1]) - } else { - buf.WriteString("*") - } - } - - return fmt.Sprintf("{Node Flags: %s}", buf.String()) -} - -func (l *LsTLVNodeFlagBits) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Flags string `json:"node_flags"` - }{ - Type: l.Type, - Flags: l.String(), - }) -} - -func (l *LsTLVNodeFlagBits) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVNodeName struct { - LsTLV - Name string -} - -func NewLsTLVNodeName(l *string) *LsTLVNodeName { - return &LsTLVNodeName{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(len(*l)), - }, - Name: *l, - } -} - -func (l *LsTLVNodeName) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_NODE_NAME { - return malformedAttrListErr("Unexpected TLV type") - } - - // RFC5301, section 3. - if l.Length < 1 || l.Length > 255 { - return malformedAttrListErr("Incorrect Node Name") - } - - l.Name = string(value) - - return nil -} - -func (l *LsTLVNodeName) Serialize() ([]byte, error) { - return l.LsTLV.Serialize([]byte(l.Name)) -} - -func (l *LsTLVNodeName) String() string { - return fmt.Sprintf("{Node Name: %s}", l.Name) -} - -func (l *LsTLVNodeName) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Name string `json:"node_name"` - }{ - Type: l.Type, - Name: l.Name, - }) -} - -func (l *LsTLVNodeName) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIsisArea struct { - LsTLV - Area []byte -} - -func NewLsTLVIsisArea(l *[]byte) *LsTLVIsisArea { - return &LsTLVIsisArea{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(len(*l)), - }, - Area: *l, - } -} - -func (l *LsTLVIsisArea) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_ISIS_AREA { - return malformedAttrListErr("Unexpected TLV type") - } - - if len(value) < 1 || len(value) > 13 { - return malformedAttrListErr("Incorrect ISIS Area size") - } - - l.Area = value - - return nil -} - -func (l *LsTLVIsisArea) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.Area) -} - -func (l *LsTLVIsisArea) String() string { - return fmt.Sprintf("{ISIS Area ID: %v}", l.Area) -} - -func (l *LsTLVIsisArea) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Area string `json:"isis_area_id"` - }{ - Type: l.Type, - Area: fmt.Sprintf("%v", l.Area), - }) -} - -func (l *LsTLVIsisArea) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVLocalIPv4RouterID struct { - LsTLV - IP net.IP -} - -func NewLsTLVLocalIPv4RouterID(l *net.IP) *LsTLVLocalIPv4RouterID { - return &LsTLVLocalIPv4RouterID{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - IP: *l, - } -} - -func (l *LsTLVLocalIPv4RouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV4_LOCAL_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-4.3 - if len(value) != 4 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - return nil -} - -func (l *LsTLVLocalIPv4RouterID) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVLocalIPv4RouterID) String() string { - return fmt.Sprintf("{Local RouterID IPv4: %v}", l.IP) -} - -func (l *LsTLVLocalIPv4RouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"node_local_router_id_ipv4"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVLocalIPv4RouterID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVRemoteIPv4RouterID struct { - LsTLV - IP net.IP -} - -func NewLsTLVRemoteIPv4RouterID(l *net.IP) *LsTLVRemoteIPv4RouterID { - return &LsTLVRemoteIPv4RouterID{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - IP: *l, - } -} - -func (l *LsTLVRemoteIPv4RouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV4_REMOTE_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-4.3 - if len(value) != 4 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - return nil -} - -func (l *LsTLVRemoteIPv4RouterID) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVRemoteIPv4RouterID) String() string { - return fmt.Sprintf("{Remote RouterID IPv4: %v}", l.IP) -} - -func (l *LsTLVRemoteIPv4RouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"node_remote_router_id_ipv4"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVRemoteIPv4RouterID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVLocalIPv6RouterID struct { - LsTLV - IP net.IP -} - -func NewLsTLVLocalIPv6RouterID(l *net.IP) *LsTLVLocalIPv6RouterID { - return &LsTLVLocalIPv6RouterID{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 0, - }, - IP: *l, - } -} - -func (l *LsTLVLocalIPv6RouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV6_LOCAL_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc6119#section-4.1 - if len(value) != 16 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - return nil -} - -func (l *LsTLVLocalIPv6RouterID) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVLocalIPv6RouterID) String() string { - return fmt.Sprintf("{Local RouterID IPv6: %v}", l.IP) -} - -func (l *LsTLVLocalIPv6RouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"node_local_router_id_ipv6"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVLocalIPv6RouterID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVRemoteIPv6RouterID struct { - LsTLV - IP net.IP -} - -func NewLsTLVRemoteIPv6RouterID(l *net.IP) *LsTLVRemoteIPv6RouterID { - return &LsTLVRemoteIPv6RouterID{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - IP: *l, - } -} - -func (l *LsTLVRemoteIPv6RouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IPV6_REMOTE_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc6119#section-4.1 - if len(value) != 16 { - return malformedAttrListErr("Unexpected address size") - } - - l.IP = net.IP(value) - - return nil -} - -func (l *LsTLVRemoteIPv6RouterID) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.IP) -} - -func (l *LsTLVRemoteIPv6RouterID) String() string { - return fmt.Sprintf("{Remote RouterID IPv6: %v}", l.IP) -} - -func (l *LsTLVRemoteIPv6RouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"node_remote_router_id_ipv6"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.IP), - }) -} - -func (l *LsTLVRemoteIPv6RouterID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVOpaqueNodeAttr struct { - LsTLV - Attr []byte -} - -func NewLsTLVOpaqueNodeAttr(l *[]byte) *LsTLVOpaqueNodeAttr { - return &LsTLVOpaqueNodeAttr{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(len(*l)), - }, - Attr: *l, - } -} - -func (l *LsTLVOpaqueNodeAttr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_OPAQUE_NODE_ATTR { - return malformedAttrListErr("Unexpected TLV type") - } - - l.Attr = value - - return nil -} - -func (l *LsTLVOpaqueNodeAttr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.Attr) -} - -func (l *LsTLVOpaqueNodeAttr) String() string { - return fmt.Sprintf("{Opaque attribute: %v}", l.Attr) -} - -func (l *LsTLVOpaqueNodeAttr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"node_opaque_attribute"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.Attr), - }) -} - -func (l *LsTLVOpaqueNodeAttr) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVAutonomousSystem struct { - LsTLV - ASN uint32 -} - -func (l *LsTLVAutonomousSystem) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_AS { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.2.1.4 - if len(value) != 4 { - return malformedAttrListErr("Incorrect AS length") - } - - l.ASN = binary.BigEndian.Uint32(value) - - return nil -} - -func (l *LsTLVAutonomousSystem) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.ASN) - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVAutonomousSystem) String() string { - return fmt.Sprintf("{ASN: %d}", l.ASN) -} - -func (l *LsTLVAutonomousSystem) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - ASN uint32 `json:"asn"` - }{ - Type: l.Type, - ASN: l.ASN, - }) -} - -func (l *LsTLVAutonomousSystem) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVBgpLsID struct { - LsTLV - BGPLsID uint32 -} - -func (l *LsTLVBgpLsID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_BGP_LS_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.2.1.4 - if len(value) != 4 { - return malformedAttrListErr("Incorrect BGP-LS ID length") - } - - l.BGPLsID = binary.BigEndian.Uint32(value) - - return nil -} - -func (l *LsTLVBgpLsID) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.BGPLsID) - - return l.LsTLV.Serialize(buf[:4]) -} - -func (l *LsTLVBgpLsID) String() string { - return fmt.Sprintf("{BGP LS ID: %d}", l.BGPLsID) -} - -func (l *LsTLVBgpLsID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - BgpLsID uint32 `json:"bgp_ls_id"` - }{ - Type: l.Type, - BgpLsID: l.BGPLsID, - }) -} - -func (l *LsTLVBgpLsID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIgpRouterID struct { - LsTLV - RouterID []byte -} - -func (l *LsTLVIgpRouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IGP_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.2.1.4 - // 4, 6, 7, and 8 are the only valid values. - switch len(value) { - case 4, 6, 7, 8: - break - default: - return malformedAttrListErr(fmt.Sprintf("Incorrect IGP Router ID length: %d", len(value))) - } - - l.RouterID = value - - return nil -} - -func (l *LsTLVIgpRouterID) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.RouterID) -} - -func (l *LsTLVIgpRouterID) String() string { - return fmt.Sprintf("{IGP Router ID: %v}", l.RouterID) -} - -func (l *LsTLVIgpRouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - RouterID string `json:"igp_router_id"` - }{ - Type: l.Type, - RouterID: fmt.Sprintf("%v", l.RouterID), - }) -} - -func (l *LsTLVIgpRouterID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVOspfAreaID struct { - LsTLV - AreaID uint32 -} - -func (l *LsTLVOspfAreaID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_OSPF_AREA { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.2.1.4 - if len(value) != 4 { - return malformedAttrListErr("Incorrect OSPF Area ID length") - } - - l.AreaID = binary.BigEndian.Uint32(value) - - return nil -} - -func (l *LsTLVOspfAreaID) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.AreaID) - - return l.LsTLV.Serialize(buf[:4]) -} - -func (l *LsTLVOspfAreaID) String() string { - return fmt.Sprintf("{OSPF Area ID: %d}", l.AreaID) -} - -func (l *LsTLVOspfAreaID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - AreaID uint32 `json:"ospf_area_id"` - }{ - Type: l.Type, - AreaID: l.AreaID, - }) -} - -func (l *LsTLVOspfAreaID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVBgpRouterID struct { - LsTLV - RouterID net.IP -} - -func (l *LsTLVBgpRouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_BGP_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc9086#section-4.1 - // 4 is the only valid value. - if len(value) != 4 { - return malformedAttrListErr(fmt.Sprintf("Incorrect BGP Router ID length: %d", len(value))) - } - - l.RouterID = net.IP(value) - - return nil -} - -func (l *LsTLVBgpRouterID) Serialize() ([]byte, error) { - tmpaddr := l.RouterID - if tmpaddr.To4() != nil { - var buf [4]byte - copy(buf[:], l.RouterID.To4()) - return l.LsTLV.Serialize(buf[:]) - } - var buf [16]byte - copy(buf[:], l.RouterID.To16()) - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVBgpRouterID) String() string { - return fmt.Sprintf("{BGP Router ID: %v}", l.RouterID) -} - -func (l *LsTLVBgpRouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - RouterID string `json:"bgp_router_id"` - }{ - Type: l.Type, - RouterID: fmt.Sprintf("%v", l.RouterID), - }) -} - -func (l *LsTLVBgpRouterID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVBgpConfederationMember struct { - LsTLV - BgpConfederationMember uint32 -} - -func (l *LsTLVBgpConfederationMember) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_BGP_CONFEDERATION_MEMBER { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc9086#section-4.3 - // 4 is the only valid value. - if len(value) != 4 { - return malformedAttrListErr(fmt.Sprintf("Incorrect BGP Confederation Member length: %d", len(value))) - } - - l.BgpConfederationMember = binary.BigEndian.Uint32(value) - - return nil -} - -func (l *LsTLVBgpConfederationMember) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.BgpConfederationMember) - - return l.LsTLV.Serialize(buf[:4]) -} - -func (l *LsTLVBgpConfederationMember) String() string { - return fmt.Sprintf("{BGP Confederation Member: %d}", l.BgpConfederationMember) -} - -func (l *LsTLVBgpConfederationMember) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - BgpConfederationMember uint32 `json:"bgp_confederation_member"` - }{ - Type: l.Type, - BgpConfederationMember: l.BgpConfederationMember, - }) -} - -func (l *LsTLVBgpConfederationMember) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsOspfRouteType uint8 - -const ( - LS_OSPF_ROUTE_TYPE_UNKNOWN = iota - LS_OSPF_ROUTE_TYPE_INTRA_AREA - LS_OSPF_ROUTE_TYPE_INTER_AREA - LS_OSPF_ROUTE_TYPE_EXTERNAL1 - LS_OSPF_ROUTE_TYPE_EXTERNAL2 - LS_OSPF_ROUTE_TYPE_NSSA1 - LS_OSPF_ROUTE_TYPE_NSSA2 -) - -func (l LsOspfRouteType) String() string { - switch l { - case LS_OSPF_ROUTE_TYPE_INTRA_AREA: - return "INTRA-AREA" - case LS_OSPF_ROUTE_TYPE_INTER_AREA: - return "INTER-AREA" - case LS_OSPF_ROUTE_TYPE_EXTERNAL1: - return "EXTERNAL1" - case LS_OSPF_ROUTE_TYPE_EXTERNAL2: - return "EXTERNAL2" - case LS_OSPF_ROUTE_TYPE_NSSA1: - return "NSSA1" - case LS_OSPF_ROUTE_TYPE_NSSA2: - return "NSSA2" - default: - return fmt.Sprintf("LsOspfRouteType(%d)", uint8(l)) - } -} - -type LsTLVOspfRouteType struct { - LsTLV - RouteType LsOspfRouteType -} - -func (l *LsTLVOspfRouteType) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_OSPF_ROUTE_TYPE { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.2.3.1 - if len(value) != 1 { - return malformedAttrListErr("Incorrect OSPF Route type length") - } - - if value[0] < byte(LS_OSPF_ROUTE_TYPE_INTRA_AREA) || value[0] > LS_OSPF_ROUTE_TYPE_NSSA2 { - return malformedAttrListErr("Incorrect OSPF Route type") - } - - l.RouteType = LsOspfRouteType(value[0]) - - return nil -} - -func (l *LsTLVOspfRouteType) Serialize() ([]byte, error) { - var buf [1]byte - buf[0] = byte(l.RouteType) - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVOspfRouteType) String() string { - return fmt.Sprintf("{OSPF Route Type: %v}", l.RouteType) -} - -func (l *LsTLVOspfRouteType) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - RouteType string `json:"ospf_route_type"` - }{ - Type: l.Type, - RouteType: l.RouteType.String(), - }) -} - -func (l *LsTLVOspfRouteType) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIPReachability struct { - LsTLV - PrefixLength uint8 - Prefix []byte -} - -func (l *LsTLVIPReachability) ToIPNet(ipv6 bool) net.IPNet { - b := make([]byte, 16) - for i := 0; i < int(((l.PrefixLength-1)/8)+1); i++ { - b[i] = l.Prefix[i] - } - - ip := net.IPv4(b[0], b[1], b[2], b[3]).To4() - if ipv6 { - ip = net.IP(b).To16() - } - - _, n, err := net.ParseCIDR(fmt.Sprintf("%v/%v", ip, l.PrefixLength)) - if err != nil { - return net.IPNet{} - } - - return *n -} - -func (l *LsTLVIPReachability) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IP_REACH_INFO { - return malformedAttrListErr("Unexpected TLV type") - } - - if len(value) < 2 { - return malformedAttrListErr("Incorrect IP reachability Info length") - } - - // https://tools.ietf.org/html/rfc7752#section-3.2.3.2 - if value[0] > 128 || value[0] == 0 { - return malformedAttrListErr("Incorrect IP prefix length") - } - - ll := int(((value[0] - 1) / 8) + 1) - if len(value[1:]) != ll { - return malformedAttrListErr("Malformed IP reachability TLV") - } - - l.PrefixLength = value[0] - l.Prefix = value[1 : 1+ll] - - return nil -} - -func (l *LsTLVIPReachability) Serialize() ([]byte, error) { - b := []byte{l.PrefixLength} - - return l.LsTLV.Serialize(append(b, l.Prefix...)) -} - -func (l *LsTLVIPReachability) String() string { - return fmt.Sprintf("{IP Reachability: %v/%v}", l.Prefix, l.PrefixLength) -} - -func (l *LsTLVIPReachability) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - PrefixLength uint8 `json:"prefix_length"` - Prefix string `json:"prefix"` - }{ - Type: l.Type, - PrefixLength: l.PrefixLength, - Prefix: fmt.Sprintf("%v", l.Prefix), - }) -} - -func (l *LsTLVIPReachability) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVAdminGroup struct { - LsTLV - AdminGroup uint32 -} - -func NewLsTLVAdminGroup(l *uint32) *LsTLVAdminGroup { - return &LsTLVAdminGroup{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - AdminGroup: *l, - } -} - -func (l *LsTLVAdminGroup) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_ADMIN_GROUP { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-3.1 - if len(value) != 4 { - return malformedAttrListErr("Incorrect Admin Group length") - } - - l.AdminGroup = binary.BigEndian.Uint32(value) - - return nil -} - -func (l *LsTLVAdminGroup) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.AdminGroup) - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVAdminGroup) String() string { - return fmt.Sprintf("{Admin Group: %08x}", l.AdminGroup) -} - -func (l *LsTLVAdminGroup) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - AdminGroup string `json:"admin_group"` - }{ - Type: l.Type, - AdminGroup: fmt.Sprintf("%08x", l.AdminGroup), - }) -} - -func (l *LsTLVAdminGroup) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVMaxLinkBw struct { - LsTLV - Bandwidth float32 -} - -func NewLsTLVMaxLinkBw(l *float32) *LsTLVMaxLinkBw { - return &LsTLVMaxLinkBw{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - Bandwidth: *l, - } -} - -func (l *LsTLVMaxLinkBw) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_MAX_LINK_BANDWIDTH { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-3.4 - if len(value) != 4 { - return malformedAttrListErr("Incorrect maximum link bandwidth length") - } - - l.Bandwidth = math.Float32frombits(binary.BigEndian.Uint32(value)) - - if l.Bandwidth < 0 || math.IsNaN(float64(l.Bandwidth)) || math.IsInf(float64(l.Bandwidth), 0) { - return malformedAttrListErr("Incorrect maximum link bandwidth value") - } - - return nil -} - -func (l *LsTLVMaxLinkBw) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], math.Float32bits(l.Bandwidth)) - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVMaxLinkBw) String() string { - return fmt.Sprintf("{Max Link BW: %v}", l.Bandwidth) -} - -func (l *LsTLVMaxLinkBw) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Bandwidth float32 `json:"max_link_bw"` - }{ - Type: l.Type, - Bandwidth: l.Bandwidth, - }) -} - -func (l *LsTLVMaxLinkBw) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVMaxReservableLinkBw struct { - LsTLV - Bandwidth float32 -} - -func NewLsTLVMaxReservableLinkBw(l *float32) *LsTLVMaxReservableLinkBw { - return &LsTLVMaxReservableLinkBw{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - Bandwidth: *l, - } -} - -func (l *LsTLVMaxReservableLinkBw) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_MAX_RESERVABLE_BANDWIDTH { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-3.5 - if len(value) != 4 { - return malformedAttrListErr("Incorrect maximum reservable link bandwidth length") - } - - l.Bandwidth = math.Float32frombits(binary.BigEndian.Uint32(value)) - - if l.Bandwidth < 0 || math.IsNaN(float64(l.Bandwidth)) || math.IsInf(float64(l.Bandwidth), 0) { - return malformedAttrListErr("Incorrect maximum reservable link bandwidth value") - } - - return nil -} - -func (l *LsTLVMaxReservableLinkBw) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], math.Float32bits(l.Bandwidth)) - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVMaxReservableLinkBw) String() string { - return fmt.Sprintf("{Max Reservable Link BW: %v}", l.Bandwidth) -} - -func (l *LsTLVMaxReservableLinkBw) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Bandwidth float32 `json:"max_reservable_link_bw"` - }{ - Type: l.Type, - Bandwidth: l.Bandwidth, - }) -} - -func (l *LsTLVMaxReservableLinkBw) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVUnreservedBw struct { - LsTLV - Bandwidth [8]float32 -} - -func NewLsTLVUnreservedBw(l *[8]float32) *LsTLVUnreservedBw { - return &LsTLVUnreservedBw{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 32, - }, - Bandwidth: *l, - } -} - -func (l *LsTLVUnreservedBw) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_UNRESERVED_BANDWIDTH { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc5305#section-3.6 - if len(value) != 32 { - return malformedAttrListErr("Incorrect unreserved bandwidth length") - } - - for i := 0; i < len(l.Bandwidth); i++ { - l.Bandwidth[i] = math.Float32frombits(binary.BigEndian.Uint32(value[:4])) - value = value[4:] - - if l.Bandwidth[i] < 0 || math.IsNaN(float64(l.Bandwidth[i])) || math.IsInf(float64(l.Bandwidth[i]), 0) { - return malformedAttrListErr("Incorrect unreserved bandwidth value") - } - } - - return nil -} - -func (l *LsTLVUnreservedBw) Serialize() ([]byte, error) { - buf := make([]byte, 0, 4*len(l.Bandwidth)) - - var b [4]byte - for i := 0; i < len(l.Bandwidth); i++ { - binary.BigEndian.PutUint32(b[:4], math.Float32bits(l.Bandwidth[i])) - buf = append(buf, b[:]...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVUnreservedBw) String() string { - return fmt.Sprintf("{Unreserved BW: %v}", l.Bandwidth) -} - -func (l *LsTLVUnreservedBw) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Bandwidth [8]float32 `json:"unreserved_bw"` - }{ - Type: l.Type, - Bandwidth: l.Bandwidth, - }) -} - -func (l *LsTLVUnreservedBw) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVTEDefaultMetric struct { - LsTLV - Metric uint32 -} - -func NewLsTLVTEDefaultMetric(l *uint32) *LsTLVTEDefaultMetric { - return &LsTLVTEDefaultMetric{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - Metric: *l, - } -} - -func (l *LsTLVTEDefaultMetric) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_TE_DEFAULT_METRIC { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.3.2.3 - if len(value) != 4 { - return malformedAttrListErr("Incorrect metric length length") - } - - l.Metric = binary.BigEndian.Uint32(value) - - return nil -} - -func (l *LsTLVTEDefaultMetric) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.Metric) - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVTEDefaultMetric) String() string { - return fmt.Sprintf("{TE Default metric: %d}", l.Metric) -} - -func (l *LsTLVTEDefaultMetric) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - DefaultMetric uint32 `json:"te_default_metric"` - }{ - Type: l.Type, - DefaultMetric: l.Metric, - }) -} - -func (l *LsTLVTEDefaultMetric) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIGPMetric struct { - LsTLV - Metric uint32 -} - -func NewLsTLVIGPMetric(l *uint32) *LsTLVIGPMetric { - return &LsTLVIGPMetric{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 3, // TODO: implementation for IS-IS small metrics and OSPF link metrics. - }, - Metric: *l, - } -} - -func (l *LsTLVIGPMetric) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IGP_METRIC { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.3.2.4 - switch len(value) { - case 1: - l.Metric = uint32(value[0] & 0x3F) - - case 2: - l.Metric = uint32(binary.BigEndian.Uint16(value)) - - case 3: - l.Metric = binary.BigEndian.Uint32([]byte{0, value[0], value[1], value[2]}) - - default: - return malformedAttrListErr("Incorrect metric length") - } - - return nil -} - -func (l *LsTLVIGPMetric) Serialize() ([]byte, error) { - switch l.Length { - case 1: - return l.LsTLV.Serialize([]byte{uint8(l.Metric) & 0x3F}) - - case 2: - var buf [2]byte - binary.BigEndian.PutUint16(buf[:2], uint16(l.Metric)) - return l.LsTLV.Serialize(buf[:]) - - case 3: - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.Metric) - return l.LsTLV.Serialize(buf[1:]) - - default: - return nil, malformedAttrListErr("Incorrect metric length") - } -} - -func (l *LsTLVIGPMetric) String() string { - return fmt.Sprintf("{IGP metric: %d}", l.Metric) -} - -func (l *LsTLVIGPMetric) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Metric uint32 `json:"igp_metric"` - }{ - Type: l.Type, - Metric: l.Metric, - }) -} - -func (l *LsTLVIGPMetric) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVLinkName struct { - LsTLV - Name string -} - -func NewLsTLVLinkName(l *string) *LsTLVLinkName { - return &LsTLVLinkName{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(len(*l)), - }, - Name: *l, - } -} - -func (l *LsTLVLinkName) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_LINK_NAME { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc7752#section-3.3.2.7 - if len(value) < 1 || len(value) > 255 { - return malformedAttrListErr("Incorrect Link Name") - } - - l.Name = string(value) - - return nil -} - -func (l *LsTLVLinkName) Serialize() ([]byte, error) { - return l.LsTLV.Serialize([]byte(l.Name)) -} - -func (l *LsTLVLinkName) String() string { - return fmt.Sprintf("{Link Name: %s}", l.Name) -} - -func (l *LsTLVLinkName) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Name string `json:"link_name"` - }{ - Type: l.Type, - Name: l.Name, - }) -} - -func (l *LsTLVLinkName) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVSrAlgorithm struct { - LsTLV - Algorithm []byte -} - -func NewLsTLVSrAlgorithm(l *[]byte) *LsTLVSrAlgorithm { - return &LsTLVSrAlgorithm{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(len(*l)), - }, - Algorithm: *l, - } -} - -func (l *LsTLVSrAlgorithm) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_SR_ALGORITHM { - return malformedAttrListErr("Unexpected TLV type") - } - - if len(value) < 1 { - return malformedAttrListErr("Incorrect SR algorithm length") - } - - l.Algorithm = value - - return nil -} - -func (l *LsTLVSrAlgorithm) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.Algorithm) -} - -func (l *LsTLVSrAlgorithm) String() string { - return fmt.Sprintf("{SR Algorithms: %v}", l.Algorithm) -} - -func (l *LsTLVSrAlgorithm) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Algorithms string `json:"sr_algorithm"` - }{ - Type: l.Type, - Algorithms: fmt.Sprintf("%v", l.Algorithm), - }) -} - -func (l *LsTLVSrAlgorithm) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsSrLabelRange struct { - Range uint32 - FirstLabel LsTLVSIDLabel -} - -type LsTLVSrCapabilities struct { - LsTLV - Flags uint8 - Ranges []LsSrLabelRange -} - -func NewLsTLVSrCapabilities(l *LsSrCapabilities) *LsTLVSrCapabilities { - var flags uint8 - if l.IPv4Supported { - flags = flags & (1 >> 0) - } - if l.IPv6Supported { - flags = flags & (1 >> 1) - } - ranges := []LsSrLabelRange{} - var length uint16 - for _, r := range l.Ranges { - ranges = append(ranges, LsSrLabelRange{ - Range: uint32(r.End - r.Begin), - FirstLabel: LsTLVSIDLabel{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - SID: r.Begin, - }, - }) - length += 4 - } - return &LsTLVSrCapabilities{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: length, - }, - Flags: flags, - Ranges: ranges, - } -} - -func (l *LsTLVSrCapabilities) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsSrRange struct { - Begin uint32 `json:"begin"` - End uint32 `json:"end"` -} - -type LsSrCapabilities struct { - IPv4Supported bool `json:"ipv4_supported"` - IPv6Supported bool `json:"ipv6_supported"` - Ranges []LsSrRange `json:"ranges"` -} - -func (l *LsTLVSrCapabilities) Extract() *LsSrCapabilities { - lsc := &LsSrCapabilities{ - IPv4Supported: (l.Flags & (1 << 0)) > 0, - IPv6Supported: (l.Flags & (1 << 1)) > 0, - } - - for _, r := range l.Ranges { - lsc.Ranges = append(lsc.Ranges, LsSrRange{ - Begin: r.FirstLabel.SID, - End: r.FirstLabel.SID + r.Range, - }) - } - - return lsc -} - -func (l *LsTLVSrCapabilities) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_SR_CAPABILITIES { - return malformedAttrListErr("Unexpected TLV type") - } - - if len(value) < 2 { - return malformedAttrListErr("Incorrect SR Capabilities length") - } - l.Flags = value[0] - - // Skip two bytes: flags and reserved. - value = value[2:] - - // The value field should be at least eight bytes long. Three bytes - // for the range size and five or six bytes for the SID/Label TLV. - for len(value) > 8 { - // First, parse range size (3 bytes) - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = value[i-1] - } - r := binary.BigEndian.Uint32(buf) - value = value[3:] - - // Second, parse SID/Label sub-TLV. - label := LsTLVSIDLabel{} - if err := label.DecodeFromBytes(value); err != nil { - return err - } - - l.Ranges = append(l.Ranges, LsSrLabelRange{ - Range: r, - FirstLabel: label, - }) - - value = value[label.Len():] - } - - if len(value) > 0 { - return malformedAttrListErr("Malformed SR Capabilities TLV") - } - - return nil -} - -func (l *LsTLVSrCapabilities) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, 0) - var b [4]byte - - for _, r := range l.Ranges { - binary.BigEndian.PutUint32(b[:4], r.Range) - buf = append(buf, b[1:]...) - ser, err := r.FirstLabel.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, ser...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVSrCapabilities) String() string { - var buf bytes.Buffer - - for _, r := range l.Ranges { - buf.WriteString(fmt.Sprintf("%v:%v ", r.FirstLabel.SID, r.FirstLabel.SID+r.Range)) - } - - return fmt.Sprintf("{SR Capabilities: Flags:%v SRGB Ranges: %v}", l.Flags, buf.String()) -} - -func (l *LsTLVSrCapabilities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Flags uint8 `json:"flags"` - Ranges []LsSrLabelRange `json:"ranges"` - }{ - Type: l.Type, - Flags: l.Flags, - Ranges: l.Ranges, - }) -} - -type LsTLVSrLocalBlock struct { - LsTLV - Flags uint8 - Ranges []LsSrLabelRange -} - -type LsSrLocalBlock struct { - Ranges []LsSrRange `json:"ranges"` -} - -func NewLsTLVSrLocalBlock(l *LsSrLocalBlock) *LsTLVSrLocalBlock { - var flags uint8 // - ranges := []LsSrLabelRange{} - var length uint16 - for _, r := range l.Ranges { - ranges = append(ranges, LsSrLabelRange{ - Range: uint32(r.End - r.Begin), - FirstLabel: LsTLVSIDLabel{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 4, - }, - SID: r.Begin, - }, - }) - length += 4 - } - return &LsTLVSrLocalBlock{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: length, - }, - Flags: flags, // MUST be set 0. (RFC9085 2.1.4) - Ranges: ranges, - } -} - -func (l *LsTLVSrLocalBlock) Extract() *LsSrLocalBlock { - lb := &LsSrLocalBlock{} - - for _, r := range l.Ranges { - lb.Ranges = append(lb.Ranges, LsSrRange{ - Begin: r.FirstLabel.SID, - End: r.FirstLabel.SID + r.Range, - }) - } - - return lb -} - -func (l *LsTLVSrLocalBlock) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_SR_LOCAL_BLOCK { - return malformedAttrListErr("Unexpected TLV type") - } - - if len(value) < 2 { - return malformedAttrListErr("Incorrect SR Local Block length") - } - l.Flags = value[0] - - // Skip two bytes: flags and reserved. - value = value[2:] - - // The value field should be at least eight bytes long. Three bytes - // for the range size and five or six bytes for the SID/Label TLV. - for len(value) > 8 { - // First, parse range size (3 bytes) - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = value[i-1] - } - r := binary.BigEndian.Uint32(buf) - value = value[3:] - - // Second, parse SID/Label sub-TLV. - label := LsTLVSIDLabel{} - if err := label.DecodeFromBytes(value); err != nil { - return err - } - - l.Ranges = append(l.Ranges, LsSrLabelRange{ - Range: r, - FirstLabel: label, - }) - - value = value[label.Len():] - } - - if len(value) > 0 { - return malformedAttrListErr("Malformed SR Local Block TLV") - } - - return nil -} - -func (l *LsTLVSrLocalBlock) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, 0) - var b [4]byte - - for _, r := range l.Ranges { - binary.BigEndian.PutUint32(b[:4], r.Range) - buf = append(buf, b[1:]...) - ser, err := r.FirstLabel.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, ser...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVSrLocalBlock) String() string { - var buf bytes.Buffer - - for _, r := range l.Ranges { - buf.WriteString(fmt.Sprintf("%v:%v ", r.FirstLabel.SID, r.FirstLabel.SID+r.Range)) - } - - return fmt.Sprintf("{SR LocalBlock: Flags:%v SRGB Ranges: %v}", l.Flags, buf.String()) -} - -func (l *LsTLVSrLocalBlock) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Flags uint8 `json:"flags"` - Ranges []LsSrLabelRange `json:"ranges"` - }{ - Type: l.Type, - Flags: l.Flags, - Ranges: l.Ranges, - }) -} - -func (l *LsTLVSrLocalBlock) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVAdjacencySID struct { - LsTLV - Flags uint8 - Weight uint8 - SID uint32 -} - -func NewLsTLVAdjacencySID(l *uint32) *LsTLVAdjacencySID { - var flags uint8 - return &LsTLVAdjacencySID{ - LsTLV: LsTLV{ - Type: LS_TLV_ADJACENCY_SID, - Length: 7, // TODO: Implementation to judge 7 octets or 8 octets - }, - Flags: flags, - Weight: 0, // TODO: Implementation for IGP - SID: *l, // TODO: Implementation for IGP - } -} - -func (l *LsTLVAdjacencySID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_ADJACENCY_SID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/draft-ietf-idr-bgp-ls-segment-routing-ext-08#section-2.2.1 - if len(value) != 7 && len(value) != 8 { - return malformedAttrListErr("Incorrect Adjacency SID length") - } - - l.Flags = value[0] - l.Weight = value[1] - - v := value[4:] - if len(v) == 4 { - l.SID = binary.BigEndian.Uint32(v) - } else { - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = v[i-1] - } - // Label is represented by 20 rightmost bits. - l.SID = binary.BigEndian.Uint32(buf) & 0xfffff - } - - return nil -} - -func (l *LsTLVAdjacencySID) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, l.Weight) - // Reserved - buf = append(buf, []byte{0, 0}...) - - var b [4]byte - binary.BigEndian.PutUint32(b[:4], l.SID) - - if l.Length == 7 { - return l.LsTLV.Serialize(append(buf, b[1:]...)) - } - - return l.LsTLV.Serialize(append(buf, b[:]...)) -} - -func (l *LsTLVAdjacencySID) String() string { - return fmt.Sprintf("{Adjacency SID: %v}", l.SID) -} - -func (l *LsTLVAdjacencySID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SID uint32 `json:"adjacency_sid"` - }{ - Type: l.Type, - SID: l.SID, - }) -} - -func (l *LsTLVAdjacencySID) GetLsTLV() LsTLV { - return l.LsTLV -} - -// https://tools.ietf.org/html/rfc9086#section-5 -type LsAttributeBgpPeerSegmentSIDFlags struct { - Value bool `json:"value"` - Local bool `json:"local"` - Backup bool `json:"backup"` - Persistent bool `json:"persistent"` -} - -func (l *LsAttributeBgpPeerSegmentSIDFlags) FlagBits() uint8 { - var flags uint8 - if l.Value { - flags = flags | (1 << 7) - } - if l.Local { - flags = flags | (1 << 6) - } - if l.Backup { - flags = flags | (1 << 5) - } - if l.Persistent { - flags = flags | (1 << 4) - } - return flags -} - -func (l *LsAttributeBgpPeerSegmentSIDFlags) SidLen() uint16 { - // https://tools.ietf.org/html/rfc9086#section-5 - if l.Value { - return 7 - } else { - return 8 - } -} - -func NewLsBgpPeerSegmentSIDFlag(v uint8) LsAttributeBgpPeerSegmentSIDFlags { - return LsAttributeBgpPeerSegmentSIDFlags{ - Value: (v & (1 << 7)) > 0, - Local: (v & (1 << 6)) > 0, - Backup: (v & (1 << 5)) > 0, - Persistent: (v & (1 << 4)) > 0, - } -} - -type LsBgpPeerSegmentSID struct { - Flags LsAttributeBgpPeerSegmentSIDFlags `json:"flags"` - Weight uint8 `json:"weight"` - SID uint32 `json:"sid"` -} - -type LsTLVPeerNodeSID struct { - LsTLV - Flags uint8 - Weight uint8 - SID uint32 -} - -func NewLsTLVPeerNodeSID(l *LsBgpPeerSegmentSID) *LsTLVPeerNodeSID { - return &LsTLVPeerNodeSID{ - LsTLV: LsTLV{ - Type: LS_TLV_PEER_NODE_SID, - Length: l.Flags.SidLen(), - }, - Flags: l.Flags.FlagBits(), - Weight: l.Weight, - SID: l.SID, - } -} - -func (l *LsTLVPeerNodeSID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_PEER_NODE_SID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc9086#section-5 - if len(value) != 7 && len(value) != 8 { - return malformedAttrListErr("Incorrect Peer Node SID length") - } - - l.Flags = value[0] - l.Weight = value[1] - - v := value[4:] - if len(v) == 4 { - l.SID = binary.BigEndian.Uint32(v) - } else { - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = v[i-1] - } - // Label is represented by 20 rightmost bits. - l.SID = binary.BigEndian.Uint32(buf) & 0xfffff - } - - return nil -} - -func (l *LsTLVPeerNodeSID) Extract() *LsBgpPeerSegmentSID { - return &LsBgpPeerSegmentSID{ - Flags: NewLsBgpPeerSegmentSIDFlag(l.Flags), - Weight: l.Weight, - SID: l.SID, - } -} - -func (l *LsTLVPeerNodeSID) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, l.Weight) - // Reserved - buf = append(buf, []byte{0, 0}...) - - var b [4]byte - binary.BigEndian.PutUint32(b[:4], l.SID) - - if l.Length == 7 { - return l.LsTLV.Serialize(append(buf, b[1:]...)) - } - - return l.LsTLV.Serialize(append(buf, b[:]...)) -} - -func (l *LsTLVPeerNodeSID) String() string { - return fmt.Sprintf("{Peer Node SID: %v}", l.SID) -} - -func (l *LsTLVPeerNodeSID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SID uint32 `json:"peer_node_sid"` - }{ - Type: l.Type, - SID: l.SID, - }) -} - -func (l *LsTLVPeerNodeSID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVPeerAdjacencySID struct { - LsTLV - Flags uint8 - Weight uint8 - SID uint32 -} - -func NewLsTLVPeerAdjacencySID(l *LsBgpPeerSegmentSID) *LsTLVPeerAdjacencySID { - return &LsTLVPeerAdjacencySID{ - LsTLV: LsTLV{ - Type: LS_TLV_ADJACENCY_SID, - Length: l.Flags.SidLen(), - }, - Flags: l.Flags.FlagBits(), - Weight: l.Weight, - SID: l.SID, - } -} - -func (l *LsTLVPeerAdjacencySID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_PEER_ADJACENCY_SID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc9086#section-5 - if len(value) != 7 && len(value) != 8 { - return malformedAttrListErr("Incorrect Peer Adjacency SID length") - } - - l.Flags = value[0] - l.Weight = value[1] - - v := value[4:] - if len(v) == 4 { - l.SID = binary.BigEndian.Uint32(v) - } else { - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = v[i-1] - } - // Label is represented by 20 rightmost bits. - l.SID = binary.BigEndian.Uint32(buf) & 0xfffff - } - - return nil -} - -func (l *LsTLVPeerAdjacencySID) Extract() *LsBgpPeerSegmentSID { - return &LsBgpPeerSegmentSID{ - Flags: NewLsBgpPeerSegmentSIDFlag(l.Flags), - Weight: l.Weight, - SID: l.SID, - } -} - -func (l *LsTLVPeerAdjacencySID) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, l.Weight) - // Reserved - buf = append(buf, []byte{0, 0}...) - - var b [4]byte - binary.BigEndian.PutUint32(b[:4], l.SID) - - if l.Length == 7 { - return l.LsTLV.Serialize(append(buf, b[1:]...)) - } - - return l.LsTLV.Serialize(append(buf, b[:]...)) -} - -func (l *LsTLVPeerAdjacencySID) String() string { - return fmt.Sprintf("{Peer Adjacency SID: %v}", l.SID) -} - -func (l *LsTLVPeerAdjacencySID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SID uint32 `json:"peer_adjacency_sid"` - }{ - Type: l.Type, - SID: l.SID, - }) -} - -func (l *LsTLVPeerAdjacencySID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVPeerSetSID struct { - LsTLV - Flags uint8 - Weight uint8 - SID uint32 -} - -func NewLsTLVPeerSetSID(l *LsBgpPeerSegmentSID) *LsTLVPeerSetSID { - return &LsTLVPeerSetSID{ - LsTLV: LsTLV{ - Type: LS_TLV_PEER_SET_SID, - Length: l.Flags.SidLen(), - }, - Flags: l.Flags.FlagBits(), - Weight: l.Weight, - SID: l.SID, - } -} - -func (l *LsTLVPeerSetSID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_PEER_SET_SID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/rfc9086#section-5 - if len(value) != 7 && len(value) != 8 { - return malformedAttrListErr("Incorrect Peer Set SID length") - } - - l.Flags = value[0] - l.Weight = value[1] - - v := value[4:] - if len(v) == 4 { - l.SID = binary.BigEndian.Uint32(v) - } else { - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = v[i-1] - } - // Label is represented by 20 rightmost bits. - l.SID = binary.BigEndian.Uint32(buf) & 0xfffff - } - - return nil -} - -func (l *LsTLVPeerSetSID) Extract() *LsBgpPeerSegmentSID { - return &LsBgpPeerSegmentSID{ - Flags: NewLsBgpPeerSegmentSIDFlag(l.Flags), - Weight: l.Weight, - SID: l.SID, - } -} - -func (l *LsTLVPeerSetSID) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, l.Weight) - // Reserved - buf = append(buf, []byte{0, 0}...) - - var b [4]byte - binary.BigEndian.PutUint32(b[:4], l.SID) - - if l.Length == 7 { - return l.LsTLV.Serialize(append(buf, b[1:]...)) - } - - return l.LsTLV.Serialize(append(buf, b[:]...)) -} - -func (l *LsTLVPeerSetSID) String() string { - return fmt.Sprintf("{Peer Set SID: %v}", l.SID) -} - -func (l *LsTLVPeerSetSID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SID uint32 `json:"peer_set_sid"` - }{ - Type: l.Type, - SID: l.SID, - }) -} - -func (l *LsTLVPeerSetSID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVSIDLabel struct { - LsTLV - SID uint32 -} - -func (l *LsTLVSIDLabel) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_SID_LABEL_TLV { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/draft-ietf-idr-bgp-ls-segment-routing-ext-08#section-2.1.1 - if len(value) != 4 && len(value) != 3 { - return malformedAttrListErr("Incorrect SID length") - } - - if len(value) == 4 { - l.SID = binary.BigEndian.Uint32(value) - } else { - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = value[i-1] - } - // Label is represented by 20 rightmost bits. - l.SID = binary.BigEndian.Uint32(buf) & 0xfffff - } - - return nil -} - -func (l *LsTLVSIDLabel) Serialize() ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], l.SID) - - if l.Length == 3 { - return l.LsTLV.Serialize(buf[1:]) - } - - return l.LsTLV.Serialize(buf[:]) -} - -func (l *LsTLVSIDLabel) String() string { - return fmt.Sprintf("{SID/Label: %v}", l.SID) -} - -func (l *LsTLVSIDLabel) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SID uint32 `json:"sid_label"` - }{ - Type: l.Type, - SID: l.SID, - }) -} - -type LsTLVPrefixSID struct { - LsTLV - Flags uint8 - Algorithm uint8 - SID uint32 -} - -func NewLsTLVPrefixSID(l *uint32) *LsTLVPrefixSID { - var flags uint8 - return &LsTLVPrefixSID{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 0, - }, - Flags: flags, // TODO: Implementation for IGP - Algorithm: 0, // TODO: Implementation for IGP - SID: *l, - } -} - -func (l *LsTLVPrefixSID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_PREFIX_SID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/draft-ietf-idr-bgp-ls-segment-routing-ext-08#section-2.3.1 - if len(value) != 7 && len(value) != 8 { - return malformedAttrListErr("Incorrect Prefix SID length") - } - - l.Flags = value[0] - l.Algorithm = value[1] - - // Flags (1) + Algorithm (1) + Reserved (2) - v := value[4:] - if len(v) == 4 { - l.SID = binary.BigEndian.Uint32(v) - } else { - buf := []byte{0, 0, 0, 0} - for i := 1; i < len(buf); i++ { - buf[i] = v[i-1] - } - // Label is represented by 20 rightmost bits. - l.SID = binary.BigEndian.Uint32(buf) & 0xfffff - } - - return nil -} - -func (l *LsTLVPrefixSID) Serialize() ([]byte, error) { - buf := make([]byte, 0) - buf = append(buf, l.Flags) - buf = append(buf, l.Algorithm) - // Reserved - buf = append(buf, []byte{0, 0}...) - - var b [4]byte - binary.BigEndian.PutUint32(b[:4], l.SID) - - if l.Length == 7 { - return l.LsTLV.Serialize(append(buf, b[1:]...)) - } - - return l.LsTLV.Serialize(append(buf, b[:]...)) -} - -func (l *LsTLVPrefixSID) String() string { - return fmt.Sprintf("{Prefix SID: %v}", l.SID) -} - -func (l *LsTLVPrefixSID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - SID uint32 `json:"prefix_sid"` - }{ - Type: l.Type, - SID: l.SID, - }) -} - -func (l *LsTLVPrefixSID) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVSourceRouterID struct { - LsTLV - RouterID []byte -} - -func (l *LsTLVSourceRouterID) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_SOURCE_ROUTER_ID { - return malformedAttrListErr("Unexpected TLV type") - } - - // https://tools.ietf.org/html/draft-ietf-idr-bgp-ls-segment-routing-ext-08#section-2.3.3 - if len(value) != 4 && len(value) != 16 { - return malformedAttrListErr("Incorrect Source Router ID length") - } - - l.RouterID = value - - return nil -} - -func (l *LsTLVSourceRouterID) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.RouterID) -} - -func (l *LsTLVSourceRouterID) String() string { - return fmt.Sprintf("{Source Router ID: %v}", net.IP(l.RouterID)) -} - -func (l *LsTLVSourceRouterID) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - RouterID string `json:"source_router_id"` - }{ - Type: l.Type, - RouterID: fmt.Sprintf("%v", net.IP(l.RouterID)), - }) -} - -type LsTLVOpaqueLinkAttr struct { - LsTLV - Attr []byte -} - -func NewLsTLVOpaqueLinkAttr(l *[]byte) *LsTLVOpaqueLinkAttr { - return &LsTLVOpaqueLinkAttr{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(len(*l)), - }, - Attr: *l, - } -} - -func (l *LsTLVOpaqueLinkAttr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_OPAQUE_LINK_ATTR { - return malformedAttrListErr("Unexpected TLV type") - } - - l.Attr = value - - return nil -} - -func (l *LsTLVOpaqueLinkAttr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.Attr) -} - -func (l *LsTLVOpaqueLinkAttr) String() string { - return fmt.Sprintf("{Opaque link attribute: %v}", l.Attr) -} - -func (l *LsTLVOpaqueLinkAttr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"link_opaque_attribute"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.Attr), - }) -} - -func (l LsTLVOpaqueLinkAttr) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVSrlg struct { - LsTLV - Srlgs []uint32 -} - -func NewLsTLVSrlg(l *[]uint32) *LsTLVSrlg { - return &LsTLVSrlg{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: uint16(4 * len(*l)), - }, - Srlgs: *l, - } -} - -func (l *LsTLVSrlg) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_SRLG { - return malformedAttrListErr("Unexpected TLV type") - } - - if len(value)%4 != 0 { - return malformedAttrListErr("Incorrect SRLG length") - } - - for len(value) > 0 { - l.Srlgs = append(l.Srlgs, binary.BigEndian.Uint32(value[:4])) - value = value[4:] - } - - return nil -} - -func (l *LsTLVSrlg) Serialize() ([]byte, error) { - buf := make([]byte, 0, 4*len(l.Srlgs)) - - var b [4]byte - for i := 0; i < len(l.Srlgs); i++ { - binary.BigEndian.PutUint32(b[:4], l.Srlgs[i]) - buf = append(buf, b[:]...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVSrlg) String() string { - return fmt.Sprintf("{SRLG link attribute: %d}", l.Srlgs) -} - -func (l *LsTLVSrlg) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value []uint32 `json:"link_srlg_attribute"` - }{ - Type: l.Type, - Value: l.Srlgs, - }) -} - -func (l *LsTLVSrlg) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVIGPFlags struct { - LsTLV - Flags uint8 -} - -func NewLsTLVIGPFlags(l *LsIGPFlags) *LsTLVIGPFlags { - var flags uint8 - if l.Down { - flags = flags & (1 >> 0) - } - if l.NoUnicast { - flags = flags & (1 >> 1) - } - if l.LocalAddress { - flags = flags & (1 >> 2) - } - if l.PropagateNSSA { - flags = flags & (1 >> 3) - } - return &LsTLVIGPFlags{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 1, - }, - Flags: flags, - } -} - -// https://tools.ietf.org/html/rfc7752#section-3.3.3.1 -type LsIGPFlags struct { - Down bool `json:"down"` - NoUnicast bool `json:"no_unicast"` - LocalAddress bool `json:"local_address"` - PropagateNSSA bool `json:"propagate_nssa"` -} - -func (l *LsTLVIGPFlags) Extract() *LsIGPFlags { - return &LsIGPFlags{ - Down: (l.Flags & (1 << 0)) > 0, - NoUnicast: (l.Flags & (1 << 1)) > 0, - LocalAddress: (l.Flags & (1 << 2)) > 0, - PropagateNSSA: (l.Flags & (1 << 3)) > 0, - } -} - -func (l *LsTLVIGPFlags) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_IGP_FLAGS { - return malformedAttrListErr("Unexpected TLV type") - } - - if l.Length != 1 { - return malformedAttrListErr("Node Flag Bits TLV malformed") - } - - l.Flags = value[0] - - return nil -} - -func (l *LsTLVIGPFlags) Serialize() ([]byte, error) { - return l.LsTLV.Serialize([]byte{l.Flags}) -} - -func (l *LsTLVIGPFlags) String() string { - flags := "XXXXPLND" - - var buf bytes.Buffer - - for i := 0; i < len(flags); i++ { - if l.Flags&(1< 0 { - buf.WriteString(flags[i : i+1]) - } else { - buf.WriteString("*") - } - } - - return fmt.Sprintf("{IGP Flags: %s}", buf.String()) -} - -func (l *LsTLVIGPFlags) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Flags string `json:"igp_flags"` - }{ - Type: l.Type, - Flags: l.String(), - }) -} - -func (l *LsTLVIGPFlags) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVOpaquePrefixAttr struct { - LsTLV - Attr []byte -} - -func NewLsTLVOpaquePrefixAttr(l *[]byte) *LsTLVOpaquePrefixAttr { - return &LsTLVOpaquePrefixAttr{ - LsTLV: LsTLV{ - Type: BGP_ASPATH_ATTR_TYPE_SET, - Length: 0, - }, - Attr: *l, - } -} - -func (l *LsTLVOpaquePrefixAttr) DecodeFromBytes(data []byte) error { - value, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_OPAQUE_PREFIX_ATTR { - return malformedAttrListErr("Unexpected TLV type") - } - - l.Attr = value - - return nil -} - -func (l *LsTLVOpaquePrefixAttr) Serialize() ([]byte, error) { - return l.LsTLV.Serialize(l.Attr) -} - -func (l *LsTLVOpaquePrefixAttr) String() string { - return fmt.Sprintf("{Prefix opaque attribute: %v}", l.Attr) -} - -func (l *LsTLVOpaquePrefixAttr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - Value string `json:"prefix_opaque_attribute"` - }{ - Type: l.Type, - Value: fmt.Sprintf("%v", l.Attr), - }) -} - -func (l *LsTLVOpaquePrefixAttr) GetLsTLV() LsTLV { - return l.LsTLV -} - -type LsTLVNodeDescriptor struct { - LsTLV - SubTLVs []LsTLVInterface -} - -func (l *LsTLVNodeDescriptor) DecodeFromBytes(data []byte) error { - tlv, err := l.LsTLV.DecodeFromBytes(data) - if err != nil { - return err - } - - if l.Type != LS_TLV_LOCAL_NODE_DESC && l.Type != LS_TLV_REMOTE_NODE_DESC { - return malformedAttrListErr("Unexpected TLV type") - } - - // RFC7752, 3.2.1.4 - // There can be at most one instance of each sub-TLV type present in - // any Node Descriptor. The sub-TLVs within a Node Descriptor MUST - // be arranged in ascending order by sub-TLV type. - prevType := uint16(0) - m := make(map[LsTLVType]bool) - - for len(tlv) >= tlvHdrLen { - sub := &LsTLV{} - _, err := sub.DecodeFromBytes(tlv) - if err != nil { - return err - } - - if uint16(sub.Type) < prevType { - return malformedAttrListErr("Incorrect TLV order") - } - if _, ok := m[sub.Type]; ok { - return malformedAttrListErr("Duplicate TLV") - } - prevType = uint16(sub.Type) - m[sub.Type] = true - - var subTLV LsTLVInterface - switch sub.Type { - case LS_TLV_AS: - subTLV = &LsTLVAutonomousSystem{} - case LS_TLV_BGP_LS_ID: - subTLV = &LsTLVBgpLsID{} - case LS_TLV_OSPF_AREA: - subTLV = &LsTLVOspfAreaID{} - case LS_TLV_IGP_ROUTER_ID: - subTLV = &LsTLVIgpRouterID{} - case LS_TLV_BGP_ROUTER_ID: - subTLV = &LsTLVBgpRouterID{} - case LS_TLV_BGP_CONFEDERATION_MEMBER: - subTLV = &LsTLVBgpConfederationMember{} - - default: - tlv = tlv[sub.Len():] - l.Length -= uint16(sub.Len()) - continue - } - - if err := subTLV.DecodeFromBytes(tlv); err != nil { - return err - } - l.SubTLVs = append(l.SubTLVs, subTLV) - tlv = tlv[subTLV.Len():] - } - - _, lsTLVIgpRouterIDExists := m[LS_TLV_IGP_ROUTER_ID] - _, lsTLVBgpRouterIDExists := m[LS_TLV_BGP_ROUTER_ID] - _, lsTLVAutonomousSystemExists := m[LS_TLV_AS] - - if !(lsTLVIgpRouterIDExists || (lsTLVBgpRouterIDExists && lsTLVAutonomousSystemExists)) { - return malformedAttrListErr("Required TLV missing") - } - - return nil -} - -func (l *LsTLVNodeDescriptor) Extract() *LsNodeDescriptor { - nd := &LsNodeDescriptor{} - - for _, tlv := range l.SubTLVs { - switch v := tlv.(type) { - case *LsTLVAutonomousSystem: - nd.Asn = v.ASN - case *LsTLVBgpLsID: - nd.BGPLsID = v.BGPLsID - case *LsTLVOspfAreaID: - nd.OspfAreaID = v.AreaID - case *LsTLVIgpRouterID: - nd.IGPRouterID, nd.PseudoNode = parseIGPRouterID(v.RouterID) - case *LsTLVBgpRouterID: - nd.BGPRouterID = v.RouterID - case *LsTLVBgpConfederationMember: - nd.BGPConfederationMember = v.BgpConfederationMember - } - } - - return nd -} - -func (l *LsTLVNodeDescriptor) Serialize() ([]byte, error) { - buf := []byte{} - for _, tlv := range l.SubTLVs { - ser, err := tlv.Serialize() - if err != nil { - return nil, err - } - - buf = append(buf, ser...) - } - - return l.LsTLV.Serialize(buf) -} - -func (l *LsTLVNodeDescriptor) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsTLVType `json:"type"` - LsNodeDescriptor - }{ - l.Type, - *l.Extract(), - }) -} - -func (l *LsTLVNodeDescriptor) String() string { - nd := l.Extract() - - return nd.String() -} - -type LsNodeDescriptor struct { - Asn uint32 `json:"asn"` - BGPLsID uint32 `json:"bgp_ls_id"` - OspfAreaID uint32 `json:"ospf_area_id"` - PseudoNode bool `json:"pseudo_node"` - IGPRouterID string `json:"igp_router_id"` - BGPRouterID net.IP `json:"bgp_router_id"` - BGPConfederationMember uint32 `json:"bgp_confederation_member"` -} - -func (l *LsTLVNodeDescriptor) GetLsTLV() LsTLV { - return l.LsTLV -} - -func (l *LsNodeDescriptor) String() string { - - if l.BGPRouterID == nil { - return fmt.Sprintf("{ASN: %v, BGP LS ID: %v, OSPF AREA: %v, IGP ROUTER ID: %v}", l.Asn, l.BGPLsID, l.OspfAreaID, l.IGPRouterID) - } - - return fmt.Sprintf("{ASN: %v, BGP LS ID: %v, BGP ROUTER ID: %v}", l.Asn, l.BGPLsID, l.BGPRouterID) -} - -func parseIGPRouterID(id []byte) (string, bool) { - switch len(id) { - // OSPF or OSPFv3 non-pseudonode - case 4: - return net.IP(id).String(), false - - // ISIS non-pseudonode - case 6: - return fmt.Sprintf("%0.2x%0.2x.%0.2x%0.2x.%0.2x%0.2x", id[0], id[1], id[2], id[3], id[4], id[5]), false - - // ISIS pseudonode - case 7: - return fmt.Sprintf("%0.2x%0.2x.%0.2x%0.2x.%0.2x%0.2x-%0.2x", id[0], id[1], id[2], id[3], id[4], id[5], id[6]), true - - // OSPF or OSPFv3 pseudonode - case 8: - return fmt.Sprintf("%v:%v", net.IP(id[:4]).String(), net.IP(id[4:]).String()), true - - default: - return fmt.Sprintf("%v", id), false - } -} - -// Generate LsTLVNodeDescriptor from LsNodeDescriptor -func NewLsTLVNodeDescriptor(nd *LsNodeDescriptor, tlvType LsTLVType) LsTLVNodeDescriptor { - // The sub-TLVs within a Node Descriptor MUST be arranged in ascending order by sub-TLV type. - subTLVs := []LsTLVInterface{} - - // TLV Code Point 512 Autonomous System - // ASN 0 is invalid. - if nd.Asn != 0 { - subTLVs = append(subTLVs, - &LsTLVAutonomousSystem{ - LsTLV: LsTLV{ - Type: LS_TLV_AS, - Length: 4, // 4 is the only valid value. - }, - ASN: nd.Asn, - }) - } - - // For IGP - if nd.IGPRouterID != "" { - routerIdBytes := []byte(nd.IGPRouterID) - routerIdLength := len([]byte(nd.IGPRouterID)) - isOspf := false - // OSPF/OSPFv3 non-pseudonode or pseudonode - if routerIdLength == 4 || routerIdLength == 8 { - isOspf = true - } - if isOspf { - // TLV Code Point 514 OSPF Area-ID - subTLVs = append(subTLVs, - &LsTLVOspfAreaID{ - LsTLV: LsTLV{ - Type: LS_TLV_OSPF_AREA, - Length: 4, // 4 is the only valid value. - }, - AreaID: nd.OspfAreaID, - }) - } - // TLV Code Point 515 IGP Router-ID - subTLVs = append(subTLVs, - &LsTLVIgpRouterID{ - LsTLV: LsTLV{ - Type: LS_TLV_IGP_ROUTER_ID, - Length: uint16(routerIdLength), - }, - RouterID: routerIdBytes, - }) - } - - // For BGP - // TLV Code Point 516 BGP Router-ID - if nd.BGPRouterID != nil { - subTLVs = append(subTLVs, - &LsTLVBgpRouterID{ - LsTLV: LsTLV{ - Type: LS_TLV_BGP_ROUTER_ID, - Length: 4, // 4 is the only valid value. - }, - RouterID: nd.BGPRouterID, - }) - if nd.BGPConfederationMember != 0 { - subTLVs = append(subTLVs, - &LsTLVBgpConfederationMember{ - LsTLV: LsTLV{ - Type: LS_TLV_BGP_CONFEDERATION_MEMBER, - Length: 4, // 4 is the only valid value. - }, - BgpConfederationMember: nd.BGPConfederationMember, - }) - } - } - - subTLVs = append(subTLVs, - &LsTLVBgpLsID{ - LsTLV: LsTLV{ - Type: LS_TLV_BGP_LS_ID, - Length: 4, // 4 is the only valid value. - }, - BGPLsID: nd.BGPLsID, - }) - - sort.Slice(subTLVs, func(i, j int) bool { - return subTLVs[i].GetLsTLV().Type < subTLVs[j].GetLsTLV().Type - }) - - ndLength := 0 - for _, val := range subTLVs { - ndLength += val.Len() - } - - return LsTLVNodeDescriptor{ - LsTLV: LsTLV{ - Type: tlvType, // LocalNodeDesc - Length: uint16(ndLength), - }, - SubTLVs: subTLVs, - } -} - -type LsAddrPrefix struct { - PrefixDefault - Type LsNLRIType - Length uint16 - NLRI LsNLRIInterface -} - -func (l *LsAddrPrefix) AFI() uint16 { - return AFI_LS -} - -func (l *LsAddrPrefix) SAFI() uint8 { - return SAFI_LS -} - -func (l *LsAddrPrefix) Len(...*MarshallingOption) int { - return int(4 + l.Length) -} - -func (l *LsAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if len(data) < 4 { - return malformedAttrListErr("Malformed BGP-LS Address Prefix") - } - - l.Type = LsNLRIType(binary.BigEndian.Uint16(data[:2])) - l.Length = binary.BigEndian.Uint16(data[2:4]) - - switch l.Type { - case LS_NLRI_TYPE_NODE: - node := &LsNodeNLRI{} - node.Length = l.Length - node.NLRIType = LS_NLRI_TYPE_NODE - l.NLRI = node - - case LS_NLRI_TYPE_LINK: - link := &LsLinkNLRI{} - link.Length = l.Length - link.NLRIType = LS_NLRI_TYPE_LINK - l.NLRI = link - - case LS_NLRI_TYPE_PREFIX_IPV4: - prefixv4 := &LsPrefixV4NLRI{} - prefixv4.Length = l.Length - prefixv4.NLRIType = LS_NLRI_TYPE_PREFIX_IPV4 - l.NLRI = prefixv4 - - case LS_NLRI_TYPE_PREFIX_IPV6: - prefixv6 := &LsPrefixV6NLRI{} - prefixv6.Length = l.Length - prefixv6.NLRIType = LS_NLRI_TYPE_PREFIX_IPV4 - l.NLRI = prefixv6 - - // TODO: LS_NLRI_TYPE_SR_POLICY_CANDIDATE_PATH - - case LS_NLRI_TYPE_SRV6_SID: - srv6sid := &LsSrv6SIDNLRI{} - srv6sid.Length = l.Length - srv6sid.NLRIType = LS_NLRI_TYPE_SRV6_SID - l.NLRI = srv6sid - - default: - return malformedAttrListErr("Unsupported BGP-LS NLRI") - } - - if l.NLRI != nil { - return l.NLRI.DecodeFromBytes(data[4:]) - } - - return nil -} - -func (l *LsAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - if l.NLRI == nil { - return nil, errors.New("empty NLRI") - } - - ser, err := l.NLRI.Serialize() - if err != nil { - return nil, err - } - - buf := make([]byte, 4+len(ser)) - binary.BigEndian.PutUint16(buf[:2], uint16(l.Type)) - binary.BigEndian.PutUint16(buf[2:4], uint16(len(ser))) - copy(buf[4:], ser) - - return buf, nil -} - -func (l *LsAddrPrefix) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type LsNLRIType `json:"type"` - Length uint16 `json:"length"` - NLRI string `json:"nlri"` - }{ - l.Type, - l.Length, - l.String(), - }) -} - -func (l *LsAddrPrefix) String() string { - if l.NLRI == nil { - return "NLRI: (nil)" - } - - return "NLRI { " + l.NLRI.String() + " }" -} - -func (l *LsAddrPrefix) Flat() map[string]string { - return map[string]string{} -} - -type LsAttributeNode struct { - Flags *LsNodeFlags `json:"flags,omitempty"` - Opaque *[]byte `json:"opaque,omitempty"` - Name *string `json:"name,omitempty"` - IsisArea *[]byte `json:"isis_area,omitempty"` - LocalRouterID *net.IP `json:"local_router_id_ipv4,omitempty"` - LocalRouterIDv6 *net.IP `json:"local_router_id_ipv6,omitempty"` - - // Segment Routing - SrCapabilties *LsSrCapabilities `json:"sr_capabilities,omitempty"` - SrAlgorithms *[]byte `json:"sr_algorithms,omitempty"` - SrLocalBlock *LsSrLocalBlock `json:"sr_local_block,omitempty"` -} - -type LsAttributeLink struct { - Name *string `json:"name,omitempty"` - LocalRouterID *net.IP `json:"local_router_id_ipv4,omitempty"` - LocalRouterIDv6 *net.IP `json:"local_router_id_ipv6,omitempty"` - RemoteRouterID *net.IP `json:"remote_router_id_ipv4,omitempty"` - RemoteRouterIDv6 *net.IP `json:"remote_router_id_ipv6,omitempty"` - AdminGroup *uint32 `json:"admin_group,omitempty"` - DefaultTEMetric *uint32 `json:"default_te_metric,omitempty"` - IGPMetric *uint32 `json:"igp_metric,omitempty"` - Opaque *[]byte `json:"opaque,omitempty"` - - // Bandwidth is expressed in bytes (not bits) per second. - Bandwidth *float32 `json:"bandwidth,omitempty"` - ReservableBandwidth *float32 `json:"reservable_bandwidth,omitempty"` - UnreservedBandwidth *[8]float32 `json:"unreserved_bandwidth,omitempty"` - Srlgs *[]uint32 `json:"srlgs,omitempty"` - - // TODO flag - SrAdjacencySID *uint32 `json:"adjacency_sid,omitempty"` -} - -type LsAttributePrefix struct { - IGPFlags *LsIGPFlags `json:"igp_flags,omitempty"` - Opaque *[]byte `json:"opaque,omitempty"` - - SrPrefixSID *uint32 `json:"sr_prefix_sid,omitempty"` -} - -type LsAttributeBgpPeerSegment struct { - BgpPeerNodeSid *LsBgpPeerSegmentSID `json:"bgp_peer_node_sid,omitempty"` - BgpPeerAdjacencySid *LsBgpPeerSegmentSID `json:"bgp_peer_adjacency_sid,omitempty"` - BgpPeerSetSid *LsBgpPeerSegmentSID `json:"bgp_peer_set_sid,omitempty"` -} - -type LsAttribute struct { - Node LsAttributeNode `json:"node"` - Link LsAttributeLink `json:"link"` - Prefix LsAttributePrefix `json:"prefix"` - BgpPeerSegment LsAttributeBgpPeerSegment `json:"bgp_peer_segment"` -} - -type PathAttributeLs struct { - PathAttribute - TLVs []LsTLVInterface -} - -func (p *PathAttributeLs) Extract() *LsAttribute { - l := &LsAttribute{} - - for _, tlv := range p.TLVs { - switch v := tlv.(type) { - case *LsTLVNodeFlagBits: - l.Node.Flags = v.Extract() - - case *LsTLVOpaqueNodeAttr: - l.Node.Opaque = &v.Attr - - case *LsTLVNodeName: - l.Node.Name = &v.Name - - case *LsTLVIsisArea: - l.Node.IsisArea = &v.Area - - case *LsTLVLocalIPv4RouterID: - l.Node.LocalRouterID = &v.IP - l.Link.LocalRouterID = &v.IP - - case *LsTLVLocalIPv6RouterID: - l.Node.LocalRouterIDv6 = &v.IP - l.Link.LocalRouterIDv6 = &v.IP - - case *LsTLVSrCapabilities: - l.Node.SrCapabilties = v.Extract() - - case *LsTLVSrAlgorithm: - l.Node.SrAlgorithms = &v.Algorithm - - case *LsTLVSrLocalBlock: - l.Node.SrLocalBlock = v.Extract() - - case *LsTLVRemoteIPv4RouterID: - l.Link.RemoteRouterID = &v.IP - - case *LsTLVRemoteIPv6RouterID: - l.Link.RemoteRouterIDv6 = &v.IP - - case *LsTLVAdminGroup: - l.Link.AdminGroup = &v.AdminGroup - - case *LsTLVMaxLinkBw: - l.Link.Bandwidth = &v.Bandwidth - - case *LsTLVMaxReservableLinkBw: - l.Link.ReservableBandwidth = &v.Bandwidth - - case *LsTLVUnreservedBw: - l.Link.UnreservedBandwidth = &v.Bandwidth - - case *LsTLVSrlg: - l.Link.Srlgs = &v.Srlgs - - case *LsTLVTEDefaultMetric: - l.Link.DefaultTEMetric = &v.Metric - - case *LsTLVIGPMetric: - l.Link.IGPMetric = &v.Metric - - case *LsTLVOpaqueLinkAttr: - l.Link.Opaque = &v.Attr - - case *LsTLVLinkName: - l.Link.Name = &v.Name - - case *LsTLVAdjacencySID: - l.Link.SrAdjacencySID = &v.SID - - case *LsTLVIGPFlags: - l.Prefix.IGPFlags = v.Extract() - - case *LsTLVOpaquePrefixAttr: - l.Prefix.Opaque = &v.Attr - - case *LsTLVPrefixSID: - l.Prefix.SrPrefixSID = &v.SID - - case *LsTLVPeerNodeSID: - l.BgpPeerSegment.BgpPeerNodeSid = v.Extract() - - case *LsTLVPeerAdjacencySID: - l.BgpPeerSegment.BgpPeerAdjacencySid = v.Extract() - - case *LsTLVPeerSetSID: - l.BgpPeerSegment.BgpPeerSetSid = v.Extract() - } - } - - return l -} - -func (p *PathAttributeLs) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - tlvs, err := p.PathAttribute.DecodeFromBytes(data) - if err != nil { - return err - } - - for len(tlvs) >= tlvHdrLen { - t := &LsTLV{} - _, err := t.DecodeFromBytes(tlvs) - if err != nil { - return err - } - - var tlv LsTLVInterface - switch t.Type { - // Node NLRI-related TLVs (https://tools.ietf.org/html/rfc7752#section-3.3.1) - case LS_TLV_NODE_FLAG_BITS: - tlv = &LsTLVNodeFlagBits{} - - case LS_TLV_OPAQUE_NODE_ATTR: - tlv = &LsTLVOpaqueNodeAttr{} - - case LS_TLV_NODE_NAME: - tlv = &LsTLVNodeName{} - - case LS_TLV_ISIS_AREA: - tlv = &LsTLVIsisArea{} - - // Used by Link NLRI as well. - case LS_TLV_IPV4_LOCAL_ROUTER_ID: - tlv = &LsTLVLocalIPv4RouterID{} - - // Used by Link NLRI as well. - case LS_TLV_IPV6_LOCAL_ROUTER_ID: - tlv = &LsTLVLocalIPv6RouterID{} - - // SR-related TLVs (draft-ietf-idr-bgp-ls-segment-routing-ext-08) for Node NLRI - case LS_TLV_SR_CAPABILITIES: - tlv = &LsTLVSrCapabilities{} - - case LS_TLV_SR_ALGORITHM: - tlv = &LsTLVSrAlgorithm{} - - case LS_TLV_SR_LOCAL_BLOCK: - tlv = &LsTLVSrLocalBlock{} - - // Link NLRI-related TLVs (https://tools.ietf.org/html/rfc7752#section-3.3.2) - case LS_TLV_IPV4_REMOTE_ROUTER_ID: - tlv = &LsTLVRemoteIPv4RouterID{} - - case LS_TLV_IPV6_REMOTE_ROUTER_ID: - tlv = &LsTLVRemoteIPv6RouterID{} - - case LS_TLV_ADMIN_GROUP: - tlv = &LsTLVAdminGroup{} - - case LS_TLV_MAX_LINK_BANDWIDTH: - tlv = &LsTLVMaxLinkBw{} - - case LS_TLV_MAX_RESERVABLE_BANDWIDTH: - tlv = &LsTLVMaxReservableLinkBw{} - - case LS_TLV_UNRESERVED_BANDWIDTH: - tlv = &LsTLVUnreservedBw{} - - case LS_TLV_SRLG: - tlv = &LsTLVSrlg{} - - case LS_TLV_TE_DEFAULT_METRIC: - tlv = &LsTLVTEDefaultMetric{} - - case LS_TLV_IGP_METRIC: - tlv = &LsTLVIGPMetric{} - - case LS_TLV_OPAQUE_LINK_ATTR: - tlv = &LsTLVOpaqueLinkAttr{} - - case LS_TLV_LINK_NAME: - tlv = &LsTLVLinkName{} - - // SR-related TLVs (draft-ietf-idr-bgp-ls-segment-routing-ext-08) for Link NLRI - case LS_TLV_ADJACENCY_SID: - tlv = &LsTLVAdjacencySID{} - - // Prefix NLRI-related TLVs (https://tools.ietf.org/html/rfc7752#section-3.3.3) - case LS_TLV_IGP_FLAGS: - tlv = &LsTLVIGPFlags{} - - case LS_TLV_OPAQUE_PREFIX_ATTR: - tlv = &LsTLVOpaquePrefixAttr{} - - // SR-related TLVs (draft-ietf-idr-bgp-ls-segment-routing-ext-08) for Prefix NLRI - case LS_TLV_PREFIX_SID: - tlv = &LsTLVPrefixSID{} - - // BGP-EPE related TLVs (https://tools.ietf.org/html/rfc9086) - case LS_TLV_PEER_NODE_SID: - tlv = &LsTLVPeerNodeSID{} - - case LS_TLV_PEER_ADJACENCY_SID: - tlv = &LsTLVPeerAdjacencySID{} - - case LS_TLV_PEER_SET_SID: - tlv = &LsTLVPeerSetSID{} - - default: - tlvs = tlvs[t.Len():] - continue - } - - if err := tlv.DecodeFromBytes(tlvs); err != nil { - return err - } - tlvs = tlvs[t.Len():] - - p.TLVs = append(p.TLVs, tlv) - } - - return nil -} - -func (p *PathAttributeLs) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{} - - for _, tlv := range p.TLVs { - s, err := tlv.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, s...) - } - - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeLs) String() string { - var buf bytes.Buffer - - for _, tlv := range p.TLVs { - buf.WriteString(tlv.String() + " ") - } - if buf.String() != "" { - return "{LsAttributes: " + buf.String() + "}" - } - return "" -} - -func (p *PathAttributeLs) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Flags BGPAttrFlag `json:"flags"` - LsAttribute - }{ - p.GetType(), - p.GetFlags(), - *p.Extract(), - }) -} - -func AfiSafiToRouteFamily(afi uint16, safi uint8) RouteFamily { - return RouteFamily(int(afi)<<16 | int(safi)) -} - -func RouteFamilyToAfiSafi(rf RouteFamily) (uint16, uint8) { - return uint16(int(rf) >> 16), uint8(int(rf) & 0xff) -} - -type RouteFamily int - -func (f RouteFamily) String() string { - if n, y := AddressFamilyNameMap[f]; y { - return n - } - return fmt.Sprintf("UnknownFamily(%d)", f) -} - -const ( - RF_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_UNICAST - RF_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_UNICAST - RF_IPv4_MC RouteFamily = AFI_IP<<16 | SAFI_MULTICAST - RF_IPv6_MC RouteFamily = AFI_IP6<<16 | SAFI_MULTICAST - RF_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN - RF_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN - RF_IPv4_VPN_MC RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN_MULTICAST - RF_IPv6_VPN_MC RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN_MULTICAST - RF_IPv4_MPLS RouteFamily = AFI_IP<<16 | SAFI_MPLS_LABEL - RF_IPv6_MPLS RouteFamily = AFI_IP6<<16 | SAFI_MPLS_LABEL - RF_VPLS RouteFamily = AFI_L2VPN<<16 | SAFI_VPLS - RF_EVPN RouteFamily = AFI_L2VPN<<16 | SAFI_EVPN - RF_RTC_UC RouteFamily = AFI_IP<<16 | SAFI_ROUTE_TARGET_CONSTRAINTS - RF_IPv4_ENCAP RouteFamily = AFI_IP<<16 | SAFI_ENCAPSULATION - RF_IPv6_ENCAP RouteFamily = AFI_IP6<<16 | SAFI_ENCAPSULATION - RF_FS_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_UNICAST - RF_FS_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_VPN - RF_FS_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_UNICAST - RF_FS_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_VPN - RF_FS_L2_VPN RouteFamily = AFI_L2VPN<<16 | SAFI_FLOW_SPEC_VPN - RF_OPAQUE RouteFamily = AFI_OPAQUE<<16 | SAFI_KEY_VALUE - RF_LS RouteFamily = AFI_LS<<16 | SAFI_LS - RF_SR_POLICY_IPv4 RouteFamily = AFI_IP<<16 | SAFI_SRPOLICY - RF_SR_POLICY_IPv6 RouteFamily = AFI_IP6<<16 | SAFI_SRPOLICY - RF_MUP_IPv4 RouteFamily = AFI_IP<<16 | SAFI_MUP - RF_MUP_IPv6 RouteFamily = AFI_IP6<<16 | SAFI_MUP -) - -var AddressFamilyNameMap = map[RouteFamily]string{ - RF_IPv4_UC: "ipv4-unicast", - RF_IPv6_UC: "ipv6-unicast", - RF_IPv4_MC: "ipv4-multicast", - RF_IPv6_MC: "ipv6-multicast", - RF_IPv4_MPLS: "ipv4-labelled-unicast", - RF_IPv6_MPLS: "ipv6-labelled-unicast", - RF_IPv4_VPN: "l3vpn-ipv4-unicast", - RF_IPv6_VPN: "l3vpn-ipv6-unicast", - RF_IPv4_VPN_MC: "l3vpn-ipv4-multicast", - RF_IPv6_VPN_MC: "l3vpn-ipv6-multicast", - RF_VPLS: "l2vpn-vpls", - RF_EVPN: "l2vpn-evpn", - RF_RTC_UC: "rtc", - RF_IPv4_ENCAP: "ipv4-encap", - RF_IPv6_ENCAP: "ipv6-encap", - RF_FS_IPv4_UC: "ipv4-flowspec", - RF_FS_IPv4_VPN: "l3vpn-ipv4-flowspec", - RF_FS_IPv6_UC: "ipv6-flowspec", - RF_FS_IPv6_VPN: "l3vpn-ipv6-flowspec", - RF_FS_L2_VPN: "l2vpn-flowspec", - RF_OPAQUE: "opaque", - RF_LS: "ls", - RF_SR_POLICY_IPv4: "ipv4-srpolicy", - RF_SR_POLICY_IPv6: "ipv6-srpolicy", - RF_MUP_IPv4: "ipv4-mup", - RF_MUP_IPv6: "ipv6-mup", -} - -var AddressFamilyValueMap = map[string]RouteFamily{ - AddressFamilyNameMap[RF_IPv4_UC]: RF_IPv4_UC, - AddressFamilyNameMap[RF_IPv6_UC]: RF_IPv6_UC, - AddressFamilyNameMap[RF_IPv4_MC]: RF_IPv4_MC, - AddressFamilyNameMap[RF_IPv6_MC]: RF_IPv6_MC, - AddressFamilyNameMap[RF_IPv4_MPLS]: RF_IPv4_MPLS, - AddressFamilyNameMap[RF_IPv6_MPLS]: RF_IPv6_MPLS, - AddressFamilyNameMap[RF_IPv4_VPN]: RF_IPv4_VPN, - AddressFamilyNameMap[RF_IPv6_VPN]: RF_IPv6_VPN, - AddressFamilyNameMap[RF_IPv4_VPN_MC]: RF_IPv4_VPN_MC, - AddressFamilyNameMap[RF_IPv6_VPN_MC]: RF_IPv6_VPN_MC, - AddressFamilyNameMap[RF_VPLS]: RF_VPLS, - AddressFamilyNameMap[RF_EVPN]: RF_EVPN, - AddressFamilyNameMap[RF_RTC_UC]: RF_RTC_UC, - AddressFamilyNameMap[RF_IPv4_ENCAP]: RF_IPv4_ENCAP, - AddressFamilyNameMap[RF_IPv6_ENCAP]: RF_IPv6_ENCAP, - AddressFamilyNameMap[RF_FS_IPv4_UC]: RF_FS_IPv4_UC, - AddressFamilyNameMap[RF_FS_IPv4_VPN]: RF_FS_IPv4_VPN, - AddressFamilyNameMap[RF_FS_IPv6_UC]: RF_FS_IPv6_UC, - AddressFamilyNameMap[RF_FS_IPv6_VPN]: RF_FS_IPv6_VPN, - AddressFamilyNameMap[RF_FS_L2_VPN]: RF_FS_L2_VPN, - AddressFamilyNameMap[RF_OPAQUE]: RF_OPAQUE, - AddressFamilyNameMap[RF_LS]: RF_LS, - AddressFamilyNameMap[RF_SR_POLICY_IPv4]: RF_SR_POLICY_IPv4, - AddressFamilyNameMap[RF_SR_POLICY_IPv6]: RF_SR_POLICY_IPv6, - AddressFamilyNameMap[RF_MUP_IPv4]: RF_MUP_IPv4, - AddressFamilyNameMap[RF_MUP_IPv6]: RF_MUP_IPv6, -} - -func GetRouteFamily(name string) (RouteFamily, error) { - if v, ok := AddressFamilyValueMap[name]; ok { - return v, nil - } - return RouteFamily(0), fmt.Errorf("%s isn't a valid route family name", name) -} - -func NewPrefixFromRouteFamily(afi uint16, safi uint8, prefixStr ...string) (prefix AddrPrefixInterface, err error) { - family := AfiSafiToRouteFamily(afi, safi) - - f := func(s string) (AddrPrefixInterface, error) { - addr, net, err := net.ParseCIDR(s) - if err != nil { - return nil, err - } - len, _ := net.Mask.Size() - switch family { - case RF_IPv4_UC, RF_IPv4_MC: - return NewIPAddrPrefix(uint8(len), addr.String()), nil - } - return NewIPv6AddrPrefix(uint8(len), addr.String()), nil - } - - rdEOR := &RouteDistinguisherUnknown{DefaultRouteDistinguisher{Type: BGP_RD_EOR}, []byte("EOR")} - - switch family { - case RF_IPv4_UC, RF_IPv4_MC: - if len(prefixStr) > 0 { - prefix, err = f(prefixStr[0]) - } else { - prefix = NewIPAddrPrefix(0, "") - } - case RF_IPv6_UC, RF_IPv6_MC: - if len(prefixStr) > 0 { - prefix, err = f(prefixStr[0]) - } else { - prefix = NewIPv6AddrPrefix(0, "") - } - case RF_IPv4_VPN: - if len(prefixStr) == 0 { - prefix = NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), rdEOR) - break - } - - rd, addr, network, err := ParseVPNPrefix(prefixStr[0]) - if err != nil { - return nil, err - } - - length, _ := network.Mask.Size() - - prefix = NewLabeledVPNIPAddrPrefix( - uint8(length), - addr.String(), - *NewMPLSLabelStack(), - rd, - ) - case RF_IPv6_VPN: - if len(prefixStr) == 0 { - prefix = NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), rdEOR) - break - } - - rd, addr, network, err := ParseVPNPrefix(prefixStr[0]) - if err != nil { - return nil, err - } - - length, _ := network.Mask.Size() - - prefix = NewLabeledVPNIPv6AddrPrefix( - uint8(length), - addr.String(), - *NewMPLSLabelStack(), - rd, - ) - case RF_IPv4_MPLS: - prefix = NewLabeledIPAddrPrefix(0, "", *NewMPLSLabelStack()) - case RF_IPv6_MPLS: - prefix = NewLabeledIPv6AddrPrefix(0, "", *NewMPLSLabelStack()) - case RF_EVPN: - prefix = NewEVPNNLRI(0, nil) - case RF_VPLS: - prefix = &VPLSNLRI{} - - // TODO (sbezverk) Add processing SR Policy NLRI - case RF_SR_POLICY_IPv4: - prefix = &SRPolicyIPv4{ - SRPolicyNLRI: SRPolicyNLRI{ - rf: RF_SR_POLICY_IPv4, - }, - } - case RF_SR_POLICY_IPv6: - prefix = &SRPolicyIPv6{ - SRPolicyNLRI: SRPolicyNLRI{ - rf: RF_SR_POLICY_IPv6, - }, - } - case RF_RTC_UC: - prefix = &RouteTargetMembershipNLRI{} - case RF_IPv4_ENCAP: - prefix = NewEncapNLRI("") - case RF_IPv6_ENCAP: - prefix = NewEncapv6NLRI("") - case RF_FS_IPv4_UC: - prefix = &FlowSpecIPv4Unicast{FlowSpecNLRI{rf: RF_FS_IPv4_UC}} - case RF_FS_IPv4_VPN: - prefix = &FlowSpecIPv4VPN{FlowSpecNLRI{rf: RF_FS_IPv4_VPN}} - case RF_FS_IPv6_UC: - prefix = &FlowSpecIPv6Unicast{FlowSpecNLRI{rf: RF_FS_IPv6_UC}} - case RF_FS_IPv6_VPN: - prefix = &FlowSpecIPv6VPN{FlowSpecNLRI{rf: RF_FS_IPv6_VPN}} - case RF_FS_L2_VPN: - prefix = &FlowSpecL2VPN{FlowSpecNLRI{rf: RF_FS_L2_VPN}} - case RF_OPAQUE: - prefix = &OpaqueNLRI{} - case RF_LS: - prefix = &LsAddrPrefix{} - case RF_MUP_IPv4: - prefix = NewMUPNLRI(AFI_IP, 0, 0, nil) - case RF_MUP_IPv6: - prefix = NewMUPNLRI(AFI_IP6, 0, 0, nil) - default: - err = fmt.Errorf("unknown route family. AFI: %d, SAFI: %d", afi, safi) - } - return prefix, err -} - -type BGPAttrFlag uint8 - -const ( - BGP_ATTR_FLAG_EXTENDED_LENGTH BGPAttrFlag = 1 << 4 - BGP_ATTR_FLAG_PARTIAL BGPAttrFlag = 1 << 5 - BGP_ATTR_FLAG_TRANSITIVE BGPAttrFlag = 1 << 6 - BGP_ATTR_FLAG_OPTIONAL BGPAttrFlag = 1 << 7 -) - -func (f BGPAttrFlag) String() string { - strs := make([]string, 0, 4) - if f&BGP_ATTR_FLAG_EXTENDED_LENGTH > 0 { - strs = append(strs, "EXTENDED_LENGTH") - } - if f&BGP_ATTR_FLAG_PARTIAL > 0 { - strs = append(strs, "PARTIAL") - } - if f&BGP_ATTR_FLAG_TRANSITIVE > 0 { - strs = append(strs, "TRANSITIVE") - } - if f&BGP_ATTR_FLAG_OPTIONAL > 0 { - strs = append(strs, "OPTIONAL") - } - return strings.Join(strs, "|") -} - -//go:generate stringer -type=BGPAttrType -type BGPAttrType uint8 - -const ( - _ BGPAttrType = iota - BGP_ATTR_TYPE_ORIGIN - BGP_ATTR_TYPE_AS_PATH - BGP_ATTR_TYPE_NEXT_HOP - BGP_ATTR_TYPE_MULTI_EXIT_DISC - BGP_ATTR_TYPE_LOCAL_PREF - BGP_ATTR_TYPE_ATOMIC_AGGREGATE - BGP_ATTR_TYPE_AGGREGATOR - BGP_ATTR_TYPE_COMMUNITIES - BGP_ATTR_TYPE_ORIGINATOR_ID - BGP_ATTR_TYPE_CLUSTER_LIST - _ - _ - _ - BGP_ATTR_TYPE_MP_REACH_NLRI // = 14 - BGP_ATTR_TYPE_MP_UNREACH_NLRI - BGP_ATTR_TYPE_EXTENDED_COMMUNITIES - BGP_ATTR_TYPE_AS4_PATH - BGP_ATTR_TYPE_AS4_AGGREGATOR - _ - _ - _ - BGP_ATTR_TYPE_PMSI_TUNNEL // = 22 - BGP_ATTR_TYPE_TUNNEL_ENCAP - _ - BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES // = 25 - BGP_ATTR_TYPE_AIGP // = 26 - _ - _ - BGP_ATTR_TYPE_LS // = 29 - BGP_ATTR_TYPE_LARGE_COMMUNITY BGPAttrType = 32 - BGP_ATTR_TYPE_PREFIX_SID BGPAttrType = 40 -) - -// NOTIFICATION Error Code RFC 4271 4.5. -const ( - _ = iota - BGP_ERROR_MESSAGE_HEADER_ERROR - BGP_ERROR_OPEN_MESSAGE_ERROR - BGP_ERROR_UPDATE_MESSAGE_ERROR - BGP_ERROR_HOLD_TIMER_EXPIRED - BGP_ERROR_FSM_ERROR - BGP_ERROR_CEASE - BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR -) - -// NOTIFICATION Error Subcode for BGP_ERROR_MESSAGE_HEADER_ERROR -const ( - _ = iota - BGP_ERROR_SUB_CONNECTION_NOT_SYNCHRONIZED - BGP_ERROR_SUB_BAD_MESSAGE_LENGTH - BGP_ERROR_SUB_BAD_MESSAGE_TYPE -) - -// NOTIFICATION Error Subcode for BGP_ERROR_OPEN_MESSAGE_ERROR -const ( - _ = iota - BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER - BGP_ERROR_SUB_BAD_PEER_AS - BGP_ERROR_SUB_BAD_BGP_IDENTIFIER - BGP_ERROR_SUB_UNSUPPORTED_OPTIONAL_PARAMETER - BGP_ERROR_SUB_DEPRECATED_AUTHENTICATION_FAILURE - BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME - BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY -) - -// NOTIFICATION Error Subcode for BGP_ERROR_UPDATE_MESSAGE_ERROR -const ( - _ = iota - BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST - BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE - BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE - BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR - BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR - BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE - BGP_ERROR_SUB_DEPRECATED_ROUTING_LOOP - BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE - BGP_ERROR_SUB_OPTIONAL_ATTRIBUTE_ERROR - BGP_ERROR_SUB_INVALID_NETWORK_FIELD - BGP_ERROR_SUB_MALFORMED_AS_PATH -) - -// NOTIFICATION Error Subcode for BGP_ERROR_HOLD_TIMER_EXPIRED -const ( - _ = iota - BGP_ERROR_SUB_HOLD_TIMER_EXPIRED -) - -// NOTIFICATION Error Subcode for BGP_ERROR_FSM_ERROR -const ( - _ = iota - BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_STATE - BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE - BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_ESTABLISHED_STATE -) - -// NOTIFICATION Error Subcode for BGP_ERROR_CEASE (RFC 4486) -const ( - _ = iota - BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED - BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN - BGP_ERROR_SUB_PEER_DECONFIGURED - BGP_ERROR_SUB_ADMINISTRATIVE_RESET - BGP_ERROR_SUB_CONNECTION_REJECTED - BGP_ERROR_SUB_OTHER_CONFIGURATION_CHANGE - BGP_ERROR_SUB_CONNECTION_COLLISION_RESOLUTION - BGP_ERROR_SUB_OUT_OF_RESOURCES - BGP_ERROR_SUB_HARD_RESET // RFC8538 -) - -// Constants for BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN and BGP_ERROR_SUB_ADMINISTRATIVE_RESET -const ( - BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX = 128 -) - -// NOTIFICATION Error Subcode for BGP_ERROR_ROUTE_REFRESH -const ( - _ = iota - BGP_ERROR_SUB_INVALID_MESSAGE_LENGTH -) - -type NotificationErrorCode uint16 - -func (c NotificationErrorCode) String() string { - code := uint8(uint16(c) >> 8) - subcode := uint8(uint16(c) & 0xff) - UNDEFINED := "undefined" - codeStr := UNDEFINED - subcodeList := []string{} - switch code { - case BGP_ERROR_MESSAGE_HEADER_ERROR: - codeStr = "header" - subcodeList = []string{ - UNDEFINED, - "connection not synchronized", - "bad message length", - "bad message type"} - case BGP_ERROR_OPEN_MESSAGE_ERROR: - codeStr = "open" - subcodeList = []string{ - UNDEFINED, - "unsupported version number", - "bad peer as", - "bad bgp identifier", - "unsupported optional parameter", - "deprecated authentication failure", - "unacceptable hold time", - "unsupported capability"} - case BGP_ERROR_UPDATE_MESSAGE_ERROR: - codeStr = "update" - subcodeList = []string{ - UNDEFINED, - "malformed attribute list", - "unrecognized well known attribute", - "missing well known attribute", - "attribute flags error", - "attribute length error", - "invalid origin attribute", - "deprecated routing loop", - "invalid next hop attribute", - "optional attribute error", - "invalid network field", - "sub malformed as path"} - case BGP_ERROR_HOLD_TIMER_EXPIRED: - codeStr = "hold timer expired" - subcodeList = []string{ - UNDEFINED, - "hold timer expired"} - case BGP_ERROR_FSM_ERROR: - codeStr = "fsm" - subcodeList = []string{ - UNDEFINED, - "receive unexpected message in opensent state", - "receive unexpected message in openconfirm state", - "receive unexpected message in established state"} - case BGP_ERROR_CEASE: - codeStr = "cease" - subcodeList = []string{ - UNDEFINED, - "maximum number of prefixes reached", - "administrative shutdown", - "peer deconfigured", - "administrative reset", - "connection rejected", - "other configuration change", - "connection collision resolution", - "out of resources"} - case BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR: - codeStr = "route refresh" - subcodeList = []string{"invalid message length"} - } - subcodeStr := func(idx uint8, l []string) string { - if len(l) == 0 || int(idx) > len(l)-1 { - return UNDEFINED - } - return l[idx] - }(subcode, subcodeList) - return fmt.Sprintf("code %v(%v) subcode %v(%v)", code, codeStr, subcode, subcodeStr) -} - -func NewNotificationErrorCode(code, subcode uint8) NotificationErrorCode { - return NotificationErrorCode(uint16(code)<<8 | uint16(subcode)) -} - -var PathAttrFlags map[BGPAttrType]BGPAttrFlag = map[BGPAttrType]BGPAttrFlag{ - BGP_ATTR_TYPE_ORIGIN: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_AS_PATH: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_NEXT_HOP: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_MULTI_EXIT_DISC: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_LOCAL_PREF: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_ATOMIC_AGGREGATE: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_ORIGINATOR_ID: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_CLUSTER_LIST: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_MP_REACH_NLRI: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_MP_UNREACH_NLRI: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_AS4_PATH: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_AS4_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_PMSI_TUNNEL: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_TUNNEL_ENCAP: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_AIGP: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_LARGE_COMMUNITY: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_LS: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_PREFIX_SID: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, -} - -// getPathAttrFlags returns BGP Path Attribute flags value from its type and -// length (byte length of value field). -func getPathAttrFlags(typ BGPAttrType, length int) BGPAttrFlag { - flags := PathAttrFlags[typ] - if length > 255 { - flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH - } - return flags -} - -type PathAttributeInterface interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) - Len(...*MarshallingOption) int - GetFlags() BGPAttrFlag - GetType() BGPAttrType - String() string - MarshalJSON() ([]byte, error) - Flat() map[string]string -} - -type PathAttribute struct { - Flags BGPAttrFlag - Type BGPAttrType - Length uint16 // length of Value -} - -func (p *PathAttribute) Len(options ...*MarshallingOption) int { - if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { - return 4 + int(p.Length) - } - return 3 + int(p.Length) -} - -func (p *PathAttribute) GetFlags() BGPAttrFlag { - return p.Flags -} - -func (p *PathAttribute) GetType() BGPAttrType { - return p.Type -} - -func (p *PathAttribute) DecodeFromBytes(data []byte, options ...*MarshallingOption) (value []byte, err error) { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - if len(data) < 2 { - return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short") - } - p.Flags = BGPAttrFlag(data[0]) - p.Type = BGPAttrType(data[1]) - - if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { - if len(data) < 4 { - return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short") - } - p.Length = binary.BigEndian.Uint16(data[2:4]) - data = data[4:] - } else { - if len(data) < 3 { - return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short") - } - p.Length = uint16(data[2]) - data = data[3:] - } - if len(data) < int(p.Length) { - return nil, NewMessageError(eCode, eSubCode, data, "attribute value length is short") - } - - if eMsg := validatePathAttributeFlags(p.Type, p.Flags); eMsg != "" { - return nil, NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data, eMsg) - } - - return data[:p.Length], nil -} - -func (p *PathAttribute) Serialize(value []byte, options ...*MarshallingOption) ([]byte, error) { - // Note: Do not update "p.Flags" and "p.Length" to avoid data race. - flags := p.Flags - length := uint16(len(value)) - if flags&BGP_ATTR_FLAG_EXTENDED_LENGTH == 0 && length > 255 { - flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH - } - var buf []byte - if flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { - buf = append(make([]byte, 4), value...) - binary.BigEndian.PutUint16(buf[2:4], length) - } else { - buf = append(make([]byte, 3), value...) - buf[2] = byte(length) - } - buf[0] = uint8(flags) - buf[1] = uint8(p.Type) - return buf, nil -} - -type PathAttributeOrigin struct { - PathAttribute - Value uint8 -} - -func (p *PathAttributeOrigin) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 1 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "Origin attribute length is incorrect") - } - p.Value = value[0] - return nil -} - -func (p *PathAttributeOrigin) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize([]byte{p.Value}, options...) -} - -func (p *PathAttributeOrigin) String() string { - typ := "-" - switch p.Value { - case BGP_ORIGIN_ATTR_TYPE_IGP: - typ = "i" - case BGP_ORIGIN_ATTR_TYPE_EGP: - typ = "e" - case BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: - typ = "?" - } - return "{Origin: " + typ + "}" -} - -func (p *PathAttributeOrigin) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value uint8 `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeOrigin(value uint8) *PathAttributeOrigin { - t := BGP_ATTR_TYPE_ORIGIN - return &PathAttributeOrigin{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 1, - }, - Value: value, - } -} - -type AsPathParamFormat struct { - start string - end string - separator string -} - -var asPathParamFormatMap = map[uint8]*AsPathParamFormat{ - BGP_ASPATH_ATTR_TYPE_SET: {"{", "}", ","}, - BGP_ASPATH_ATTR_TYPE_SEQ: {"", "", " "}, - BGP_ASPATH_ATTR_TYPE_CONFED_SET: {"(", ")", " "}, - BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: {"[", "]", ","}, -} - -type AsPathParamInterface interface { - GetType() uint8 - GetAS() []uint32 - Serialize() ([]byte, error) - DecodeFromBytes([]byte) error - Len() int - ASLen() int - MarshalJSON() ([]byte, error) - String() string -} - -func AsPathString(aspath *PathAttributeAsPath) string { - s := bytes.NewBuffer(make([]byte, 0, 64)) - for i, param := range aspath.Value { - segType := param.GetType() - asList := param.GetAS() - if i != 0 { - s.WriteString(" ") - } - - sep := " " - switch segType { - case BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - s.WriteString("(") - case BGP_ASPATH_ATTR_TYPE_CONFED_SET: - s.WriteString("[") - sep = "," - case BGP_ASPATH_ATTR_TYPE_SET: - s.WriteString("{") - sep = "," - } - for j, as := range asList { - s.WriteString(fmt.Sprintf("%d", as)) - if j != len(asList)-1 { - s.WriteString(sep) - } - } - switch segType { - case BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - s.WriteString(")") - case BGP_ASPATH_ATTR_TYPE_CONFED_SET: - s.WriteString("]") - case BGP_ASPATH_ATTR_TYPE_SET: - s.WriteString("}") - } - } - return s.String() -} - -type AsPathParam struct { - Type uint8 - Num uint8 - AS []uint16 -} - -func (a *AsPathParam) GetType() uint8 { - return a.Type -} - -func (a *AsPathParam) GetAS() []uint32 { - nums := make([]uint32, 0, len(a.AS)) - for _, as := range a.AS { - nums = append(nums, uint32(as)) - } - return nums -} - -func (a *AsPathParam) Serialize() ([]byte, error) { - buf := make([]byte, 2+len(a.AS)*2) - buf[0] = uint8(a.Type) - buf[1] = a.Num - for j, as := range a.AS { - binary.BigEndian.PutUint16(buf[2+j*2:], as) - } - return buf, nil -} - -func (a *AsPathParam) DecodeFromBytes(data []byte) error { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) - if len(data) < 2 { - return NewMessageError(eCode, eSubCode, nil, "AS param header length is short") - } - a.Type = data[0] - a.Num = data[1] - data = data[2:] - if len(data) < int(a.Num*2) { - return NewMessageError(eCode, eSubCode, nil, "AS param data length is short") - } - for i := 0; i < int(a.Num); i++ { - a.AS = append(a.AS, binary.BigEndian.Uint16(data)) - data = data[2:] - } - return nil -} - -func (a *AsPathParam) Len() int { - return 2 + len(a.AS)*2 -} - -func (a *AsPathParam) ASLen() int { - switch a.Type { - case BGP_ASPATH_ATTR_TYPE_SEQ: - return len(a.AS) - case BGP_ASPATH_ATTR_TYPE_SET: - return 1 - case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - return 0 - } - return 0 -} - -func (a *AsPathParam) String() string { - format, ok := asPathParamFormatMap[a.Type] - if !ok { - return fmt.Sprintf("%v", a.AS) - } - aspath := make([]string, 0, len(a.AS)) - for _, asn := range a.AS { - aspath = append(aspath, strconv.FormatUint(uint64(asn), 10)) - } - s := bytes.NewBuffer(make([]byte, 0, 32)) - s.WriteString(format.start) - s.WriteString(strings.Join(aspath, format.separator)) - s.WriteString(format.end) - return s.String() -} - -func (a *AsPathParam) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint8 `json:"segment_type"` - Num uint8 `json:"num"` - AS []uint16 `json:"asns"` - }{ - Type: a.Type, - Num: a.Num, - AS: a.AS, - }) -} - -func NewAsPathParam(segType uint8, as []uint16) *AsPathParam { - return &AsPathParam{ - Type: segType, - Num: uint8(len(as)), - AS: as, - } -} - -type As4PathParam struct { - Type uint8 - Num uint8 - AS []uint32 -} - -func (a *As4PathParam) GetType() uint8 { - return a.Type -} - -func (a *As4PathParam) GetAS() []uint32 { - return a.AS -} - -func (a *As4PathParam) Serialize() ([]byte, error) { - buf := make([]byte, 2+len(a.AS)*4) - buf[0] = a.Type - buf[1] = a.Num - for j, as := range a.AS { - binary.BigEndian.PutUint32(buf[2+j*4:], as) - } - return buf, nil -} - -func (a *As4PathParam) DecodeFromBytes(data []byte) error { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) - if len(data) < 2 { - return NewMessageError(eCode, eSubCode, nil, "AS4 param header length is short") - } - a.Type = data[0] - a.Num = data[1] - data = data[2:] - if len(data) < int(a.Num)*4 { - return NewMessageError(eCode, eSubCode, nil, "AS4 param data length is short") - } - for i := 0; i < int(a.Num); i++ { - a.AS = append(a.AS, binary.BigEndian.Uint32(data)) - data = data[4:] - } - return nil -} - -func (a *As4PathParam) Len() int { - return 2 + len(a.AS)*4 -} - -func (a *As4PathParam) ASLen() int { - switch a.Type { - case BGP_ASPATH_ATTR_TYPE_SEQ: - return len(a.AS) - case BGP_ASPATH_ATTR_TYPE_SET: - return 1 - case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - return 0 - } - return 0 -} - -func (a *As4PathParam) String() string { - format, ok := asPathParamFormatMap[a.Type] - if !ok { - return fmt.Sprintf("%v", a.AS) - } - aspath := make([]string, 0, len(a.AS)) - for _, asn := range a.AS { - aspath = append(aspath, strconv.FormatUint(uint64(asn), 10)) - } - s := bytes.NewBuffer(make([]byte, 0, 32)) - s.WriteString(format.start) - s.WriteString(strings.Join(aspath, format.separator)) - s.WriteString(format.end) - return s.String() -} - -func (a *As4PathParam) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint8 `json:"segment_type"` - Num uint8 `json:"num"` - AS []uint32 `json:"asns"` - }{ - Type: a.Type, - Num: a.Num, - AS: a.AS, - }) -} - -func NewAs4PathParam(segType uint8, as []uint32) *As4PathParam { - return &As4PathParam{ - Type: segType, - Num: uint8(len(as)), - AS: as, - } -} - -type PathAttributeAsPath struct { - PathAttribute - Value []AsPathParamInterface -} - -func (p *PathAttributeAsPath) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length == 0 { - // ibgp or something - return nil - } - isAs4, err := validateAsPathValueBytes(value) - if err != nil { - err.(*MessageError).Data, _ = p.PathAttribute.Serialize(value, options...) - return err - } - for len(value) > 0 { - var tuple AsPathParamInterface - if isAs4 { - tuple = &As4PathParam{} - } else { - tuple = &AsPathParam{} - } - err := tuple.DecodeFromBytes(value) - if err != nil { - return err - } - p.Value = append(p.Value, tuple) - value = value[tuple.Len():] - } - return nil -} - -func (p *PathAttributeAsPath) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, v := range p.Value { - vbuf, err := v.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, vbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAsPath) String() string { - params := make([]string, 0, len(p.Value)) - for _, param := range p.Value { - params = append(params, param.String()) - } - return "{AsPath: " + strings.Join(params, " ") + "}" -} - -func (p *PathAttributeAsPath) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []AsPathParamInterface `json:"as_paths"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeAsPath(value []AsPathParamInterface) *PathAttributeAsPath { - var l int - for _, v := range value { - l += v.Len() - } - t := BGP_ATTR_TYPE_AS_PATH - return &PathAttributeAsPath{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeNextHop struct { - PathAttribute - Value net.IP -} - -func (p *PathAttributeNextHop) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 && p.Length != 16 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "nexthop length isn't correct") - } - p.Value = value - return nil -} - -func (p *PathAttributeNextHop) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize(p.Value, options...) -} - -func (p *PathAttributeNextHop) String() string { - return "{Nexthop: " + p.Value.String() + "}" -} - -func (p *PathAttributeNextHop) MarshalJSON() ([]byte, error) { - value := "0.0.0.0" - if p.Value != nil { - value = p.Value.String() - } - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value string `json:"nexthop"` - }{ - Type: p.GetType(), - Value: value, - }) -} - -func NewPathAttributeNextHop(addr string) *PathAttributeNextHop { - t := BGP_ATTR_TYPE_NEXT_HOP - ip := net.ParseIP(addr) - l := net.IPv4len - if ip.To4() == nil { - l = net.IPv6len - } else { - ip = ip.To4() - } - return &PathAttributeNextHop{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: uint16(l), - }, - Value: ip, - } -} - -type PathAttributeMultiExitDisc struct { - PathAttribute - Value uint32 -} - -func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "med length isn't correct") - } - p.Value = binary.BigEndian.Uint32(value) - return nil -} - -func (p *PathAttributeMultiExitDisc) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:], p.Value) - return p.PathAttribute.Serialize(buf[:], options...) -} - -func (p *PathAttributeMultiExitDisc) String() string { - return "{Med: " + strconv.FormatUint(uint64(p.Value), 10) + "}" -} - -func (p *PathAttributeMultiExitDisc) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value uint32 `json:"metric"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeMultiExitDisc(value uint32) *PathAttributeMultiExitDisc { - t := BGP_ATTR_TYPE_MULTI_EXIT_DISC - return &PathAttributeMultiExitDisc{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: value, - } -} - -type PathAttributeLocalPref struct { - PathAttribute - Value uint32 -} - -func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "local pref length isn't correct") - } - p.Value = binary.BigEndian.Uint32(value) - return nil -} - -func (p *PathAttributeLocalPref) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:], p.Value) - return p.PathAttribute.Serialize(buf[:], options...) -} - -func (p *PathAttributeLocalPref) String() string { - return "{LocalPref: " + strconv.FormatUint(uint64(p.Value), 10) + "}" -} - -func (p *PathAttributeLocalPref) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value uint32 `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeLocalPref(value uint32) *PathAttributeLocalPref { - t := BGP_ATTR_TYPE_LOCAL_PREF - return &PathAttributeLocalPref{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: value, - } -} - -type PathAttributeAtomicAggregate struct { - PathAttribute -} - -func (p *PathAttributeAtomicAggregate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - _, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "atomic aggregate should have no value") - } - return nil -} - -func (p *PathAttributeAtomicAggregate) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize(nil, options...) -} - -func (p *PathAttributeAtomicAggregate) String() string { - return "{AtomicAggregate}" -} - -func (p *PathAttributeAtomicAggregate) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - }{ - Type: p.GetType(), - }) -} - -func NewPathAttributeAtomicAggregate() *PathAttributeAtomicAggregate { - t := BGP_ATTR_TYPE_ATOMIC_AGGREGATE - return &PathAttributeAtomicAggregate{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 0, - }, - } -} - -type PathAttributeAggregatorParam struct { - AS uint32 - Askind reflect.Kind - Address net.IP -} - -type PathAttributeAggregator struct { - PathAttribute - Value PathAttributeAggregatorParam -} - -func (p *PathAttributeAggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - switch p.Length { - case 6: - p.Value.Askind = reflect.Uint16 - p.Value.AS = uint32(binary.BigEndian.Uint16(value[0:2])) - p.Value.Address = value[2:] - case 8: - p.Value.Askind = reflect.Uint32 - p.Value.AS = binary.BigEndian.Uint32(value[0:4]) - p.Value.Address = value[4:] - default: - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "aggregator length isn't correct") - } - return nil -} - -func (p *PathAttributeAggregator) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - switch p.Value.Askind { - case reflect.Uint16: - buf = make([]byte, 6) - binary.BigEndian.PutUint16(buf, uint16(p.Value.AS)) - copy(buf[2:], p.Value.Address) - case reflect.Uint32: - buf = make([]byte, 8) - binary.BigEndian.PutUint32(buf, p.Value.AS) - copy(buf[4:], p.Value.Address) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAggregator) String() string { - return "{Aggregate: {AS: " + strconv.FormatUint(uint64(p.Value.AS), 10) + - ", Address: " + p.Value.Address.String() + "}}" -} - -func (p *PathAttributeAggregator) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - AS uint32 `json:"as"` - Address string `json:"address"` - }{ - Type: p.GetType(), - AS: p.Value.AS, - Address: p.Value.Address.String(), - }) -} - -func NewPathAttributeAggregator(as interface{}, address string) *PathAttributeAggregator { - v := reflect.ValueOf(as) - asKind := v.Kind() - var l uint16 - switch asKind { - case reflect.Uint16: - l = 6 - case reflect.Uint32: - l = 8 - default: - // Invalid type - return nil - } - t := BGP_ATTR_TYPE_AGGREGATOR - return &PathAttributeAggregator{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: l, - }, - Value: PathAttributeAggregatorParam{ - AS: uint32(v.Uint()), - Askind: asKind, - Address: net.ParseIP(address).To4(), - }, - } -} - -type PathAttributeCommunities struct { - PathAttribute - Value []uint32 -} - -func (p *PathAttributeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length%4 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "communities length isn't correct") - } - for len(value) >= 4 { - p.Value = append(p.Value, binary.BigEndian.Uint32(value)) - value = value[4:] - } - return nil -} - -func (p *PathAttributeCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, len(p.Value)*4) - for i, v := range p.Value { - binary.BigEndian.PutUint32(buf[i*4:], v) - } - return p.PathAttribute.Serialize(buf, options...) -} - -type WellKnownCommunity uint32 - -const ( - COMMUNITY_INTERNET WellKnownCommunity = 0x00000000 - COMMUNITY_PLANNED_SHUT WellKnownCommunity = 0xffff0000 - COMMUNITY_ACCEPT_OWN WellKnownCommunity = 0xffff0001 - COMMUNITY_ROUTE_FILTER_TRANSLATED_v4 WellKnownCommunity = 0xffff0002 - COMMUNITY_ROUTE_FILTER_v4 WellKnownCommunity = 0xffff0003 - COMMUNITY_ROUTE_FILTER_TRANSLATED_v6 WellKnownCommunity = 0xffff0004 - COMMUNITY_ROUTE_FILTER_v6 WellKnownCommunity = 0xffff0005 - COMMUNITY_LLGR_STALE WellKnownCommunity = 0xffff0006 - COMMUNITY_NO_LLGR WellKnownCommunity = 0xffff0007 - COMMUNITY_BLACKHOLE WellKnownCommunity = 0xffff029a - COMMUNITY_NO_EXPORT WellKnownCommunity = 0xffffff01 - COMMUNITY_NO_ADVERTISE WellKnownCommunity = 0xffffff02 - COMMUNITY_NO_EXPORT_SUBCONFED WellKnownCommunity = 0xffffff03 - COMMUNITY_NO_PEER WellKnownCommunity = 0xffffff04 -) - -var WellKnownCommunityNameMap = map[WellKnownCommunity]string{ - COMMUNITY_INTERNET: "internet", - COMMUNITY_PLANNED_SHUT: "planned-shut", - COMMUNITY_ACCEPT_OWN: "accept-own", - COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: "route-filter-translated-v4", - COMMUNITY_ROUTE_FILTER_v4: "route-filter-v4", - COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: "route-filter-translated-v6", - COMMUNITY_ROUTE_FILTER_v6: "route-filter-v6", - COMMUNITY_LLGR_STALE: "llgr-stale", - COMMUNITY_NO_LLGR: "no-llgr", - COMMUNITY_BLACKHOLE: "blackhole", - COMMUNITY_NO_EXPORT: "no-export", - COMMUNITY_NO_ADVERTISE: "no-advertise", - COMMUNITY_NO_EXPORT_SUBCONFED: "no-export-subconfed", - COMMUNITY_NO_PEER: "no-peer", -} - -var WellKnownCommunityValueMap = map[string]WellKnownCommunity{ - WellKnownCommunityNameMap[COMMUNITY_INTERNET]: COMMUNITY_INTERNET, - WellKnownCommunityNameMap[COMMUNITY_PLANNED_SHUT]: COMMUNITY_PLANNED_SHUT, - WellKnownCommunityNameMap[COMMUNITY_ACCEPT_OWN]: COMMUNITY_ACCEPT_OWN, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_TRANSLATED_v4]: COMMUNITY_ROUTE_FILTER_TRANSLATED_v4, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_v4]: COMMUNITY_ROUTE_FILTER_v4, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_TRANSLATED_v6]: COMMUNITY_ROUTE_FILTER_TRANSLATED_v6, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_v6]: COMMUNITY_ROUTE_FILTER_v6, - WellKnownCommunityNameMap[COMMUNITY_LLGR_STALE]: COMMUNITY_LLGR_STALE, - WellKnownCommunityNameMap[COMMUNITY_NO_LLGR]: COMMUNITY_NO_LLGR, - WellKnownCommunityNameMap[COMMUNITY_NO_EXPORT]: COMMUNITY_NO_EXPORT, - WellKnownCommunityNameMap[COMMUNITY_BLACKHOLE]: COMMUNITY_BLACKHOLE, - WellKnownCommunityNameMap[COMMUNITY_NO_ADVERTISE]: COMMUNITY_NO_ADVERTISE, - WellKnownCommunityNameMap[COMMUNITY_NO_EXPORT_SUBCONFED]: COMMUNITY_NO_EXPORT_SUBCONFED, - WellKnownCommunityNameMap[COMMUNITY_NO_PEER]: COMMUNITY_NO_PEER, -} - -func (p *PathAttributeCommunities) String() string { - l := make([]string, 0, len(p.Value)) - for _, v := range p.Value { - n, ok := WellKnownCommunityNameMap[WellKnownCommunity(v)] - if ok { - l = append(l, n) - } else { - comm := strconv.FormatUint(uint64((0xffff0000&v)>>16), 10) + ":" + strconv.FormatUint(uint64(0xffff&v), 10) - l = append(l, comm) - } - } - return "{Communities: " + strings.Join(l, ", ") + "}" -} - -func (p *PathAttributeCommunities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []uint32 `json:"communities"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeCommunities(value []uint32) *PathAttributeCommunities { - l := len(value) * 4 - t := BGP_ATTR_TYPE_COMMUNITIES - return &PathAttributeCommunities{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeOriginatorId struct { - PathAttribute - Value net.IP -} - -func (p *PathAttributeOriginatorId) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "originator id length isn't correct") - } - p.Value = value - return nil -} - -func (p *PathAttributeOriginatorId) String() string { - return "{Originator: " + p.Value.String() + "}" -} - -func (p *PathAttributeOriginatorId) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value string `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value.String(), - }) -} - -func (p *PathAttributeOriginatorId) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf [4]byte - copy(buf[:], p.Value) - return p.PathAttribute.Serialize(buf[:], options...) -} - -func NewPathAttributeOriginatorId(value string) *PathAttributeOriginatorId { - t := BGP_ATTR_TYPE_ORIGINATOR_ID - return &PathAttributeOriginatorId{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: net.ParseIP(value).To4(), - } -} - -type PathAttributeClusterList struct { - PathAttribute - Value []net.IP -} - -func (p *PathAttributeClusterList) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length%4 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "clusterlist length isn't correct") - } - for len(value) >= 4 { - p.Value = append(p.Value, value[:4]) - value = value[4:] - } - return nil -} - -func (p *PathAttributeClusterList) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, len(p.Value)*4) - for i, v := range p.Value { - copy(buf[i*4:], v) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeClusterList) String() string { - return fmt.Sprintf("{ClusterList: %v}", p.Value) -} - -func (p *PathAttributeClusterList) MarshalJSON() ([]byte, error) { - value := make([]string, 0, len(p.Value)) - for _, v := range p.Value { - value = append(value, v.String()) - } - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []string `json:"value"` - }{ - Type: p.GetType(), - Value: value, - }) -} - -func NewPathAttributeClusterList(value []string) *PathAttributeClusterList { - l := len(value) * 4 - list := make([]net.IP, len(value)) - for i, v := range value { - list[i] = net.ParseIP(v).To4() - } - t := BGP_ATTR_TYPE_CLUSTER_LIST - return &PathAttributeClusterList{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: list, - } -} - -type PathAttributeMpReachNLRI struct { - PathAttribute - Nexthop net.IP - LinkLocalNexthop net.IP - AFI uint16 - SAFI uint8 - Value []AddrPrefixInterface -} - -func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - eData, _ := p.PathAttribute.Serialize(value, options...) - if p.Length < 3 { - return NewMessageError(eCode, eSubCode, value, "mpreach header length is short") - } - - var afi uint16 - var safi uint8 - - // In MRT dumps, AFI+SAFI+NLRI is implicit based on RIB Entry Header, see RFC 6396 4.3.4 - implicitPrefix := GetImplicitPrefix(options) - if implicitPrefix == nil { - afi = binary.BigEndian.Uint16(value[0:2]) - safi = value[2] - - value = value[3:] - } else { - afi = implicitPrefix.AFI() - safi = implicitPrefix.SAFI() - - p.Value = []AddrPrefixInterface{implicitPrefix} - } - - p.AFI = afi - p.SAFI = safi - _, err = NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error()) - } - nexthoplen := int(value[0]) - if len(value) < 1+nexthoplen { - return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is short") - } - nexthopbin := value[1 : 1+nexthoplen] - if nexthoplen > 0 { - v4addrlen := 4 - v6addrlen := 16 - offset := 0 - if safi == SAFI_MPLS_VPN { - offset = 8 - } - switch nexthoplen { - case 2 * (offset + v6addrlen): - p.LinkLocalNexthop = nexthopbin[offset+v6addrlen+offset : 2*(offset+v6addrlen)] - fallthrough - case offset + v6addrlen: - p.Nexthop = nexthopbin[offset : offset+v6addrlen] - case offset + v4addrlen: - p.Nexthop = nexthopbin[offset : offset+v4addrlen] - default: - return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is incorrect") - } - } - - // NLRI implicit for MRT dumps - if implicitPrefix != nil { - return nil - } - - value = value[1+nexthoplen:] - // skip reserved - if len(value) == 0 { - return NewMessageError(eCode, eSubCode, value, "no skip byte") - } - value = value[1:] - addpathLen := 0 - if IsAddPathEnabled(true, AfiSafiToRouteFamily(afi, safi), options) { - addpathLen = 4 - } - for len(value) > 0 { - prefix, err := NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error()) - } - err = prefix.DecodeFromBytes(value, options...) - if err != nil { - return err - } - if prefix.Len(options...)+addpathLen > len(value) { - return NewMessageError(eCode, eSubCode, value, "prefix length is incorrect") - } - value = value[prefix.Len(options...)+addpathLen:] - p.Value = append(p.Value, prefix) - } - return nil -} - -func (p *PathAttributeMpReachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - afi := p.AFI - safi := p.SAFI - nexthoplen := 4 - if afi == AFI_IP6 || p.Nexthop.To4() == nil { - nexthoplen = BGP_ATTR_NHLEN_IPV6_GLOBAL - } - offset := 0 - switch safi { - case SAFI_MPLS_VPN: - offset = 8 - nexthoplen += offset - case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST: - nexthoplen = 0 - } - if p.LinkLocalNexthop != nil && p.LinkLocalNexthop.IsLinkLocalUnicast() { - nexthoplen = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL - } - var buf []byte - includeNLRI := GetImplicitPrefix(options) == nil - if includeNLRI { - family := make([]byte, 3) - binary.BigEndian.PutUint16(family[0:], afi) - family[2] = safi - - buf = append(buf, family...) - } - buf = append(buf, uint8(nexthoplen)) - if nexthoplen != 0 { - nexthop := make([]byte, nexthoplen) - - if p.Nexthop.To4() == nil { - copy(nexthop[offset:], p.Nexthop.To16()) - - if nexthoplen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL { - copy(nexthop[offset+16:], p.LinkLocalNexthop.To16()) - } - } else { - copy(nexthop[offset:], p.Nexthop) - } - - buf = append(buf, nexthop...) - } - if includeNLRI { - buf = append(buf, 0) - for _, prefix := range p.Value { - pbuf, err := prefix.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeMpReachNLRI) MarshalJSON() ([]byte, error) { - nexthop := p.Nexthop.String() - if p.Nexthop == nil { - switch p.AFI { - case AFI_IP: - nexthop = "0.0.0.0" - case AFI_IP6: - nexthop = "::" - default: - nexthop = "fictitious" - } - } - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Nexthop string `json:"nexthop"` - AFI uint16 `json:"afi"` - SAFI uint8 `json:"safi"` - Value []AddrPrefixInterface `json:"value"` - }{ - Type: p.GetType(), - Nexthop: nexthop, - AFI: p.AFI, - SAFI: p.SAFI, - Value: p.Value, - }) -} - -func (p *PathAttributeMpReachNLRI) String() string { - return fmt.Sprintf("{MpReach(%s): {Nexthop: %s, NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Nexthop, p.Value) -} - -func NewPathAttributeMpReachNLRI(nexthop string, nlri []AddrPrefixInterface) *PathAttributeMpReachNLRI { - // AFI(2) + SAFI(1) + NexthopLength(1) + Nexthop(variable) - // + Reserved(1) + NLRI(variable) - l := 5 - var afi uint16 - var safi uint8 - if len(nlri) > 0 { - afi = nlri[0].AFI() - safi = nlri[0].SAFI() - } - nh := net.ParseIP(nexthop) - if nh.To4() != nil && afi != AFI_IP6 { - nh = nh.To4() - switch safi { - case SAFI_MPLS_VPN: - l += 12 - case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST: - // Should not have Nexthop - default: - l += 4 - } - } else { - switch safi { - case SAFI_MPLS_VPN: - l += 24 - case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST: - // Should not have Nexthop - default: - l += 16 - } - } - var nlriLen int - for _, n := range nlri { - l += n.Len() - nBuf, _ := n.Serialize() - nlriLen += len(nBuf) - } - t := BGP_ATTR_TYPE_MP_REACH_NLRI - return &PathAttributeMpReachNLRI{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Nexthop: nh, - AFI: afi, - SAFI: safi, - Value: nlri, - } -} - -type PathAttributeMpUnreachNLRI struct { - PathAttribute - AFI uint16 - SAFI uint8 - Value []AddrPrefixInterface -} - -func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - eData, _ := p.PathAttribute.Serialize(value, options...) - if p.Length < 3 { - return NewMessageError(eCode, eSubCode, value, "unreach header length is incorrect") - } - afi := binary.BigEndian.Uint16(value[0:2]) - safi := value[2] - _, err = NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error()) - } - value = value[3:] - p.AFI = afi - p.SAFI = safi - addpathLen := 0 - if IsAddPathEnabled(true, AfiSafiToRouteFamily(afi, safi), options) { - addpathLen = 4 - } - for len(value) > 0 { - prefix, err := NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error()) - } - err = prefix.DecodeFromBytes(value, options...) - if err != nil { - return err - } - if prefix.Len(options...)+addpathLen > len(value) { - return NewMessageError(eCode, eSubCode, eData, "prefix length is incorrect") - } - value = value[prefix.Len(options...)+addpathLen:] - p.Value = append(p.Value, prefix) - } - return nil -} - -func (p *PathAttributeMpUnreachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 3) - binary.BigEndian.PutUint16(buf, p.AFI) - buf[2] = p.SAFI - for _, prefix := range p.Value { - pbuf, err := prefix.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeMpUnreachNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - AFI uint16 `json:"afi"` - SAFI uint8 `json:"safi"` - Value []AddrPrefixInterface `json:"value"` - }{ - Type: p.GetType(), - AFI: p.AFI, - SAFI: p.SAFI, - Value: p.Value, - }) -} - -func (p *PathAttributeMpUnreachNLRI) String() string { - if len(p.Value) > 0 { - return fmt.Sprintf("{MpUnreach(%s): {NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Value) - } - return fmt.Sprintf("{MpUnreach(%s): End-of-Rib}", AfiSafiToRouteFamily(p.AFI, p.SAFI)) -} - -func NewPathAttributeMpUnreachNLRI(nlri []AddrPrefixInterface) *PathAttributeMpUnreachNLRI { - // AFI(2) + SAFI(1) + NLRI(variable) - l := 3 - var afi uint16 - var safi uint8 - if len(nlri) > 0 { - afi = nlri[0].AFI() - safi = nlri[0].SAFI() - } - for _, n := range nlri { - l += n.Len() - } - t := BGP_ATTR_TYPE_MP_UNREACH_NLRI - return &PathAttributeMpUnreachNLRI{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - AFI: afi, - SAFI: safi, - Value: nlri, - } -} - -type ExtendedCommunityInterface interface { - Serialize() ([]byte, error) - String() string - GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) - MarshalJSON() ([]byte, error) - Flat() map[string]string -} - -type TwoOctetAsSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - AS uint16 - LocalAdmin uint32 - IsTransitive bool -} - -func (e *TwoOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) - } - buf[1] = byte(e.SubType) - binary.BigEndian.PutUint16(buf[2:], e.AS) - binary.BigEndian.PutUint32(buf[4:], e.LocalAdmin) - return buf, nil -} - -func (e *TwoOctetAsSpecificExtended) String() string { - return strconv.FormatUint(uint64(e.AS), 10) + ":" + strconv.FormatUint(uint64(e.LocalAdmin), 10) -} - -func (e *TwoOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *TwoOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC - } - return t, e.SubType -} - -func NewTwoOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uint16, localAdmin uint32, isTransitive bool) *TwoOctetAsSpecificExtended { - return &TwoOctetAsSpecificExtended{ - SubType: subtype, - AS: as, - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -type IPv4AddressSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - IPv4 net.IP - LocalAdmin uint16 - IsTransitive bool -} - -func (e *IPv4AddressSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC) - } - buf[1] = byte(e.SubType) - copy(buf[2:6], e.IPv4) - binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin) - return buf, nil -} - -func (e *IPv4AddressSpecificExtended) String() string { - return e.IPv4.String() + ":" + strconv.FormatUint(uint64(e.LocalAdmin), 10) -} - -func (e *IPv4AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *IPv4AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_IP4_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC - } - return t, e.SubType -} - -func NewIPv4AddressSpecificExtended(subtype ExtendedCommunityAttrSubType, ip string, localAdmin uint16, isTransitive bool) *IPv4AddressSpecificExtended { - ipv4 := net.ParseIP(ip) - if ipv4.To4() == nil { - return nil - } - return &IPv4AddressSpecificExtended{ - SubType: subtype, - IPv4: ipv4.To4(), - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -type IPv6AddressSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - IPv6 net.IP - LocalAdmin uint16 - IsTransitive bool -} - -func (e *IPv6AddressSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 20) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_IP6_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC) - } - buf[1] = byte(e.SubType) - copy(buf[2:18], e.IPv6) - binary.BigEndian.PutUint16(buf[18:], e.LocalAdmin) - return buf, nil -} - -func (e *IPv6AddressSpecificExtended) String() string { - return e.IPv6.String() + ":" + strconv.FormatUint(uint64(e.LocalAdmin), 10) -} - -func (e *IPv6AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *IPv6AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_IP6_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC - } - return t, e.SubType -} - -func NewIPv6AddressSpecificExtended(subtype ExtendedCommunityAttrSubType, ip string, localAdmin uint16, isTransitive bool) *IPv6AddressSpecificExtended { - ipv6 := net.ParseIP(ip) - if ipv6.To16() == nil { - return nil - } - return &IPv6AddressSpecificExtended{ - SubType: subtype, - IPv6: ipv6.To16(), - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -type FourOctetAsSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - AS uint32 - LocalAdmin uint16 - IsTransitive bool -} - -func (e *FourOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) - } - buf[1] = byte(e.SubType) - binary.BigEndian.PutUint32(buf[2:], e.AS) - binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin) - return buf, nil -} - -func (e *FourOctetAsSpecificExtended) String() string { - var buf [4]byte - binary.BigEndian.PutUint32(buf[:4], e.AS) - asUpper := binary.BigEndian.Uint16(buf[0:2]) - asLower := binary.BigEndian.Uint16(buf[2:4]) - return strconv.FormatUint(uint64(asUpper), 10) + "." + strconv.FormatUint(uint64(asLower), 10) + - ":" + strconv.FormatUint(uint64(e.LocalAdmin), 10) -} - -func (e *FourOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *FourOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC - } - return t, e.SubType -} - -func NewFourOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uint32, localAdmin uint16, isTransitive bool) *FourOctetAsSpecificExtended { - return &FourOctetAsSpecificExtended{ - SubType: subtype, - AS: as, - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -func ParseExtendedCommunity(subtype ExtendedCommunityAttrSubType, com string) (ExtendedCommunityInterface, error) { - if subtype == EC_SUBTYPE_ENCAPSULATION { - var t TunnelType - switch com { - case TUNNEL_TYPE_L2TP3.String(): - t = TUNNEL_TYPE_L2TP3 - case TUNNEL_TYPE_GRE.String(): - t = TUNNEL_TYPE_GRE - case TUNNEL_TYPE_IP_IN_IP.String(): - t = TUNNEL_TYPE_IP_IN_IP - case TUNNEL_TYPE_VXLAN.String(): - t = TUNNEL_TYPE_VXLAN - case TUNNEL_TYPE_NVGRE.String(): - t = TUNNEL_TYPE_NVGRE - case TUNNEL_TYPE_MPLS.String(): - t = TUNNEL_TYPE_MPLS - case TUNNEL_TYPE_MPLS_IN_GRE.String(): - t = TUNNEL_TYPE_MPLS_IN_GRE - case TUNNEL_TYPE_VXLAN_GRE.String(): - t = TUNNEL_TYPE_VXLAN_GRE - case TUNNEL_TYPE_MPLS_IN_UDP.String(): - t = TUNNEL_TYPE_MPLS_IN_UDP - case TUNNEL_TYPE_GENEVE.String(): - t = TUNNEL_TYPE_GENEVE - case "L2TPv3 over IP": - t = TUNNEL_TYPE_L2TP3 - case "GRE": - t = TUNNEL_TYPE_GRE - case "IP in IP": - t = TUNNEL_TYPE_IP_IN_IP - case "VXLAN": - t = TUNNEL_TYPE_VXLAN - case "NVGRE": - t = TUNNEL_TYPE_NVGRE - case "MPLS": - t = TUNNEL_TYPE_MPLS - case "MPLS in GRE": - t = TUNNEL_TYPE_MPLS_IN_GRE - case "VXLAN GRE": - t = TUNNEL_TYPE_VXLAN_GRE - case "MPLS in UDP": - t = TUNNEL_TYPE_MPLS_IN_UDP - case "GENEVE": - t = TUNNEL_TYPE_GENEVE - default: - return nil, fmt.Errorf("invalid encap type %s", com) - } - return NewEncapExtended(t), nil - } - - if subtype == EC_SUBTYPE_ORIGIN_VALIDATION { - var state ValidationState - switch com { - case VALIDATION_STATE_VALID.String(): - state = VALIDATION_STATE_VALID - case VALIDATION_STATE_NOT_FOUND.String(): - state = VALIDATION_STATE_NOT_FOUND - case VALIDATION_STATE_INVALID.String(): - state = VALIDATION_STATE_INVALID - default: - return nil, errors.New("invalid validation state") - } - return &ValidationExtended{ - State: state, - }, nil - } - elems, err := parseRdAndRt(com) - if err != nil { - return nil, err - } - localAdmin, _ := strconv.ParseUint(elems[10], 10, 32) - if subtype == EC_SUBTYPE_SOURCE_AS { - localAdmin = 0 - } - ip := net.ParseIP(elems[1]) - isTransitive := true - switch { - case subtype == EC_SUBTYPE_LINK_BANDWIDTH: - asn, _ := strconv.ParseUint(elems[8], 10, 16) - return NewLinkBandwidthExtended(uint16(asn), float32(localAdmin)), nil - case ip.To4() != nil: - return NewIPv4AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil - case ip.To16() != nil: - return NewIPv6AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil - case elems[6] == "" && elems[7] == "": - asn, _ := strconv.ParseUint(elems[8], 10, 16) - return NewTwoOctetAsSpecificExtended(subtype, uint16(asn), uint32(localAdmin), isTransitive), nil - default: - fst, _ := strconv.ParseUint(elems[7], 10, 16) - snd, _ := strconv.ParseUint(elems[8], 10, 16) - asn := fst<<16 | snd - return NewFourOctetAsSpecificExtended(subtype, uint32(asn), uint16(localAdmin), isTransitive), nil - } -} - -func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) { - return ParseExtendedCommunity(EC_SUBTYPE_ROUTE_TARGET, rt) -} - -func SerializeExtendedCommunities(comms []ExtendedCommunityInterface) ([][]byte, error) { - bufs := make([][]byte, len(comms)) - var err error - for i, c := range comms { - bufs[i], err = c.Serialize() - if err != nil { - return nil, err - } - } - return bufs, err -} - -type ValidationState uint8 - -const ( - VALIDATION_STATE_VALID ValidationState = 0 - VALIDATION_STATE_NOT_FOUND ValidationState = 1 - VALIDATION_STATE_INVALID ValidationState = 2 -) - -func (s ValidationState) String() string { - switch s { - case VALIDATION_STATE_VALID: - return "valid" - case VALIDATION_STATE_NOT_FOUND: - return "not-found" - case VALIDATION_STATE_INVALID: - return "invalid" - } - return fmt.Sprintf("unknown validation state(%d)", s) -} - -type ValidationExtended struct { - State ValidationState -} - -func (e *ValidationExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - typ, subType := e.GetTypes() - buf[0] = byte(typ) - buf[1] = byte(subType) - buf[7] = byte(e.State) - return buf, nil -} - -func (e *ValidationExtended) String() string { - return e.State.String() -} - -func (e *ValidationExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_NON_TRANSITIVE_OPAQUE, EC_SUBTYPE_ORIGIN_VALIDATION -} - -func (e *ValidationExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - SubType ExtendedCommunityAttrSubType `json:"subtype"` - State ValidationState `json:"value"` - }{ - Type: t, - SubType: s, - State: e.State, - }) -} - -func NewValidationExtended(state ValidationState) *ValidationExtended { - return &ValidationExtended{ - State: state, - } -} - -type LinkBandwidthExtended struct { - AS uint16 - Bandwidth float32 -} - -func (e *LinkBandwidthExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_NON_TRANSITIVE_LINK_BANDWIDTH, EC_SUBTYPE_LINK_BANDWIDTH -} - -func (e *LinkBandwidthExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - typ, subType := e.GetTypes() - buf[0] = byte(typ) - buf[1] = byte(subType) - binary.BigEndian.PutUint16(buf[2:4], e.AS) - binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(e.Bandwidth)) - return buf, nil -} - -func (e *LinkBandwidthExtended) String() string { - return strconv.FormatUint(uint64(e.AS), 10) + ":" + strconv.FormatUint(uint64(e.Bandwidth), 10) -} - -func (e *LinkBandwidthExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - SubType ExtendedCommunityAttrSubType `json:"subtype"` - AS uint16 `json:"asn"` - Bandwidth float32 `json:"bandwidth"` - }{ - Type: t, - SubType: s, - AS: e.AS, - Bandwidth: e.Bandwidth, - }) -} - -func NewLinkBandwidthExtended(as uint16, bw float32) *LinkBandwidthExtended { - return &LinkBandwidthExtended{ - AS: as, - Bandwidth: bw, - } -} - -type ColorExtended struct { - Color uint32 -} - -func (e *ColorExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - typ, subType := e.GetTypes() - buf[0] = byte(typ) - buf[1] = byte(subType) - binary.BigEndian.PutUint32(buf[4:8], uint32(e.Color)) - return buf, nil -} - -func (e *ColorExtended) String() string { - return strconv.FormatUint(uint64(e.Color), 10) -} - -func (e *ColorExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_COLOR -} - -func (e *ColorExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - SubType ExtendedCommunityAttrSubType `json:"subtype"` - Color uint32 `json:"color"` - }{ - Type: t, - SubType: s, - Color: e.Color, - }) -} - -func NewColorExtended(color uint32) *ColorExtended { - return &ColorExtended{ - Color: color, - } -} - -type EncapExtended struct { - TunnelType TunnelType -} - -func (e *EncapExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - typ, subType := e.GetTypes() - buf[0] = byte(typ) - buf[1] = byte(subType) - binary.BigEndian.PutUint16(buf[6:8], uint16(e.TunnelType)) - return buf, nil -} - -func (e *EncapExtended) String() string { - switch e.TunnelType { - case TUNNEL_TYPE_L2TP3: - return "L2TPv3 over IP" - case TUNNEL_TYPE_GRE: - return "GRE" - case TUNNEL_TYPE_IP_IN_IP: - return "IP in IP" - case TUNNEL_TYPE_VXLAN: - return "VXLAN" - case TUNNEL_TYPE_NVGRE: - return "NVGRE" - case TUNNEL_TYPE_MPLS: - return "MPLS" - case TUNNEL_TYPE_MPLS_IN_GRE: - return "MPLS in GRE" - case TUNNEL_TYPE_VXLAN_GRE: - return "VXLAN GRE" - case TUNNEL_TYPE_MPLS_IN_UDP: - return "MPLS in UDP" - case TUNNEL_TYPE_SR_POLICY: - return "SR Policy" - case TUNNEL_TYPE_GENEVE: - return "GENEVE" - default: - return "tunnel: " + strconv.FormatUint(uint64(e.TunnelType), 10) - } -} - -func (e *EncapExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_ENCAPSULATION -} - -func (e *EncapExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - SubType ExtendedCommunityAttrSubType `json:"subtype"` - TunnelType TunnelType `json:"tunnel_type"` - }{ - Type: t, - SubType: s, - TunnelType: e.TunnelType, - }) -} - -func NewEncapExtended(tunnelType TunnelType) *EncapExtended { - return &EncapExtended{ - TunnelType: tunnelType, - } -} - -type DefaultGatewayExtended struct { -} - -func (e *DefaultGatewayExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - typ, subType := e.GetTypes() - buf[0] = byte(typ) - buf[1] = byte(subType) - return buf, nil -} - -func (e *DefaultGatewayExtended) String() string { - return "default-gateway" -} - -func (e *DefaultGatewayExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_DEFAULT_GATEWAY -} - -func (e *DefaultGatewayExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - SubType ExtendedCommunityAttrSubType `json:"subtype"` - }{ - Type: t, - SubType: s, - }) -} - -func NewDefaultGatewayExtended() *DefaultGatewayExtended { - return &DefaultGatewayExtended{} -} - -type OpaqueExtended struct { - IsTransitive bool - Value []byte -} - -func (e *OpaqueExtended) Serialize() ([]byte, error) { - if len(e.Value) != 7 { - return nil, fmt.Errorf("invalid value length for opaque extended community: %d", len(e.Value)) - } - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_OPAQUE) - } - copy(buf[1:], e.Value) - return buf, nil -} - -func (e *OpaqueExtended) String() string { - var buf [8]byte - copy(buf[1:], e.Value) - return strconv.FormatUint(binary.BigEndian.Uint64(buf[:]), 10) -} - -func (e *OpaqueExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - var subType ExtendedCommunityAttrSubType - if len(e.Value) > 0 { - // Use the first byte of value as the sub type - subType = ExtendedCommunityAttrSubType(e.Value[0]) - } - if e.IsTransitive { - return EC_TYPE_TRANSITIVE_OPAQUE, subType - } - return EC_TYPE_NON_TRANSITIVE_OPAQUE, subType -} - -func (e *OpaqueExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value []byte `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.Value, - }) -} - -func NewOpaqueExtended(isTransitive bool, value []byte) *OpaqueExtended { - v := make([]byte, 7) - copy(v, value) - return &OpaqueExtended{ - IsTransitive: isTransitive, - Value: v, - } -} - -func parseOpaqueExtended(data []byte) (ExtendedCommunityInterface, error) { - typ := ExtendedCommunityAttrType(data[0]) - isTransitive := false - switch typ { - case EC_TYPE_TRANSITIVE_OPAQUE: - isTransitive = true - case EC_TYPE_NON_TRANSITIVE_OPAQUE: - // isTransitive = false - default: - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid opaque extended community type: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - - if isTransitive { - switch subType { - case EC_SUBTYPE_COLOR: - return &ColorExtended{ - Color: binary.BigEndian.Uint32(data[4:8]), - }, nil - case EC_SUBTYPE_ENCAPSULATION: - return &EncapExtended{ - TunnelType: TunnelType(binary.BigEndian.Uint16(data[6:8])), - }, nil - case EC_SUBTYPE_DEFAULT_GATEWAY: - return &DefaultGatewayExtended{}, nil - } - } else { - switch subType { - case EC_SUBTYPE_ORIGIN_VALIDATION: - return &ValidationExtended{ - State: ValidationState(data[7]), - }, nil - } - } - return NewOpaqueExtended(isTransitive, data[1:8]), nil -} - -type ESILabelExtended struct { - Label uint32 - IsSingleActive bool -} - -func (e *ESILabelExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_ESI_LABEL) - if e.IsSingleActive { - buf[2] = byte(1) - } - buf[3] = 0 - buf[4] = 0 - buf[5] = byte((e.Label >> 16) & 0xff) - buf[6] = byte((e.Label >> 8) & 0xff) - buf[7] = byte(e.Label & 0xff) - return buf, nil -} - -func (e *ESILabelExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString("esi-label: " + strconv.FormatUint(uint64(e.Label), 10)) - if e.IsSingleActive { - buf.WriteString(", single-active") - } - return buf.String() -} - -func (e *ESILabelExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Label uint32 `json:"label"` - IsSingleActive bool `json:"is_single_active"` - }{ - Type: t, - Subtype: s, - Label: e.Label, - IsSingleActive: e.IsSingleActive, - }) -} - -func (e *ESILabelExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_ESI_LABEL -} - -func NewESILabelExtended(label uint32, isSingleActive bool) *ESILabelExtended { - return &ESILabelExtended{ - Label: label, - IsSingleActive: isSingleActive, - } -} - -type ESImportRouteTarget struct { - ESImport net.HardwareAddr -} - -func (e *ESImportRouteTarget) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_ES_IMPORT) - copy(buf[2:], e.ESImport) - return buf, nil -} - -func (e *ESImportRouteTarget) String() string { - return "es-import rt: " + e.ESImport.String() -} - -func (e *ESImportRouteTarget) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.ESImport.String(), - }) -} - -func (e *ESImportRouteTarget) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_ES_IMPORT -} - -func NewESImportRouteTarget(mac string) *ESImportRouteTarget { - esImport, err := net.ParseMAC(mac) - if err != nil { - return nil - } - return &ESImportRouteTarget{ - ESImport: esImport, - } -} - -type MacMobilityExtended struct { - Sequence uint32 - IsSticky bool -} - -func (e *MacMobilityExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_MAC_MOBILITY) - if e.IsSticky { - buf[2] = byte(1) - } - binary.BigEndian.PutUint32(buf[4:], e.Sequence) - return buf, nil -} - -func (e *MacMobilityExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString("mac-mobility: " + strconv.FormatUint(uint64(e.Sequence), 10)) - if e.IsSticky { - buf.WriteString(", sticky") - } - return buf.String() -} - -func (e *MacMobilityExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Sequence uint32 `json:"sequence"` - IsSticky bool `json:"is_sticky"` - }{ - Type: t, - Subtype: s, - Sequence: e.Sequence, - IsSticky: e.IsSticky, - }) -} - -func (e *MacMobilityExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_MAC_MOBILITY -} - -func NewMacMobilityExtended(seq uint32, isSticky bool) *MacMobilityExtended { - return &MacMobilityExtended{ - Sequence: seq, - IsSticky: isSticky, - } -} - -type RouterMacExtended struct { - Mac net.HardwareAddr -} - -func (e *RouterMacExtended) Serialize() ([]byte, error) { - buf := make([]byte, 2, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_ROUTER_MAC) - buf = append(buf, e.Mac...) - return buf, nil -} - -func (e *RouterMacExtended) String() string { - return "router's mac: " + e.Mac.String() -} - -func (e *RouterMacExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Mac string `json:"mac"` - }{ - Type: t, - Subtype: s, - Mac: e.Mac.String(), - }) -} - -func (e *RouterMacExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_ROUTER_MAC -} - -func NewRoutersMacExtended(mac string) *RouterMacExtended { - hw, err := net.ParseMAC(mac) - if err != nil { - return nil - } - return &RouterMacExtended{ - Mac: hw, - } -} - -type Layer2AttributesExtended struct { - HasCILabel bool - HasFlowLabel bool - HasControlWord bool - IsPrimaryPe bool - IsBackupPe bool - Mtu uint16 -} - -type EvpnControlFlag uint8 - -const ( - BACKUP_PE EvpnControlFlag = 1 << 0 - PRIMARY_PE EvpnControlFlag = 1 << 1 - CONTROL_WORD EvpnControlFlag = 1 << 2 - FLOW_LABEL EvpnControlFlag = 1 << 3 - CI_LABEL EvpnControlFlag = 1 << 4 -) - -func (e *Layer2AttributesExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_L2_ATTRIBUTES) - - if e.IsBackupPe { - buf[3] |= uint8(BACKUP_PE) - } else if e.IsPrimaryPe { - buf[3] |= uint8(PRIMARY_PE) - } - if e.HasControlWord { - buf[3] |= uint8(CONTROL_WORD) - } - if e.HasFlowLabel { - buf[3] |= uint8(FLOW_LABEL) - } - if e.HasCILabel { - buf[3] |= uint8(CI_LABEL) - } - binary.BigEndian.PutUint16(buf[4:6], e.Mtu) - return buf, nil -} - -func (e *Layer2AttributesExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString("evpn-l2-info: ") - if e.IsPrimaryPe { - buf.WriteString("is-primary-pe, ") - } - if e.IsBackupPe { - buf.WriteString("is-backup-pe, ") - } - if e.HasControlWord { - buf.WriteString("control-word, ") - } - if e.HasFlowLabel { - buf.WriteString("flow-label, ") - } - if e.HasCILabel { - buf.WriteString("ci-label, ") - } - - buf.WriteString("mtu " + strconv.FormatUint(uint64(e.Mtu), 10)) - return buf.String() -} - -func (e *Layer2AttributesExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - CILabel bool `json:"ci_label,omitempty"` - FlowLabel bool `json:"flow_label,omitempty"` - ControlWord bool `json:"control_word,omitempty"` - PrimaryPe bool `json:"is_primary_pe,omitempty"` - BackupPe bool `json:"is_backup_pe,omitempty"` - Mtu uint16 `json:"mtu"` - }{ - Type: t, - Subtype: s, - CILabel: e.HasCILabel, - FlowLabel: e.HasFlowLabel, - ControlWord: e.HasControlWord, - PrimaryPe: e.IsPrimaryPe, - BackupPe: e.IsBackupPe, - Mtu: e.Mtu, - }) -} - -func (e *Layer2AttributesExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_L2_ATTRIBUTES -} - -func parseEvpnExtended(data []byte) (ExtendedCommunityInterface, error) { - if ExtendedCommunityAttrType(data[0]) != EC_TYPE_EVPN { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_EVPN: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - switch subType { - case EC_SUBTYPE_ESI_LABEL: - var isSingleActive bool - if data[2] > 0 { - isSingleActive = true - } - label := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) - return &ESILabelExtended{ - IsSingleActive: isSingleActive, - Label: label, - }, nil - case EC_SUBTYPE_ES_IMPORT: - return &ESImportRouteTarget{ - ESImport: net.HardwareAddr(data[2:8]), - }, nil - case EC_SUBTYPE_MAC_MOBILITY: - var isSticky bool - if data[2] > 0 { - isSticky = true - } - seq := binary.BigEndian.Uint32(data[4:8]) - return &MacMobilityExtended{ - Sequence: seq, - IsSticky: isSticky, - }, nil - case EC_SUBTYPE_ROUTER_MAC: - return &RouterMacExtended{ - Mac: net.HardwareAddr(data[2:8]), - }, nil - case EC_SUBTYPE_L2_ATTRIBUTES: - if flags := data[3]; flags == 0 { - return &Layer2AttributesExtended{ - Mtu: binary.BigEndian.Uint16(data[4:6]), - }, nil - } else { - return &Layer2AttributesExtended{ - HasCILabel: flags&uint8(CI_LABEL) > 0, - HasFlowLabel: flags&uint8(FLOW_LABEL) > 0, - HasControlWord: flags&uint8(CONTROL_WORD) > 0, - IsPrimaryPe: flags&uint8(PRIMARY_PE) > 0, - IsBackupPe: flags&uint8(BACKUP_PE) > 0, - Mtu: binary.BigEndian.Uint16(data[4:6]), - }, nil - } - } - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("unknown evpn subtype: %d", subType)) -} - -type TrafficRateExtended struct { - AS uint16 - Rate float32 -} - -func (e *TrafficRateExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE) - binary.BigEndian.PutUint16(buf[2:4], e.AS) - binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(e.Rate)) - return buf, nil -} - -func (e *TrafficRateExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - if e.Rate == 0 { - buf.WriteString("discard") - } else { - buf.WriteString("rate: " + strconv.FormatFloat(float64(e.Rate), 'f', 6, 32)) - } - if e.AS != 0 { - buf.WriteString("(as: " + strconv.FormatUint(uint64(e.AS), 10) + ")") - } - return buf.String() -} - -func (e *TrafficRateExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - As uint16 `json:"as"` - Rate float32 `json:"rate"` - }{t, s, e.AS, e.Rate}) -} - -func (e *TrafficRateExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE -} - -func NewTrafficRateExtended(as uint16, rate float32) *TrafficRateExtended { - return &TrafficRateExtended{ - AS: as, - Rate: rate, - } -} - -type TrafficActionExtended struct { - Terminal bool - Sample bool -} - -func (e *TrafficActionExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION) - if e.Terminal { - buf[7] = 0x01 - } - if e.Sample { - buf[7] = buf[7] | 0x2 - } - return buf, nil -} - -func (e *TrafficActionExtended) String() string { - ss := make([]string, 0, 2) - if e.Terminal { - ss = append(ss, "terminal") - } - if e.Sample { - ss = append(ss, "sample") - } - return "action: " + strings.Join(ss, "-") -} - -func (e *TrafficActionExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Terminal bool `json:"terminal"` - Sample bool `json:"sample"` - }{t, s, e.Terminal, e.Sample}) -} - -func (e *TrafficActionExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION -} - -func NewTrafficActionExtended(terminal bool, sample bool) *TrafficActionExtended { - return &TrafficActionExtended{ - Terminal: terminal, - Sample: sample, - } -} - -type RedirectTwoOctetAsSpecificExtended struct { - TwoOctetAsSpecificExtended -} - -func (e *RedirectTwoOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.TwoOctetAsSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT) - return buf, err -} - -func (e *RedirectTwoOctetAsSpecificExtended) String() string { - return "redirect: " + e.TwoOctetAsSpecificExtended.String() -} - -func (e *RedirectTwoOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.TwoOctetAsSpecificExtended.String()}) -} - -func (e *RedirectTwoOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_REDIRECT -} - -func NewRedirectTwoOctetAsSpecificExtended(as uint16, localAdmin uint32) *RedirectTwoOctetAsSpecificExtended { - return &RedirectTwoOctetAsSpecificExtended{*NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, as, localAdmin, false)} -} - -type RedirectIPv4AddressSpecificExtended struct { - IPv4AddressSpecificExtended -} - -func (e *RedirectIPv4AddressSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.IPv4AddressSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT) - return buf, err -} - -func (e *RedirectIPv4AddressSpecificExtended) String() string { - return "redirect: " + e.IPv4AddressSpecificExtended.String() -} - -func (e *RedirectIPv4AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.IPv4AddressSpecificExtended.String()}) -} - -func (e *RedirectIPv4AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2, EC_SUBTYPE_FLOWSPEC_REDIRECT -} - -func NewRedirectIPv4AddressSpecificExtended(ipv4 string, localAdmin uint16) *RedirectIPv4AddressSpecificExtended { - e := NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv4, localAdmin, false) - if e == nil { - return nil - } - return &RedirectIPv4AddressSpecificExtended{*e} -} - -type RedirectIPv6AddressSpecificExtended struct { - IPv6AddressSpecificExtended -} - -func (e *RedirectIPv6AddressSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.IPv6AddressSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6) - return buf, err -} - -func (e *RedirectIPv6AddressSpecificExtended) String() string { - return "redirect: " + e.IPv6AddressSpecificExtended.String() -} - -func (e *RedirectIPv6AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.IPv6AddressSpecificExtended.String()}) -} - -func (e *RedirectIPv6AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6 -} - -func NewRedirectIPv6AddressSpecificExtended(ipv6 string, localAdmin uint16) *RedirectIPv6AddressSpecificExtended { - e := NewIPv6AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv6, localAdmin, false) - if e == nil { - return nil - } - return &RedirectIPv6AddressSpecificExtended{*e} -} - -type RedirectFourOctetAsSpecificExtended struct { - FourOctetAsSpecificExtended -} - -func (e *RedirectFourOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.FourOctetAsSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT) - return buf, err -} - -func (e *RedirectFourOctetAsSpecificExtended) String() string { - return "redirect: " + e.FourOctetAsSpecificExtended.String() -} - -func (e *RedirectFourOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.FourOctetAsSpecificExtended.String()}) -} - -func (e *RedirectFourOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3, EC_SUBTYPE_FLOWSPEC_REDIRECT -} - -func NewRedirectFourOctetAsSpecificExtended(as uint32, localAdmin uint16) *RedirectFourOctetAsSpecificExtended { - return &RedirectFourOctetAsSpecificExtended{*NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, as, localAdmin, false)} -} - -type TrafficRemarkExtended struct { - DSCP uint8 -} - -func (e *TrafficRemarkExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK) - buf[7] = byte(e.DSCP) - return buf, nil -} - -func (e *TrafficRemarkExtended) String() string { - return "remark: " + strconv.FormatUint(uint64(e.DSCP), 10) -} - -func (e *TrafficRemarkExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value uint8 `json:"value"` - }{t, s, e.DSCP}) -} - -func (e *TrafficRemarkExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK -} - -func NewTrafficRemarkExtended(dscp uint8) *TrafficRemarkExtended { - return &TrafficRemarkExtended{ - DSCP: dscp, - } -} - -func parseGenericTransitiveExperimentalExtended(data []byte) (ExtendedCommunityInterface, error) { - typ := ExtendedCommunityAttrType(data[0]) - if typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - switch subType { - case EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE: - asn := binary.BigEndian.Uint16(data[2:4]) - bits := binary.BigEndian.Uint32(data[4:8]) - rate := math.Float32frombits(bits) - return NewTrafficRateExtended(asn, rate), nil - case EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION: - terminal := data[7]&0x1 == 1 - sample := (data[7]>>1)&0x1 == 1 - return NewTrafficActionExtended(terminal, sample), nil - case EC_SUBTYPE_FLOWSPEC_REDIRECT: - // RFC7674 - switch typ { - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL: - as := binary.BigEndian.Uint16(data[2:4]) - localAdmin := binary.BigEndian.Uint32(data[4:8]) - return NewRedirectTwoOctetAsSpecificExtended(as, localAdmin), nil - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2: - ipv4 := net.IP(data[2:6]).String() - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewRedirectIPv4AddressSpecificExtended(ipv4, localAdmin), nil - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3: - as := binary.BigEndian.Uint32(data[2:6]) - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewRedirectFourOctetAsSpecificExtended(as, localAdmin), nil - } - case EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK: - dscp := data[7] - return NewTrafficRemarkExtended(dscp), nil - case EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6: - if len(data) < 20 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all extended community bytes for IPv6 FlowSpec are available") - } - - ipv6 := net.IP(data[2:18]).String() - localAdmin := binary.BigEndian.Uint16(data[18:20]) - return NewRedirectIPv6AddressSpecificExtended(ipv6, localAdmin), nil - case EC_SUBTYPE_L2_INFO: - switch data[2] { - case byte(LAYER2ENCAPSULATION_TYPE_VPLS): - controlFlags := uint8(data[3]) - mtu := binary.BigEndian.Uint16(data[4:6]) - return NewVPLSExtended(controlFlags, mtu), nil - } - } - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:8], - }, nil -} - -func parseIP6FlowSpecExtended(data []byte) (ExtendedCommunityInterface, error) { - typ := ExtendedCommunityAttrType(data[0]) - if typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_FLOWSPEC: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - switch subType { - case EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6: - // RFC7674 - switch typ { - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL: - ipv6 := net.IP(data[2:18]).String() - localAdmin := binary.BigEndian.Uint16(data[18:20]) - return NewRedirectIPv6AddressSpecificExtended(ipv6, localAdmin), nil - } - } - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:20], - }, nil -} - -type UnknownExtended struct { - Type ExtendedCommunityAttrType - Value []byte -} - -func (e *UnknownExtended) Serialize() ([]byte, error) { - if len(e.Value) != 7 { - return nil, fmt.Errorf("invalid value length for unknown extended community: %d", len(e.Value)) - } - buf := make([]byte, 8) - buf[0] = uint8(e.Type) - copy(buf[1:], e.Value) - return buf, nil -} - -func (e *UnknownExtended) String() string { - var buf [8]byte - copy(buf[1:], e.Value) - return strconv.FormatUint(binary.BigEndian.Uint64(buf[:]), 10) -} - -func (e *UnknownExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value []byte `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.Value, - }) -} - -func (e *UnknownExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - var subType ExtendedCommunityAttrSubType - if len(e.Value) > 0 { - // Use the first byte of value as the sub type - subType = ExtendedCommunityAttrSubType(e.Value[0]) - } - return e.Type, subType -} - -func NewUnknownExtended(typ ExtendedCommunityAttrType, value []byte) *UnknownExtended { - v := make([]byte, 7) - copy(v, value) - return &UnknownExtended{ - Type: typ, - Value: v, - } -} - -type PathAttributeExtendedCommunities struct { - PathAttribute - Value []ExtendedCommunityInterface -} - -func ParseExtended(data []byte) (ExtendedCommunityInterface, error) { - if len(data) < 8 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all extended community bytes are available") - } - attrType := ExtendedCommunityAttrType(data[0]) - subtype := ExtendedCommunityAttrSubType(data[1]) - transitive := false - switch attrType { - case EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: - as := binary.BigEndian.Uint16(data[2:4]) - localAdmin := binary.BigEndian.Uint32(data[4:8]) - - if subtype == EC_SUBTYPE_LINK_BANDWIDTH { - return NewLinkBandwidthExtended(as, math.Float32frombits(localAdmin)), nil - } else { - return NewTwoOctetAsSpecificExtended(subtype, as, localAdmin, transitive), nil - } - case EC_TYPE_TRANSITIVE_IP4_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC: - ipv4 := net.IP(data[2:6]).String() - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewIPv4AddressSpecificExtended(subtype, ipv4, localAdmin, transitive), nil - case EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: - as := binary.BigEndian.Uint32(data[2:6]) - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewFourOctetAsSpecificExtended(subtype, as, localAdmin, transitive), nil - case EC_TYPE_TRANSITIVE_OPAQUE: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_OPAQUE: - return parseOpaqueExtended(data) - case EC_TYPE_EVPN: - return parseEvpnExtended(data) - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2, EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3: - return parseGenericTransitiveExperimentalExtended(data) - case EC_TYPE_MUP: - return parseMUPExtended(data) - default: - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:8], - }, nil - } -} - -func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length%8 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "extendedcommunities length isn't correct") - } - for len(value) >= 8 { - e, err := ParseExtended(value) - if err != nil { - return err - } - p.Value = append(p.Value, e) - value = value[8:] - } - return nil -} - -func (p *PathAttributeExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, p := range p.Value { - ebuf, err := p.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, ebuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeExtendedCommunities) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - for idx, v := range p.Value { - buf.WriteString("[") - buf.WriteString(v.String()) - buf.WriteString("]") - if idx < len(p.Value)-1 { - buf.WriteString(", ") - } - } - return "{Extcomms: " + buf.String() + "}" -} - -func (p *PathAttributeExtendedCommunities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []ExtendedCommunityInterface `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeExtendedCommunities(value []ExtendedCommunityInterface) *PathAttributeExtendedCommunities { - l := len(value) * 8 - t := BGP_ATTR_TYPE_EXTENDED_COMMUNITIES - return &PathAttributeExtendedCommunities{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeAs4Path struct { - PathAttribute - Value []*As4PathParam -} - -func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length == 0 { - // ibgp or something - return nil - } - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - isAs4, err := validateAsPathValueBytes(value) - if err != nil { - return err - } - - if !isAs4 { - return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed") - } - - for len(value) > 0 { - tuple := &As4PathParam{} - tuple.DecodeFromBytes(value) - p.Value = append(p.Value, tuple) - if len(value) < tuple.Len() { - return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed") - } - value = value[tuple.Len():] - } - return nil -} - -func (p *PathAttributeAs4Path) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, v := range p.Value { - vbuf, err := v.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, vbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAs4Path) String() string { - params := make([]string, 0, len(p.Value)) - for _, param := range p.Value { - params = append(params, param.String()) - } - return strings.Join(params, " ") -} - -func (p *PathAttributeAs4Path) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []*As4PathParam `json:"as_paths"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeAs4Path(value []*As4PathParam) *PathAttributeAs4Path { - var l int - for _, v := range value { - l += v.Len() - } - t := BGP_ATTR_TYPE_AS4_PATH - return &PathAttributeAs4Path{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeAs4Aggregator struct { - PathAttribute - Value PathAttributeAggregatorParam -} - -func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 8 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "AS4 Aggregator length is incorrect") - } - p.Value.AS = binary.BigEndian.Uint32(value[0:4]) - p.Value.Address = value[4:] - return nil -} - -func (p *PathAttributeAs4Aggregator) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 8) - binary.BigEndian.PutUint32(buf[0:], p.Value.AS) - copy(buf[4:], p.Value.Address.To4()) - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAs4Aggregator) String() string { - return "{As4Aggregator: {AS: " + - strconv.FormatUint(uint64(p.Value.AS), 10) + ", Address: " + p.Value.Address.String() + "}}" -} - -func (p *PathAttributeAs4Aggregator) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - AS uint32 `json:"as"` - Address string `json:"address"` - }{ - Type: p.GetType(), - AS: p.Value.AS, - Address: p.Value.Address.String(), - }) -} - -func NewPathAttributeAs4Aggregator(as uint32, address string) *PathAttributeAs4Aggregator { - t := BGP_ATTR_TYPE_AS4_AGGREGATOR - return &PathAttributeAs4Aggregator{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 8, - }, - Value: PathAttributeAggregatorParam{ - AS: as, - Address: net.ParseIP(address).To4(), - }, - } -} - -type TunnelEncapSubTLVInterface interface { - Len() int - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - String() string - MarshalJSON() ([]byte, error) -} - -type TunnelEncapSubTLV struct { - Type EncapSubTLVType - Length uint16 -} - -func (t *TunnelEncapSubTLV) Len() int { - if t.Type >= 0x80 { - return 3 + int(t.Length) - } - return 2 + int(t.Length) -} - -func (t *TunnelEncapSubTLV) DecodeFromBytes(data []byte) (value []byte, err error) { - t.Type = EncapSubTLVType(data[0]) - if t.Type >= 0x80 { - t.Length = binary.BigEndian.Uint16(data[1:3]) - data = data[3:] - } else { - t.Length = uint16(data[1]) - data = data[2:] - } - if len(data) < int(t.Length) { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLV bytes available") - } - return data[:t.Length], nil -} - -func (t *TunnelEncapSubTLV) Serialize(value []byte) (buf []byte, err error) { - t.Length = uint16(len(value)) - if t.Type >= 0x80 { - buf = append(make([]byte, 3), value...) - binary.BigEndian.PutUint16(buf[1:3], t.Length) - } else { - buf = append(make([]byte, 2), value...) - buf[1] = uint8(t.Length) - } - buf[0] = uint8(t.Type) - return buf, nil -} - -type TunnelEncapSubTLVUnknown struct { - TunnelEncapSubTLV - Value []byte -} - -func (t *TunnelEncapSubTLVUnknown) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - t.Value = value - return nil -} - -func (t *TunnelEncapSubTLVUnknown) Serialize() ([]byte, error) { - return t.TunnelEncapSubTLV.Serialize(t.Value) -} - -func (t *TunnelEncapSubTLVUnknown) String() string { - return fmt.Sprintf("{Type: %d, Value: %x}", t.Type, t.Value) -} - -func (t *TunnelEncapSubTLVUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Value []byte `json:"value"` - }{ - Type: t.Type, - Value: t.Value, - }) -} - -func NewTunnelEncapSubTLVUnknown(typ EncapSubTLVType, value []byte) *TunnelEncapSubTLVUnknown { - return &TunnelEncapSubTLVUnknown{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: typ, - }, - Value: value, - } -} - -type TunnelEncapSubTLVEncapsulation struct { - TunnelEncapSubTLV - Key uint32 // this represent both SessionID for L2TPv3 case and GRE-key for GRE case (RFC5512 4.) - Cookie []byte -} - -func (t *TunnelEncapSubTLVEncapsulation) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length < 4 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVEncapsulation bytes available") - } - t.Key = binary.BigEndian.Uint32(value[0:4]) - t.Cookie = value[4:] - return nil -} - -func (t *TunnelEncapSubTLVEncapsulation) Serialize() ([]byte, error) { - buf := make([]byte, 4, 4+len(t.Cookie)) - binary.BigEndian.PutUint32(buf, t.Key) - buf = append(buf, t.Cookie...) - return t.TunnelEncapSubTLV.Serialize(buf) -} - -func (t *TunnelEncapSubTLVEncapsulation) String() string { - return fmt.Sprintf("{Key: %d, Cookie: %x}", t.Key, t.Cookie) -} - -func (t *TunnelEncapSubTLVEncapsulation) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Key uint32 `json:"key"` - Cookie []byte `json:"cookie"` - }{ - Type: t.Type, - Key: t.Key, - Cookie: t.Cookie, - }) -} - -func NewTunnelEncapSubTLVEncapsulation(key uint32, cookie []byte) *TunnelEncapSubTLVEncapsulation { - return &TunnelEncapSubTLVEncapsulation{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_ENCAPSULATION, - }, - Key: key, - Cookie: cookie, - } -} - -type TunnelEncapSubTLVProtocol struct { - TunnelEncapSubTLV - Protocol uint16 -} - -func (t *TunnelEncapSubTLVProtocol) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length < 2 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVProtocol bytes available") - } - t.Protocol = binary.BigEndian.Uint16(value[0:2]) - return nil -} - -func (t *TunnelEncapSubTLVProtocol) Serialize() ([]byte, error) { - var buf [2]byte - binary.BigEndian.PutUint16(buf[:2], t.Protocol) - return t.TunnelEncapSubTLV.Serialize(buf[:]) -} - -func (t *TunnelEncapSubTLVProtocol) String() string { - return fmt.Sprintf("{Protocol: %d}", t.Protocol) -} - -func (t *TunnelEncapSubTLVProtocol) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Protocol uint16 `json:"protocol"` - }{ - Type: t.Type, - Protocol: t.Protocol, - }) -} - -func NewTunnelEncapSubTLVProtocol(protocol uint16) *TunnelEncapSubTLVProtocol { - return &TunnelEncapSubTLVProtocol{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_PROTOCOL, - }, - Protocol: protocol, - } -} - -type TunnelEncapSubTLVColor struct { - TunnelEncapSubTLV - Color uint32 -} - -func (t *TunnelEncapSubTLVColor) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length != 8 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Invalid TunnelEncapSubTLVColor length") - } - t.Color = binary.BigEndian.Uint32(value[4:8]) - return nil -} - -func (t *TunnelEncapSubTLVColor) Serialize() ([]byte, error) { - var buf [8]byte - buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) - buf[1] = byte(EC_SUBTYPE_COLOR) - binary.BigEndian.PutUint32(buf[4:8], t.Color) - return t.TunnelEncapSubTLV.Serialize(buf[:]) -} - -func (t *TunnelEncapSubTLVColor) String() string { - return fmt.Sprintf("{Color: %d}", t.Color) -} - -func (t *TunnelEncapSubTLVColor) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Color uint32 `json:"color"` - }{ - Type: t.Type, - Color: t.Color, - }) -} - -func NewTunnelEncapSubTLVColor(color uint32) *TunnelEncapSubTLVColor { - return &TunnelEncapSubTLVColor{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_COLOR, - }, - Color: color, - } -} - -type TunnelEncapSubTLVEgressEndpoint struct { - TunnelEncapSubTLV - Address net.IP -} - -// Tunnel Egress Endpoint Sub-TLV subfield positions -const ( - EGRESS_ENDPOINT_RESERVED_POS = 0 - EGRESS_ENDPOINT_FAMILY_POS = 4 - EGRESS_ENDPOINT_ADDRESS_POS = 6 -) - -func (t *TunnelEncapSubTLVEgressEndpoint) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length < EGRESS_ENDPOINT_ADDRESS_POS { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVEgressEndpoint bytes available") - } - addressFamily := binary.BigEndian.Uint16(value[EGRESS_ENDPOINT_FAMILY_POS : EGRESS_ENDPOINT_FAMILY_POS+2]) - - var addressLen uint16 - switch addressFamily { - case 0: - addressLen = 0 - case AFI_IP: - addressLen = net.IPv4len - case AFI_IP6: - addressLen = net.IPv6len - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Unsupported address family in TunnelEncapSubTLVEgressEndpoint") - } - if t.Length != EGRESS_ENDPOINT_ADDRESS_POS+addressLen { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVEgressEndpoint address bytes available") - } - t.Address = nil - if addressFamily != 0 { - t.Address = net.IP(value[EGRESS_ENDPOINT_ADDRESS_POS : EGRESS_ENDPOINT_ADDRESS_POS+addressLen]) - } - - return nil -} - -func (t *TunnelEncapSubTLVEgressEndpoint) Serialize() ([]byte, error) { - var length uint32 = EGRESS_ENDPOINT_ADDRESS_POS - var family uint16 - var ip net.IP - if t.Address == nil { - family = 0 - } else if t.Address.To4() != nil { - length += net.IPv4len - family = AFI_IP - ip = t.Address.To4() - } else { - length += net.IPv6len - family = AFI_IP6 - ip = t.Address.To16() - } - buf := make([]byte, length) - binary.BigEndian.PutUint32(buf, 0) - binary.BigEndian.PutUint16(buf[EGRESS_ENDPOINT_FAMILY_POS:], family) - if family != 0 { - copy(buf[EGRESS_ENDPOINT_ADDRESS_POS:], ip) - } - return t.TunnelEncapSubTLV.Serialize(buf) -} - -func (t *TunnelEncapSubTLVEgressEndpoint) String() string { - address := "" - if t.Address != nil { - address = t.Address.String() - } - return fmt.Sprintf("{EgressEndpoint: %s}", address) -} - -func (t *TunnelEncapSubTLVEgressEndpoint) MarshalJSON() ([]byte, error) { - address := "" - if t.Address != nil { - address = t.Address.String() - } - - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Address string `json:"address"` - }{ - Type: t.Type, - Address: address, - }) -} - -func NewTunnelEncapSubTLVEgressEndpoint(address string) *TunnelEncapSubTLVEgressEndpoint { - var ip net.IP = nil - if address != "" { - ip = net.ParseIP(address) - } - return &TunnelEncapSubTLVEgressEndpoint{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_EGRESS_ENDPOINT, - }, - Address: ip, - } -} - -type TunnelEncapSubTLVUDPDestPort struct { - TunnelEncapSubTLV - UDPDestPort uint16 -} - -func (t *TunnelEncapSubTLVUDPDestPort) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length < 2 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVUDPDestPort bytes available") - } - t.UDPDestPort = binary.BigEndian.Uint16(value[0:2]) - return nil -} - -func (t *TunnelEncapSubTLVUDPDestPort) Serialize() ([]byte, error) { - buf := make([]byte, 2) - binary.BigEndian.PutUint16(buf, t.UDPDestPort) - return t.TunnelEncapSubTLV.Serialize(buf) -} - -func (t *TunnelEncapSubTLVUDPDestPort) String() string { - return fmt.Sprintf("{UDPDestPort: %d}", t.UDPDestPort) -} - -func (t *TunnelEncapSubTLVUDPDestPort) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - UDPDestPort uint16 `json:"port"` - }{ - Type: t.Type, - UDPDestPort: t.UDPDestPort, - }) -} - -func NewTunnelEncapSubTLVUDPDestPort(port uint16) *TunnelEncapSubTLVUDPDestPort { - return &TunnelEncapSubTLVUDPDestPort{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_UDP_DEST_PORT, - }, - UDPDestPort: port, - } -} - -type TunnelEncapTLV struct { - Type TunnelType - Length uint16 - Value []TunnelEncapSubTLVInterface -} - -func (t *TunnelEncapTLV) Len() int { - var l int - for _, v := range t.Value { - l += v.Len() - } - return 4 + l // Type(2) + Length(2) + Value(variable) -} - -func (t *TunnelEncapTLV) DecodeFromBytes(data []byte) error { - t.Type = TunnelType(binary.BigEndian.Uint16(data[0:2])) - t.Length = binary.BigEndian.Uint16(data[2:4]) - data = data[4:] - if len(data) < int(t.Length) { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapTLV bytes available") - } - value := data[:t.Length] - for len(value) > 2 { - subType := EncapSubTLVType(value[0]) - var subTlv TunnelEncapSubTLVInterface - switch subType { - case ENCAP_SUBTLV_TYPE_ENCAPSULATION: - subTlv = &TunnelEncapSubTLVEncapsulation{} - case ENCAP_SUBTLV_TYPE_PROTOCOL: - subTlv = &TunnelEncapSubTLVProtocol{} - case ENCAP_SUBTLV_TYPE_COLOR: - subTlv = &TunnelEncapSubTLVColor{} - case ENCAP_SUBTLV_TYPE_UDP_DEST_PORT: - subTlv = &TunnelEncapSubTLVUDPDestPort{} - case ENCAP_SUBTLV_TYPE_EGRESS_ENDPOINT: - subTlv = &TunnelEncapSubTLVEgressEndpoint{} - case ENCAP_SUBTLV_TYPE_SRPREFERENCE: - subTlv = &TunnelEncapSubTLVSRPreference{} - case ENCAP_SUBTLV_TYPE_SRBINDING_SID: - subTlv = &TunnelEncapSubTLVSRBSID{} - case ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST: - subTlv = &TunnelEncapSubTLVSRSegmentList{} - case ENCAP_SUBTLV_TYPE_SRENLP: - subTlv = &TunnelEncapSubTLVSRENLP{} - case ENCAP_SUBTLV_TYPE_SRPRIORITY: - subTlv = &TunnelEncapSubTLVSRPriority{} - case ENCAP_SUBTLV_TYPE_SRCANDIDATE_PATH_NAME: - subTlv = &TunnelEncapSubTLVSRCandidatePathName{} - default: - subTlv = &TunnelEncapSubTLVUnknown{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: subType, - }, - } - } - err := subTlv.DecodeFromBytes(value) - if err != nil { - return err - } - t.Value = append(t.Value, subTlv) - value = value[subTlv.Len():] - } - return nil -} - -func (p *TunnelEncapTLV) Serialize() ([]byte, error) { - buf := make([]byte, 4) - for _, t := range p.Value { - tBuf, err := t.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tBuf...) - } - binary.BigEndian.PutUint16(buf, uint16(p.Type)) - binary.BigEndian.PutUint16(buf[2:], uint16(len(buf)-4)) - return buf, nil -} - -func (p *TunnelEncapTLV) String() string { - tlvList := make([]string, len(p.Value)) - for i, v := range p.Value { - tlvList[i] = v.String() - } - return fmt.Sprintf("{%s: %s}", p.Type, strings.Join(tlvList, ", ")) -} - -func (p *TunnelEncapTLV) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type TunnelType `json:"type"` - Value []TunnelEncapSubTLVInterface `json:"value"` - }{ - Type: p.Type, - Value: p.Value, - }) -} - -func NewTunnelEncapTLV(typ TunnelType, value []TunnelEncapSubTLVInterface) *TunnelEncapTLV { - return &TunnelEncapTLV{ - Type: typ, - Value: value, - } -} - -type PathAttributeTunnelEncap struct { - PathAttribute - Value []*TunnelEncapTLV -} - -func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - for len(value) > 4 { - tlv := &TunnelEncapTLV{} - err = tlv.DecodeFromBytes(value) - if err != nil { - return err - } - p.Value = append(p.Value, tlv) - value = value[4+tlv.Length:] - } - return nil -} - -func (p *PathAttributeTunnelEncap) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, t := range p.Value { - bbuf, err := t.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeTunnelEncap) String() string { - tlvList := make([]string, len(p.Value)) - for i, v := range p.Value { - tlvList[i] = v.String() - } - return "{TunnelEncap: " + strings.Join(tlvList, ", ") + "}" -} - -func (p *PathAttributeTunnelEncap) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []*TunnelEncapTLV `json:"value"` - }{ - Type: p.Type, - Value: p.Value, - }) -} - -func NewPathAttributeTunnelEncap(value []*TunnelEncapTLV) *PathAttributeTunnelEncap { - var l int - for _, v := range value { - l += v.Len() - } - t := BGP_ATTR_TYPE_TUNNEL_ENCAP - return &PathAttributeTunnelEncap{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PmsiTunnelIDInterface interface { - Len() int - Serialize() ([]byte, error) - String() string -} - -type DefaultPmsiTunnelID struct { - Value []byte -} - -func (i *DefaultPmsiTunnelID) Len() int { - return len(i.Value) -} - -func (i *DefaultPmsiTunnelID) Serialize() ([]byte, error) { - return i.Value, nil -} - -func (i *DefaultPmsiTunnelID) String() string { - return string(i.Value) -} - -func NewDefaultPmsiTunnelID(value []byte) *DefaultPmsiTunnelID { - return &DefaultPmsiTunnelID{ - Value: value, - } -} - -type IngressReplTunnelID struct { - Value net.IP -} - -func (i *IngressReplTunnelID) Len() int { - return len(i.Value) -} - -func (i *IngressReplTunnelID) Serialize() ([]byte, error) { - if i.Value.To4() != nil { - return []byte(i.Value.To4()), nil - } - return []byte(i.Value), nil -} - -func (i *IngressReplTunnelID) String() string { - return i.Value.String() -} - -func NewIngressReplTunnelID(value string) *IngressReplTunnelID { - ip := net.ParseIP(value) - if ip == nil { - return nil - } - return &IngressReplTunnelID{ - Value: ip, - } -} - -type PathAttributePmsiTunnel struct { - PathAttribute - IsLeafInfoRequired bool - TunnelType PmsiTunnelType - Label uint32 - TunnelID PmsiTunnelIDInterface -} - -func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length < 5 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "PMSI Tunnel length is incorrect") - } - - if (value[0] & 0x01) > 0 { - p.IsLeafInfoRequired = true - } - p.TunnelType = PmsiTunnelType(value[1]) - if p.Label, err = labelDecode(value[2:5]); err != nil { - return err - } - - switch p.TunnelType { - case PMSI_TUNNEL_TYPE_INGRESS_REPL: - p.TunnelID = &IngressReplTunnelID{net.IP(value[5:])} - default: - p.TunnelID = &DefaultPmsiTunnelID{value[5:]} - } - return nil -} - -func (p *PathAttributePmsiTunnel) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 2) - if p.IsLeafInfoRequired { - buf[0] = 0x01 - } - buf[1] = byte(p.TunnelType) - tbuf, err := labelSerialize(p.Label) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - tbuf, err = p.TunnelID.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributePmsiTunnel) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString(fmt.Sprintf("{Pmsi: type: %s,", p.TunnelType)) - if p.IsLeafInfoRequired { - buf.WriteString(" leaf-info-required,") - } - buf.WriteString(fmt.Sprintf(" label: %d, tunnel-id: %s}", p.Label, p.TunnelID)) - return buf.String() -} - -func (p *PathAttributePmsiTunnel) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - IsLeafInfoRequired bool `json:"is-leaf-info-required"` - TunnelType uint8 `json:"tunnel-type"` - Label uint32 `json:"label"` - TunnelID string `json:"tunnel-id"` - }{ - Type: p.Type, - IsLeafInfoRequired: p.IsLeafInfoRequired, - TunnelType: uint8(p.TunnelType), - Label: p.Label, - TunnelID: p.TunnelID.String(), - }) -} - -func NewPathAttributePmsiTunnel(typ PmsiTunnelType, isLeafInfoRequired bool, label uint32, id PmsiTunnelIDInterface) *PathAttributePmsiTunnel { - if id == nil { - return nil - } - // Flags(1) + TunnelType(1) + Label(3) + TunnelID(variable) - l := 5 + id.Len() - t := BGP_ATTR_TYPE_PMSI_TUNNEL - return &PathAttributePmsiTunnel{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - IsLeafInfoRequired: isLeafInfoRequired, - TunnelType: typ, - Label: label, - TunnelID: id, - } -} - -func ParsePmsiTunnel(args []string) (*PathAttributePmsiTunnel, error) { - // Format: - // "" ["leaf-info-required"] "